Global hotkeys, in TeamSpeak's own shape

Bindings are captured system-wide rather than only while the window has
focus: X11's RECORD extension where the X server sees every key, and a
/dev/input reader as the Wayland fallback. Any key can act as a modifier,
mouse buttons included, as TS3 allows.

The action catalogue, its three categories and the "advanced actions"
split are reverse-engineered from the original client; actions this
client cannot perform are listed but greyed out. Push-to-talk becomes one
of these hotkeys, so the old focus-bound pushToTalkKey setting is gone and
the Voice Activation button edits that binding instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-16 17:08:28 +00:00
parent 3e2c06248f
commit 7e4b9671fe
25 changed files with 2858 additions and 55 deletions

View File

@@ -80,6 +80,25 @@ frontend supplies its own UI and audio backend while reusing `core` unchanged.
- **Status bar** shows the server name, user count and live ping.
- Change your nickname, mute/deafen from the toolbar.
### Hotkeys
- **Global hotkeys**, as in TeamSpeak 3: single keys or combinations (any key can act
as the modifier) and mouse buttons including *Mouse 4* / *Mouse 5*, working
system-wide rather than only while the window has focus. Configure them in
**Options → Hotkeys**.
- Per binding you choose whether it **triggers on key down or on key up**, and whether
it applies **on the active server** only or to every connected one (checkbox off).
Push-to-talk style actions ignore the trigger setting and simply last while held.
- The action list is TeamSpeak's own, reverse-engineered from its hotkey dialog:
three categories (*Server*, *Self*, *Misc*) and a **"Show advanced actions"**
checkbox that reveals the rest, exactly as the original hides all but the everyday
actions. Actions this client does not implement are listed but greyed out.
- Push-to-talk is one of those hotkeys; the button in **Options → Voice Activation**
edits that binding.
- Capture uses X11's RECORD extension, which needs no privileges and does not swallow
the keystroke. On Wayland the X server never sees keys aimed at other applications,
so the client falls back to reading `/dev/input/event*` — for which your user has to
be in the `input` group. The Hotkeys tab says which backend is in use, or why none is.
### Notification sounds
- **Sound packs** in TeamSpeak's own format: a folder of waves plus a `settings.ini`
mapping actions (`CONNECTION_CONNECTED`, `CLIENT_MOVED_TO_CURRENT_CHANNEL_STAYS`, …)
@@ -151,6 +170,12 @@ core/ com.ts3client
├── gfx
│ ├── IconPack an icon pack zip/folder + its settings.ini mapping
│ └── IconPacks discovery of installed packs
├── hotkey
│ ├── HotkeyAction catalogue of TeamSpeak's hotkey actions (RE'd from its binary)
│ ├── Hotkey/HotkeyCombo one binding: keys, trigger edge, server scope, argument
│ ├── Hotkeys persisted bindings (~/.ts3jclient/hotkeys.properties)
│ ├── GlobalInputHook platform hook interface: system-wide key/button events
│ └── HotkeyEngine held-key tracking, combination matching, recording
├── sound
│ ├── SoundEvent catalogue of actions (TeamSpeak's own event ids)
│ ├── SoundPack a pack folder + its settings.ini mapping
@@ -164,14 +189,18 @@ core/ com.ts3client
├── ChannelNode/ClientEntry view models
└── ConnectionListener frontend callbacks
desktop/ com.ts3client.audio.desktop
desktop/ com.ts3client.audio.desktop + com.ts3client.hotkey.desktop
├── Opus Panama (FFM) binding to native libopus
├── OpusEncoder/OpusDecoder thin codec wrappers
├── AudioDevices device enumeration + line opening (48 kHz/16-bit)
├── JavaSoundVoiceInput capture + VAD/PTT gating + Opus encode
├── JavaSoundVoiceOutput per-client Opus decode + playback + mixing
├── WavSoundPlayer sound-pack playback: decode, resample and mix on one line
── JavaSoundAudioBackend wires the above into the core AudioBackend
── JavaSoundAudioBackend wires the above into the core AudioBackend
└── hotkey.desktop
├── XRecordInputHook global key/button capture via X11's RECORD extension
├── EvdevInputHook /dev/input fallback for Wayland sessions
└── DesktopInputHooks picks the backend that suits the session
swing/ com.ts3client
├── Main entry point (look & feel, settings, backend injection)
@@ -182,6 +211,10 @@ swing/ com.ts3client
├── InfoPanel channel description / client group + details view
├── ChatPanel chat log + input
├── SettingsDialog audio + VAD options with live meter
├── HotkeysPanel hotkey list (Options → Hotkeys)
├── HotkeyDialog add/edit one hotkey: action, combination, trigger, scope
├── HotkeyService bindings + engine + input hook, for the dialogs
├── HotkeyActions carries a fired hotkey out on the client
├── NotificationsPanel sound pack + per-action sound/important configuration
├── IconPackPanel icon pack chooser + icon viewer (Options → Design)
├── ConnectDialog connect form
@@ -200,6 +233,9 @@ swing/ com.ts3client
dependency-free and reusable in the core library.
- Whisper is received/played but not yet **sendable** from the UI.
- Playback decodes streams as mono; stereo music-bot audio is down-mixed.
- Push-to-talk is captured via Swing key events, so it only works while the app
window has focus (no global hotkey).
- Hotkey actions TeamSpeak offers but this client does not perform yet (listed but
greyed out in the dialog): capture/playback/hotkey profiles and sound packs,
whisper and push-to-whisper, recording, plugins, server groups, talk power, 3D
sound, hardware ("local") microphone mute and the channel-traversal variants
beyond "Switch to Channel".
- No file transfer, avatars, or server/channel administration UI yet.