Capture global hotkeys on Windows through raw input
A message-only window registers the keyboard and mouse with RIDEV_INPUTSINK, so every key and button arrives as WM_INPUT whether or not the client is in front. Raw input only observes, where a WH_KEYBOARD_LL hook sits in the path of the system input queue and can swallow a keystroke; it also reports the side buttons and both edges of every key, which push-to-talk needs. Keyboard codes stay in each platform's own numbering — X keycodes on X11, set-1 scan codes with the E0/E1 escape folded into the high byte on Windows — since that is what the input API reports and the key-naming call expects. Bindings are per-machine either way, as TeamSpeak's own per-OS keydefs are. Mouse buttons are unified on the X numbering, so "Mouse 4" means the same thing on both. The RAWINPUT decoding lives in its own class so it can be tested off Windows; the window and its pump have not been run on Windows yet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -94,9 +94,14 @@ frontend supplies its own UI and audio backend while reusing `core` unchanged.
|
||||
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 **XInput2 raw events**, as TeamSpeak's own Linux client does: no
|
||||
- On Linux, capture uses **XInput2 raw events**, as TeamSpeak's own client does: no
|
||||
privileges needed and the keystroke is not swallowed. X11's RECORD extension is kept
|
||||
as a fallback for servers without XInput2.
|
||||
- On **Windows**, capture uses **raw input** (`RIDEV_INPUTSINK`) through a message-only
|
||||
window: it observes rather than intercepts, so unlike a low-level keyboard hook it
|
||||
cannot swallow a keystroke or stall the system input queue, and it reports the side
|
||||
buttons and both edges of every key. Bindings are stored as scan codes, so they follow
|
||||
the physical key rather than the layout.
|
||||
- On Wayland the hooks run inside Xwayland, so they see every X11 application, and keys
|
||||
aimed at native Wayland windows only where the compositor forwards them — under KWin
|
||||
that is *System Settings → Window Management → Legacy X11 App Support*, which is why
|
||||
@@ -206,6 +211,9 @@ desktop/ com.ts3client.audio.desktop + com.ts3client.hotkey.desktop
|
||||
├── XInput2InputHook global key/button capture via XInput2 raw events
|
||||
├── XRecordInputHook the same via X11's RECORD extension, as a fallback
|
||||
├── EvdevInputHook /dev/input fallback for Wayland sessions
|
||||
├── WindowsInputHook the same on Windows: raw input into a message-only window
|
||||
├── RawInput RAWINPUT layout and decoding, split out to be testable
|
||||
├── X11KeyNamer/WindowsKeyNamer layout-aware key labels per platform
|
||||
└── DesktopInputHooks picks the backend that suits the session
|
||||
|
||||
swing/ com.ts3client
|
||||
@@ -244,4 +252,10 @@ swing/ com.ts3client
|
||||
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".
|
||||
- Global hotkeys cover Linux and Windows; **macOS has no backend**, so hotkeys there are
|
||||
inert (a `CGEventTap`, which needs Accessibility permission, is the way in). The
|
||||
Windows backend is written but has not been run on Windows — only its decoding is
|
||||
covered by tests.
|
||||
- When no backend can start, push-to-talk does not work at all, not even with the window
|
||||
focused; a focus-scoped fallback hook would restore the pre-hotkey behaviour.
|
||||
- No file transfer, avatars, or server/channel administration UI yet.
|
||||
|
||||
Reference in New Issue
Block a user