macos-global-hotkey-troubleshooting
Debug existing macOS desktop app codebases, especially Tauri, Electron, Swift, Objective-C, or Rust hybrids, where global shortcuts, Fn or Globe keys, native event interception, Accessibility, Input Monitoring, CGEventTap, NSEvent monitors, flagsChanged handlers, debounce and release bugs, or conflicts between standard global-shortcut libraries and native listeners are involved. Use when a macOS hotkey cannot be recorded, recorded hotkeys do not run, hold-to-record stops immediately, normal typing falsely triggers a hotkey, switching away from Fn breaks normal shortcuts, or a suspected hotkey bug may actually be a downstream pipeline or action failure.
macOS Global Hotkey Troubleshooting
Use this skill for debugging existing macOS app codebases, not for broad product architecture discussion.
Target platforms
This skill is written for macOS desktop apps with hybrid or native input stacks, especially:
- Tauri plus Rust plus Objective-C or Swift helpers
- Electron plus native macOS modules
- pure Swift or Objective-C macOS apps
- other desktop apps with one standard shortcut path and one native interception path
The workflow assumes there may be both:
- a standard library path for normal shortcuts
- a native path for
Fn,Globe, or special interception cases
When to use
Use this skill when the user asks to debug or understand:
- macOS global shortcut failures
Fn/Globehotkey capture or runtime issues- Accessibility or Input Monitoring gating hotkeys
CGEventTap,NSEventmonitor,flagsChanged, or native event interception problems- conflicts between a standard global-shortcut library and a native listener
- hold or toggle behavior, false releases, debounce issues, or hotkey persistence bugs
Do not use this skill when the real issue is clearly downstream and unrelated to shortcut handling.
Fast triage workflow
- Confirm the symptom class before changing code. Distinguish recording, persistence, registration, runtime press or release, permissions, and shared pipeline failures.
- Classify the active hotkey path. Decide whether the repo uses a standard shortcut library, a native monitor, or a hybrid split.
- Check system prerequisites first. Confirm macOS-only behavior, required permissions, and whether permission failures can happen silently.
- Inspect code entrypoints in a fixed order. Start at recording UI, then config normalization and persistence, then registration or sync, then native capture, then native runtime monitor, then press or release to action or pipeline.
- Match the symptom to a known conflict pattern. Use the symptom matrix before inventing a new theory.
- Validate with symptom-specific tests. Always test both the hotkey path and a direct action path if available.
Quick walkthrough
Example symptom:
- User reports
Fn+Spacecan be recorded in settings, but hold-to-record starts and stops immediately.
Recommended diagnosis sequence:
- Confirm this is a runtime release problem, not a recording problem. The hotkey already records, so do not start in the recorder UI.
- Classify the path as native or hybrid.
Search for a native monitor,
CGEventTap,flagsChanged, Objective-C or Swift helper, and Rust or backend bridge events likehotkey_pressedandhotkey_released. - Check whether the same downstream action works via direct click or command. If direct click also fails, stop and inspect the shared pipeline or action path instead of patching hotkey logic.
- Inspect native runtime monitor code before editing.
Look for debounce timers, held-modifier booleans, standalone
Fnhandling, combo-key release handling, and generic modifier-release logic. - Form the first concrete hypothesis.
For this symptom, prefer “release is emitted too early for
Fn+keycombos” over “capture is broken”. - Verify the hypothesis with the smallest relevant test. Reproduce hold start, hold duration, and release behavior, then run the smallest backend build or typecheck for the touched surface.
Evidence checklist
Collect these before proposing a fix:
- exact symptom and whether it is record-time or run-time
- macOS version if relevant
- active input method or Globe-key switching behavior if relevant
- standard shortcut library in use, if any
- native monitor implementation details, if any
- permission requirements and current app prompts or status APIs
- config fields controlling hotkey mode and native-vs-standard routing
- event names or callbacks used for capture, press, release, and status
- whether direct click or non-hotkey invocation also fails
Symptom routing
Fncannot be recorded: inspect native capture and permission prompting first- recorded hotkey does not run: inspect persistence, normalization, registration, and sync
- hold starts then instantly stops: inspect native press or release state machine and debounce
- normal typing triggers the hotkey: inspect held-modifier state, stale flags, and release timers
- switching away from
Fnbreaks normal hotkeys: inspect config routing and standard registration fallback - hotkey and direct click both fail: inspect shared downstream action or pipeline before changing hotkey code
For detailed paths, read references/symptom-matrix.md.
Required code inspection order
- Hotkey recording UI or browser capture path
- Config normalization and persistence path
- Registration or sync path
- Native capture path
- Native runtime monitor path
- Press or release to action or pipeline path
Use references/code-entrypoints.md for what to look for at each step.
Common conflict patterns
- browser or WebView cannot observe
Fn - standard shortcut library cannot represent
Fn - permission prompt exists in monitor mode but not capture mode
- permission error is emitted but swallowed in UI
- native-hotkey flag stays sticky and blocks standard shortcut registration
- recorder updates frontend state but does not persist backend config
- release timer emits too early for combo keys
- held-modifier state never clears
Fnstate leaks into generic modifier-release logic
Read references/permissions-and-system-behavior.md and references/symptom-matrix.md before patching native code.
Verification checklist
Validate the exact reported symptom and nearby regressions:
- record
Fn - record
Fn+Space - switch from
Fn+Spaceback to a normal hotkey - verify hold-to-record start, hold, and stop
- verify toggle mode if supported
- run a false-trigger typing test
- test a direct action path to rule out shared backend failures
- run the smallest relevant build or typecheck for the changed surface
Use references/verification.md for the full matrix.