Skip to content

Fix hotkey capture corrupting Option combos into unparseable accelerators (v0.1.17)#21

Merged
archdex-art merged 1 commit into
mainfrom
fix/hotkey-capture-nbsp
Jul 17, 2026
Merged

Fix hotkey capture corrupting Option combos into unparseable accelerators (v0.1.17)#21
archdex-art merged 1 commit into
mainfrom
fix/hotkey-capture-nbsp

Conversation

@archdex-art

Copy link
Copy Markdown
Owner

Root cause — from the user's own live log

WARN Global shortcut registration failed, retrying attempt=1 error=Some("Found empty token while parsing hotkey: Alt+\u{a0}") shortcut=Alt+
WARN Global shortcut registration failed, retrying attempt=2 ...
ERROR Failed to register global shortcut after retries error=Found empty token while parsing hotkey: Alt+ shortcut=Alt+
WARN Registered the default shortcut instead and persisted the correction fallback="Alt+Space"

settings.json's toggle_shortcut was "Alt+\u00A0" — Alt followed by a non-breaking space (U+00A0), not the literal string "Space". General.tsx's toAccelerator() built the accelerator from KeyboardEvent.key (the composed character). macOS recomposes many keys under Option into a different Unicode character than what's printed on the keycap: Option+Space's key is U+00A0, not " "; Option+letters compose accented characters (Option+C → "ç"). The capture UI displayed "Alt+Space" (fine, that's a static label) but the value it persisted was built from the corrupted composed character — invisible until the next registration attempt rejected it outright.

The 0.1.15/0.1.16 boot-time self-heal already recovered the hotkey back to the default (confirmed: settings.json on the user's machine already reads Alt+Space again after that log), but the underlying capture defect means rebinding to any Option combo reproduces the exact same corruption every time.

Fix

toAccelerator now resolves letters/digits/Space from KeyboardEvent.code (the physical key, unaffected by modifier-driven composition) instead of key, via a new codeToAcceleratorKey helper. Falls back to the existing key-based handling only for keys Option can't recompose (arrows, function keys, Escape, etc.), preserving all prior behavior for those.

Verification

  • tsc --noEmit clean.
  • Drove the real Settings UI in a browser and dispatched the exact synthetic event macOS actually sends for Option+Space (code: "Space", key: "\u00A0") — captured as Alt+Space, not corrupted.
  • Same for Option+C (key: "ç") — captured as Alt+C.
  • Bumped src-tauri/tauri.conf.json + Cargo.toml/Cargo.lock to 0.1.17, added CHANGELOG entry.

…tors (v0.1.17)

Live log evidence from the user's own session:

  Global shortcut registration failed ... error=Found empty token while
  parsing hotkey: Alt+\u{a0}

General.tsx's toAccelerator() built the accelerator from
KeyboardEvent.key — the *composed* character. macOS recomposes many keys
under Option into a different Unicode character than what's printed on the
keycap: Option+Space's key is a non-breaking space (U+00A0), not a plain
' '. The capture UI displayed 'Alt+Space' but persisted 'Alt+<NBSP>' to
settings.json — invisible until the next boot's registration attempt
rejected it outright. The 0.1.15/0.1.16 self-heal recovered the hotkey back
to the default afterward (confirmed: settings.json already reads
Alt+Space again), but the underlying capture bug means rebinding to any
Option combo reproduces it every time.

toAccelerator now resolves letters/digits/Space from KeyboardEvent.code
(the physical key, unaffected by modifier composition) instead of key.

Verified live in a real browser: simulated the exact Option+Space event
macOS actually sends (code: 'Space', key: '\u00A0') and confirmed it now
captures as 'Alt+Space'; same for Option+C (key: 'ç') capturing as 'Alt+C'.

Bump to v0.1.17, changelog entry.
@archdex-art
archdex-art merged commit 6b0d323 into main Jul 17, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant