Skip to content

feat(windows): server-side key anchoring#172

Draft
stefanverleysen wants to merge 5 commits intomasterfrom
feat/server-key-anchoring
Draft

feat(windows): server-side key anchoring#172
stefanverleysen wants to merge 5 commits intomasterfrom
feat/server-key-anchoring

Conversation

@stefanverleysen
Copy link
Copy Markdown
Collaborator

Summary

  • Server-side key anchoring: configured keys stay on the server during relay mode instead of being forwarded to the client
  • Supports modifier+key combos (e.g. Ctrl+Shift+F6) for foot pedal use cases
  • VK_CANCEL wrapping prevents injected events from leaking to client
  • Order-independent combo detection for simultaneous key arrival (USB HID pedals)
  • No isInjected filtering so SendInput-based devices (pedals) work correctly

To test

  1. Configure anchoredKeys = Ctrl+Shift+F6 on the server screen
  2. Open a target app on the server, move cursor to client
  3. Press Ctrl+Shift+F6 -- should fire on the server target app
  4. Release -- combo should stop cleanly, no stuck keys
  5. Move cursor back to server -- all keys should work normally
  6. Test with a SendInput-based foot pedal if available

stefanverleysen and others added 5 commits March 11, 2026 16:46
Per-screen anchoredKeys option keeps specified keys and combos local
on the server instead of relaying them to clients. Supports single
keys (F13, Delete), modifier combos (Alt+Tab, Ctrl+A), and arbitrary
VK codes via a 256-bit bitmask. Combos use a pending-modifier
mechanism that holds modifier keys until the next keypress determines
whether to anchor locally or flush to the client.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Repurpose unused lParam bit 30 to carry LLKHF_INJECTED so the combo
handler can distinguish physical keypresses from its own SendInput
events. Prevents infinite re-entry on combo repeat and modifier-UP
paths. Keys that are both combo triggers and bare-anchored now enter
the combo state machine correctly instead of short-circuiting. Combo
state is cleared on mode transitions to prevent stale holdover.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
injectComboLocally fired a full down+up cycle on every keypress,
causing held keys to produce rapid press-release instead of a
sustained hold. Split into injectComboLocally (downs only) and
releaseComboLocally (ups on physical release). Extracted
sendInputToTarget to share the foreground-flip logic. Added
!isInjected guard on trigger-UP path to prevent infinite SendInput
loop. Combo state cleanup on mode transitions now includes
g_firedModCount.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
VK_CANCEL wrapping in sendInputToTarget so injected events bypass
the hook instead of being relayed to the client. Clear g_keyState
on mode change to prevent stale modifier state. Remove isInjected
guards that blocked pedal (SendInput) events from releasing combos.
Order-independent trigger buffering for simultaneous key arrival.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant