"The chord was recordable and unnameable at once."
Three Ways to Hear a Key You Do Not Own
A utility that answers a shortcut while another app is frontmost has three tools, and they cost different things.
- Carbon
RegisterEventHotKeyregisters a chord (a key plus modifiers) system-wide and delivers a hot-key event to your app. It needs no Accessibility grant, it does not see other keystrokes, and it is still the tool the family's text transformer, dictation tool and launchers use. The API is old; nothing newer does this job. NSEvent.addGlobalMonitorForEventsobserves events headed to other apps. Key-related events arrive only when the app is trusted for Accessibility, and a monitor can observe but never consume.- A
CGEventTapcan listen to events or, as an active filter, modify and swallow them. Listening needs Input Monitoring, an active tap needs Accessibility, and a tap that suppresses the wrong event eats that key for every app on the Mac.
Registration Can Fail, Per Chord
RegisterEventHotKey returns eventHotKeyExistsErr (-9878) when the chord is already registered. Measured by registering ⌘⌥K twice in one process: the first call succeeded and the second returned -9878. The text transformer registers every enabled macro separately and returns a failure per binding for its Settings window, so one collision does not disable the rest, and a duplicate inside the app is reported by name before it ever reaches Carbon.
Function Keys Are Not a Range
Virtual key codes are positions on a keyboard, not a sequence. kVK_F1 is 0x7A and kVK_F12 is 0x6F, so UInt16(kVK_F1)...UInt16(kVK_F12) has its lower bound above its upper bound, and a shortcut recorder built on it trapped with "Range requires lowerBound <= upperBound" the instant any key was pressed. Use an explicit set of the constants. The recorder was coupled to NSEvent and had no tests, so the check moved into a pure helper with a self-test.
A Key the App Cannot Name, It Cannot Accept
Three apps carried copies of the same keycode-to-glyph table. One recorder accepted any key except Escape, Caps Lock and Fn, while its table lacked Home, End, Page Up and Down, F13 to F20 and the keypad. So ⌘⌥Home recorded, saved and registered, and the hotkey worked, while Settings displayed it as "⌘⌥Key 115". The shared kit type now answers "can this key be named" separately from "does this app accept it": a key value can only be constructed through the complete table, so a label with no name cannot exist. Each app still layers its own exclusions on top.
Hold-to-Talk on a Bare Modifier
Carbon cannot express a chord that is only a modifier, like holding right ⌘ or Fn to dictate. The dictation tool watches flagsChanged under the Accessibility grant it already holds, with a global monitor for other apps and a local one for its own windows (a global monitor never sees events sent to its own app), and decides pressed or released with CGEventSource.keyState, because the modifier flag stays set while the other ⌘ key is still down. Fn doubles as the Globe key, so users set the Globe key's action to Do Nothing.