Skip to content

Support modifier+key combo hotkeys for quick dictation - #204

Merged
jatinkrmalik merged 3 commits into
VocaHQ:mainfrom
Mr-Sunglasses:feat/hotkey-combo
Aug 12, 2026
Merged

Support modifier+key combo hotkeys for quick dictation#204
jatinkrmalik merged 3 commits into
VocaHQ:mainfrom
Mr-Sunglasses:feat/hotkey-combo

Conversation

@Mr-Sunglasses

@Mr-Sunglasses Mr-Sunglasses commented Aug 10, 2026

Copy link
Copy Markdown
Member

closes: #132

Screenshot 2026-08-11 at 3 05 16 AM Screenshot 2026-08-11 at 3 05 27 AM

Summary

  • Quick dictation was previously limited to a single key (a lone modifier like Right Option, or a regular key like F5). Adds support for modifier+key combos (e.g. ⌘Space, ⌃Space, ⌥Space, ⌃⌥Space) while every existing single-key hotkey keeps working exactly as before.
  • New HotKeyCombo/HotKeyModifiers model (Sources/VocaMac/Models/HotKeyModifiers.swift) represents "required modifiers + base key," stored via a new @AppStorage("vocamac.hotKeyModifiers") field alongside the existing hotKeyCode.
  • HotKeyManager's global event tap now gates a combo's base key on an exact modifier match, and force-stops push-to-talk if a required modifier is released before the base key.
  • The Settings/Onboarding hotkey recorder now captures full combos: it tracks held modifiers by physical key code (not shared NSEvent flag) so Left+Right presses of the same modifier aren't conflated, and seeds its initial state from live key state (CGEventSource.keyState) so a modifier already held down when "Record" is clicked is handled correctly.
  • Fixed a regression where an unmatched Space-based combo press could swallow autorepeat keystrokes for plain spacebar use in other apps.

Test plan

  • swift build — clean, no warnings introduced
  • swift test — all pre-existing and new tests pass (full suite run 3x for stability; excluded a pre-existing flaky/segfaulting AudioEngine hardware-access suite that reproduces identically on unmodified main)
  • New unit tests: combo start/stop, exact-match rejection of extra/missing modifiers, early modifier-release force-stop, double-tap combo timing, autorepeat-pass-through regression guard, legacy single-key regression guard
  • Manual verification in the running app (Settings → General → Record a combo, confirm it triggers dictation and a plain key-press elsewhere still works normally)

@github-actions github-actions Bot added app bug Something isn't working ci and removed ci labels Aug 10, 2026
@Mr-Sunglasses

Copy link
Copy Markdown
Member Author

@jatinkrmalik PTAL!

@jatinkrmalik jatinkrmalik added this to the v0.8.0 milestone Aug 12, 2026
Quick dictation was limited to a single key (a lone modifier or a
regular key). Adds ⌘Space/⌃Space/⌥Space-style combos while keeping
every existing single-key hotkey working exactly as before.

- New HotKeyCombo/HotKeyModifiers model for required-modifiers + base key
- HotKeyManager's event tap gates the base key on an exact modifier
  match and force-stops push-to-talk if a required modifier releases early
- Settings/Onboarding hotkey recorder captures full combos, tracking
  held modifiers by physical key (not shared flag) and seeding from
  live key state so a modifier already held when recording starts is
  handled correctly
- Guards against autorepeat swallowing unrelated keystrokes (e.g.
  plain spacebar use elsewhere) when a Space-based combo is configured
The recorder used NSEvent.addLocalMonitorForEvents, which only sees
keystrokes macOS has already declined to handle itself. Combos the
system reserves therefore never arrived — ⌃Space and ⌃⌥Space are bound
to input-source switching, ⌘Space to Spotlight — and ⌘-based combos are
routed to menu key equivalents first, so whole categories of shortcut
(including ⌃⇧Space) could not be recorded at all.

The runtime engine already solves this: HotKeyManager uses a session
CGEventTap at head-insert, which sees every keystroke before the system
does. That asymmetry was the bug — triggering worked while recording
did not. The recorder now uses the same mechanism, and consumes the
key-down while recording so the shortcut being recorded doesn't also
fire its normal action.

- Extracts capture into HotKeyComboRecorder, leaving the NSView as a
  lifecycle shell (start on appear, cancel on window resign)
- Falls back to the local monitor when the tap can't be created (no
  Accessibility permission) so recording degrades rather than dying
- Disables the tap synchronously on teardown and defers run loop source
  removal, so the run loop is never mutated from inside its callback
@jatinkrmalik
jatinkrmalik merged commit d62af5a into VocaHQ:main Aug 12, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

idea: key combination to start / stop recording

2 participants