Dep swap:
- Drop the git-pinned jamiepine/rdev fork we were carrying since the
upstream crate is abandoned.
- Depend on keytap 0.2 from crates.io — our own cross-platform global
keyboard tap crate. Clean shutdown via Drop, Sonoma-safe by design
(no TSMGetInputSourceProperty calls off the main thread, so
`set_is_main_thread(false)` is gone), and properly versioned.
Chord engine rewrite:
- Delete hotkey_monitor.rs's internal Chord state machine (Match enum,
KeyEvent enum, step()/classify() methods, associated unit tests).
keytap's ChordMatcher subsumes it: Momentary chord for PTT,
add_toggle() for Toggle-to-talk, longest-match resolution, sticky-end
for Toggle. Net: -80 LOC in hotkey_monitor.rs; the remaining module
is the dispatcher loop + Effect→Tauri translation.
- Preserve the PTT→Toggle "RestartRecording" upgrade signal. keytap
emits End(PTT)+Start(Toggle) atomically (same Instant) when the held
set upgrades from a shorter chord to a longer superset. The
dispatcher peeks at the matcher with a 5 ms recv_timeout after any
End and coalesces the pair into Effect::RestartRecording so the
frontend still gets the "discard the transition-moment audio" signal
instead of an unrelated Stop+Start pair.
- HotkeyMonitor::update_bindings now actually tears down the tap on
empty bindings instead of leaving an idle CGEventTap around. New
bindings rebuild the matcher and the dispatcher thread from scratch.
key_codes.rs:
- Rewrite the browser-code → Key table against keytap's cleaner Key
variant names (`A`..`Z` not `KeyA`..`KeyZ`, `Digit0`..`Digit9` not
`Num0`..`Num9`, `ArrowUp` not `UpArrow`, `AltLeft`/`AltRight` instead
of `Alt`/`AltGr`, `Period` not `Dot`, …). On-disk chord string
format (W3C `KeyboardEvent.code` identifiers) is unchanged, so
capture_settings rows written before the swap round-trip identically.
Legacy aliases (`Alt`, `AltGr`, `Num0`, `UpArrow`, `Dot`, …) kept for
forward-compat on old rows.
main.rs / input_monitoring.rs:
- Update the few doc comments that referenced `rdev::listen` to
describe keytap's Tap; no behavioural change.
- build_chord_bindings now imports from keytap::Key.
- enable_hotkey / disable_hotkey / update_chord_bindings reach into
HotkeyMonitor via &mut since apply()/update_bindings() now mutate.
Tests live in keytap now (22 chord-related tests in keytap 0.2,
including the PTT→Toggle upgrade scenario that used to be tested in
hotkey_monitor.rs). Voicebox's hotkey_monitor.rs is thin enough that
local testing would be trivia.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>