Skip to content

driverkit: fast stuck-key recovery after VHID daemon reconnect (MAL-57 Layer 2)#26

Merged
malpern merged 1 commit into
keypath/bundledfrom
mal-57-layer2-fast-vhid-reset
Jun 11, 2026
Merged

driverkit: fast stuck-key recovery after VHID daemon reconnect (MAL-57 Layer 2)#26
malpern merged 1 commit into
keypath/bundledfrom
mal-57-layer2-fast-vhid-reset

Conversation

@malpern

@malpern malpern commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Summary

When the socket to the Karabiner VHID daemon dies mid-keystroke (CPU starvation under parallel builds, daemon restart), a key Release lost in transit leaves the DriverKit virtual keyboard holding that key down. The daemon only garbage-collects the dead client after its own heartbeat timeout, so the key autorepeats at the OS level for 1-3 seconds. Two live incidents on 2026-06-10 were traced end to end — see KeyPath docs/bugs/MAL-57-duplicate-keypresses.md (2026-06-10 Incident Evidence) and KeyPath PR malpern/KeyPath#882 (Layer 1, launchd priority fix).

Changes

Vendors karabiner-driverkit 0.3.1 into driverkit/ via [patch.crates-io] with three targeted changes:

  1. Stable per-PID client socket path (virtual_hid_device_service/client.hpp). The daemon keys per-client state — including the DriverKit virtual keyboard instance — by this path. A reconnect under the same path reuses the existing keyboard instead of spawning a second instance while the stuck one repeats until GC. local_datagram::client_impl already removes an existing file before bind, so stale files are harmless.
  2. virtual_hid_keyboard_reset on the keyboard-ready rising edge (c_src/driverkit.cpp). Clears any stuck key as soon as the connection recovers. Safe for held keys: kanata's next posted report carries absolute full state (the C++ report object tracks all pressed keys), so genuinely-held keys are re-asserted by the next event.
  3. Client server-check interval 3000ms → 1000ms. Detects a dead daemon connection ~2s sooner; the daemon already pings each client at 1000ms, so no new traffic class.

Also: virtual_hid_keyboard_ready is now printed only on transitions instead of every ~1s daemon status push — this was 95%+ of the 183MB daemon stdout log.

Worst-case stuck-key window drops from ~3s to ~1.5s; typical under 1s. No Rust-side changes; cargo build and cargo check pass with the patched crate resolving from driverkit/.

Test plan

  • cargo check / cargo build green with the vendored patch
  • Manual verification planned via KeyPath integration: SIGSTOP the VHID daemon for >3s while holding a key, resume, confirm the stuck-key burst is bounded by ~1s and held modifiers survive benign reconnects
  • Log verification: virtual_hid_keyboard_reset sent after ready transition appears on reconnect; ready-spam gone

…7 Layer 2)

When the socket to the Karabiner VHID daemon dies mid-keystroke (CPU
starvation, daemon restart), a key Release lost in transit leaves the
DriverKit virtual keyboard holding that key down. The daemon only
garbage-collects the dead client after its own heartbeat timeout, so the
key autorepeats at the OS level for 1-3 seconds (KeyPath MAL-57).

Vendor karabiner-driverkit 0.3.1 (patch.crates-io) with three changes:

1. Stable per-PID client socket path. The daemon keys per-client state
   (including the virtual keyboard instance) by this path, so a
   reconnect reuses the existing keyboard instead of spawning a second
   instance while the stuck one repeats until GC.
2. virtual_hid_keyboard_reset on the keyboard-ready rising edge. Clears
   any stuck key as soon as the connection recovers; the next posted
   report re-asserts genuinely held keys since reports carry absolute
   full state.
3. Client server-check interval 3000ms -> 1000ms, matching the daemon's
   own per-client ping rate, so a dead connection is detected ~2s
   sooner.

Also stops printing virtual_hid_keyboard_ready on every (~1/s) daemon
status push - transitions only - which was 95%+ of the daemon stdout
log volume.

Worst-case stuck-key window drops from ~3s to ~1.5s; typical under 1s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@malpern malpern merged commit 6a05a4a into keypath/bundled Jun 11, 2026
malpern added a commit to malpern/KeyPath that referenced this pull request Jun 11, 2026
…-57 Layer 2)

Pulls malpern/kanata#26 into the bundled engine: stable per-PID VHID
client socket path, virtual_hid_keyboard_reset on the keyboard-ready
rising edge, and 1s (was 3s) daemon heartbeat detection. Worst-case
stuck-key autorepeat after a daemon connection loss drops from ~3s to
~1.5s, typical under 1s. Also reduces daemon stdout log volume ~95%
(ready-status now logged on transitions only).

Engine release build (cmd,tcp_server, aarch64) verified locally via
Scripts/build-kanata.sh: signs and passes binary smoke test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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