Skip to content

Option + letter hotkeys sometimes stop working (Carbon RegisterEventHotKey limitation) #558

@BashkaMen

Description

@BashkaMen

Problem

Hotkeys bound to option + letter (e.g. option + q) stop working intermittently, while option + number (e.g. option + 1) always work reliably.

Opening the FlashSpace UI temporarily fixes the issue — hotkeys start working again until something breaks them.

Root Cause Analysis

After reading the source code, I believe the root cause is a fundamental limitation of the Carbon RegisterEventHotKey API when combined with option + letter shortcuts.

On macOS, option + letter combos (like option + qœ) are processed by the Text Services Manager / IME layer before Carbon hot key events are dispatched. This means:

  • option + 1 → no IME character composition → kEventHotKeyPressed fires reliably
  • option + q → triggers character composition (œ) → the event gets consumed at a higher level and never reaches the Carbon event handler

This is a known limitation of RegisterEventHotKey — it sits below system hot keys but above IME input, and option+letter combos fall in an ambiguous zone depending on the active application's input handling.

Why Opening the UI "Fixes" It

Looking at CarbonKeyboardShortcuts.swift, when a menu is open, the code switches to RunLoopLocalEventMonitor with .eventTracking mode (raw key events via NSEvent), which intercepts events before IME processing. When the UI is closed, it switches back to RegisterEventHotKey, and the issue returns.

Question

Is this a known limitation you're aware of? Are there plans to use a lower-level mechanism (like CGEventTap or a persistent NSEvent.addGlobalMonitorForEvents) that would intercept events before the IME layer, similar to how tools like Raycast or BetterTouchTool handle it?

Or is there a recommended workaround users can follow (e.g. always add cmd or ctrl alongside option for letter keys)?

Environment

  • macOS version: 26.3
  • FlashSpace version: latest main branch

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions