* fix(hotkeys): consume the dictation shortcut so it stops leaking to apps
Grab each monitored keyboard with EVIOCGRAB and re-emit every event the
shortcut does not own through a paired uinput clone. The configured
shortcut key is now consumed by Vocalinux instead of also reaching the
focused app (right-alt opening menus in Thunderbird/Firefox, F11/F12
triggering browser actions).
- Pure-modifier gestures reserve the modifier's events entirely; bare
function-key shortcuts consume that key; modifier+key combos consume
the main key only while the combo owns it, so typing and chords like
Alt+Tab keep working and injected text is untouched
- BUS_VIRTUAL devices (our clones, ydotool, remappers) are never grabbed
- EV_REP is stripped from clones and repeats are forwarded verbatim, so
repeat rate is preserved without doubling
- Feedback event types (EV_LED/EV_SND/EV_FF) are never re-injected
- Falls back to ungrabbed listening when /dev/uinput or the grab is
unavailable, warning once that keys will also reach the app
Fixes#871
* test(hotkeys): cover grab/forward edge cases
Race cleanup on duplicate open, forwarder close errors during stop and
device removal, mid-SYN_DROPPED forwarding, write failures, and the
combo consume edge cases (unowned repeat/release, missing main key).
* fix(installer): grant read on /dev/uinput so key suppression works
The evdev backend's uinput clone opens /dev/uinput O_RDWR, but the
installed 80-dotool.rules gave the input group write-only access
(0620), so shortcut suppression silently fell back to ungrabbed
monitoring on stock installs. Bump the rule to 0660 and refresh it when
the installed copy differs so existing installs pick up the fix.
* fix(hotkeys): harden evdev grab/forward lifecycle and udev install
- release the device grab and close the clone when a uinput write fails
- close all devices if the monitor exits unexpectedly (releases grabs)
- monitor virtual devices too; skip only our own uinput clones
- track consumed combo presses per device so releases stay paired
- after SYN_DROPPED, release keys the clone still believes are held
- append the uinput udev rule instead of overwriting local rules
- annotate new signatures and narrow the clone-creation catch
* fix(hotkeys): reconcile swallowed combo releases after SYN_DROPPED
- resync the swallowed-press pairing even when the clone holds no keys;
a dropped combo release otherwise leaves the next ordinary press
consumed, eating a keystroke
- narrow every new close-cleanup catch to OSError/IOError/RuntimeError
with debug context instead of blanket Exception passes
---------
Co-authored-by: Jatin K Malik <jatinkrmalik@gmail.com>
* refactor(installer): split implementation into sourced modules
* test(installer): harden module path coverage
* fix(installer): qualify interactive privacy and engine claims
The guided installer overstated local-only privacy and ranked
whisper.cpp without evidence. Match PRODUCT.md: on-device local
engines, optional Remote API, and the ~33 language catalog plus
Auto-detect.
---------
Co-authored-by: Jatin K Malik <jatinkrmalik@gmail.com>