Summary
After a transient DriverKit output-backend failure (asio.system:55), managed repeat continues firing indefinitely for keys that were physically held at the moment of disconnection. The key repeats at ~30ms intervals and cannot be stopped by pressing other keys — requires killing kanata.
Root Cause
The recovery path in kanata/macos.rs:288-293 clears PRESSED_KEYS (input thread tracking) but does not clear the keyberon layout state. The processing thread's tick_managed_repeat() checks self.cur_keys (populated from self.layout.keycodes()), which still contains the stuck key because no Release event was ever delivered — the physical key-up happened while input was ungrabbed and went directly to macOS.
After re-grab, no release event arrives (key is no longer physically held), so the keyberon layout permanently retains the key as "pressed" and managed repeat loops forever.
Observed Behavior (2026-05-31)
14:29:05.392 — e key pressed during normal typing
14:29:05.424 — error_occurred asio.system:55
14:29:05.472 — "output backend unavailable during write — releasing input devices"
14:29:05.891 — managed repeat E starts firing (~30ms interval)
14:29:06.587 — output backend recovers, input re-grabbed
14:29:06.611+ — managed repeat E continues for 21+ seconds (928 total repeats)
— user pressed Esc multiple times, no effect
— had to emergency-stop kanata
Proposed Fix
After recovery, before re-grabbing input, also clear keyberon layout state and managed repeat timers — matching what the latency-soft-reset path already does (mod.rs:2612-2616):
// In macos.rs recovery path, after line 293:
{
let mut kanata = kanata.lock();
kanata.kbd_out.release_tracked_output_keys("output-backend-recovery");
// ADD: clear keyberon layout state so no keys appear "stuck"
release_normalkey_states(kanata.layout.bm());
// ADD: clear managed repeat timers
if let Some(ref mut mrs) = kanata.managed_repeat_state {
mrs.timers.clear();
}
}
PRESSED_KEYS.lock().clear();
Relevant Code
src/kanata/macos.rs:247-293 — recovery path (missing layout clear)
src/kanata/managed_repeat.rs:59-143 — tick_managed_repeat (checks cur_keys from layout)
src/kanata/mod.rs:2612-2616 — latency-soft-reset (has the correct pattern)
Summary
After a transient DriverKit output-backend failure (
asio.system:55), managed repeat continues firing indefinitely for keys that were physically held at the moment of disconnection. The key repeats at ~30ms intervals and cannot be stopped by pressing other keys — requires killing kanata.Root Cause
The recovery path in
kanata/macos.rs:288-293clearsPRESSED_KEYS(input thread tracking) but does not clear the keyberon layout state. The processing thread'stick_managed_repeat()checksself.cur_keys(populated fromself.layout.keycodes()), which still contains the stuck key because noReleaseevent was ever delivered — the physical key-up happened while input was ungrabbed and went directly to macOS.After re-grab, no release event arrives (key is no longer physically held), so the keyberon layout permanently retains the key as "pressed" and managed repeat loops forever.
Observed Behavior (2026-05-31)
Proposed Fix
After recovery, before re-grabbing input, also clear keyberon layout state and managed repeat timers — matching what the latency-soft-reset path already does (
mod.rs:2612-2616):Relevant Code
src/kanata/macos.rs:247-293— recovery path (missing layout clear)src/kanata/managed_repeat.rs:59-143—tick_managed_repeat(checkscur_keysfrom layout)src/kanata/mod.rs:2612-2616— latency-soft-reset (has the correct pattern)