Skip to content

feat: expose physical key events over TCP - #2130

Draft
ksquaring wants to merge 1 commit into
jtroo:mainfrom
ksquaring:codex/physical-key-events
Draft

feat: expose physical key events over TCP#2130
ksquaring wants to merge 1 commit into
jtroo:mainfrom
ksquaring:codex/physical-key-events

Conversation

@ksquaring

Copy link
Copy Markdown

What changed

  • add an opt-in PhysicalKey TCP notification containing the original key name, platform-specific numeric code, and press/release/repeat/tap state
  • add SubscribePhysicalKeyEvents so delivery is enabled per connection and defaults off
  • emit physical input in the shared processing loop before remapping while excluding internal wake-up events
  • advertise the physical-key-events capability through HelloOk
  • update the example TCP client and protocol documentation
  • add protocol, conversion, routing, backpressure, and live localhost TCP coverage
  • include a repository-grounded technical plan documenting the selected design and alternatives

Why

Keyboard overlay, accessibility, and teaching tools cannot observe a key that Kanata intercepts and remaps. Existing push-msg annotations require manual configuration, while TapActivated and HoldActivated only cover tap-hold resolution.

This provides structured access to the original defsrc input without confusing it with remapped output. Because physical keystrokes are sensitive and high-volume, clients must explicitly subscribe and can unsubscribe at any time.

User impact

TCP clients can detect support using the physical-key-events capability, subscribe with:

{"SubscribePhysicalKeyEvents":{"enabled":true}}

and receive events such as:

{"PhysicalKey":{"key":"w","code":17,"state":"press"}}

Existing clients receive no physical key traffic unless they opt in.

Validation

  • cargo test -p kanata-tcp-protocol
  • cargo test -p kanata --features tcp_server
  • live localhost integration test covering default-off, subscribe, delivery, unsubscribe, and post-unsubscribe filtering
  • cargo check -p kanata_example_tcp_client
  • cargo clippy -p kanata-tcp-protocol -p kanata -p kanata_example_tcp_client --features tcp_server -- -D warnings
  • cargo fmt --all
  • git diff --check

Closes #1097.

@malpern

malpern commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Thanks for working on this — I’m excited to see it.

I’ve been maintaining a similar fork-only feature for KeyPath since May: KeyInput physical-key events over TCP. I use it for live keyboard visualization when Kanata intercepts or remaps the original input, so this could let me retire that part of my fork. I also like the per-connection, opt-in approach here better than my current broadcast implementation.

A few thoughts from that integration, in case they’re useful:

  • On macOS, I think OsCode::as_u16() represents Kanata’s converted/internal code rather than a native CGKeyCode. It might be worth clarifying that in the field name or documentation so clients don’t assume it has native OS semantics.
  • I’ve found a monotonic timestamp useful, and a sequence number might also help clients notice dropped events. A dropped release can otherwise leave a keyboard visualization showing a stuck key.
  • The Windows CI failure looks to me more like a test-fixture issue than a problem with the feature itself: the test seems to start the Interception backend without the driver being installed. Perhaps a simulated or backend-neutral fixture could keep that test portable.

Happy to try the revised protocol through KeyPath on macOS and share anything I find.

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.

Feature request: Show keystroke or can let other app know the real key is stroked.

2 participants