fix: resolve position-invariant keys from the physical code - #1
Merged
Merged
Conversation
macOS composes Option with the pressed key, so Opt+Space reports KeyboardEvent.key as U+00A0 rather than " ". The captured token became the no-break space itself, producing an "Alt+<U+00A0>" shortcut that no layout can resolve back to a physical key, so registration failed. Space, Enter, Tab, Backspace, Delete, Escape, the arrows and F1-F12 now come from KeyboardEvent.code, whose position is identical on every layout. Punctuation and digits still come from KeyboardEvent.key so shortcuts keep following the active layout.
karamouche
self-requested a review
August 3, 2026 16:22
Collaborator
|
thanks for the contribution @rmarquet21! It looks good, approving the merge 👍 |
karamouche
approved these changes
Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Opt+Spacecannot be bound as a dictation shortcut on macOS. The recorder shows⌥followed by a blank key chip, and saving the shortcut fails to register.macOS treats Option as a character-composing modifier, so
Opt+Spaceis how you type a no-break space. The browser correctly reports:normalizeCapturedKeyreadevent.keyfirst.LOGICAL_KEY_FROM_EVENT_KEYmaps" "(U+0020) to"Space", so the lookup missed and execution fell through to the generic single-character branch, which returned the no-break space itself as the logical key token. The recorded shortcut wasAlt+<U+00A0>.Nothing surfaced the problem:
formatKeySymbolhas no mapping for U+00A0 so the key chip rendered blank, andcanSaveCapturesaw one modifier plus one non-modifier and enabled the Save button.If saved,
parse_combo_shortcutpassed" "toresolve_logical_key, which fell throughstable_logical_to_codetoresolve_char_in_current_layout. That scans the active layout viaUCKeyTranslatefor a key producing the character unmodified or with Shift — no key produces U+00A0 without Option, by definition — so registration failed.The same root cause affects every
Alt-composed printable key, which is noted below but not addressed here.Approach
Resolve position-invariant keys from
KeyboardEvent.codebefore consultingKeyboardEvent.key:The table covers only keys whose physical position is identical on every layout: Space, Enter, Tab, Backspace, Delete, Escape, the four arrows, and F1–F12. Every token it emits is already accepted by
stable_logical_to_codeinhotkey_layout.rs, so these shortcuts bypass the character round-trip through the layout entirely.Punctuation and digits deliberately stay on the
event.keypath.Semicolonproducesmon AZERTY andDigit1produces&, so resolving those from the physical code would store the wrong logical key and register the wrong physical key on non-QWERTY layouts. A test locks that behaviour in.The change is behaviour-preserving for every case that already worked: bare Space, Enter, Tab, arrows and F-keys resolve to the identical token via the code path.
Testing
macOS 15.6, French layout, MacBook Pro internal keyboard.
npm test— 120 Rust tests, 28 frontend tests,tsc --noEmit, all passingnpm run build— passingcargo clippy --manifest-path src-tauri/Cargo.toml --all-targets -- -D warnings— cleanprettier --checkon both changed files — cleanVerified end to end in
tauri:devwith Accessibility granted: capturingOpt+Spacenow logstoken=Spacethenrecorded=Alt+Space, registration logsresolved stable logical key "Space" -> physical Space, and a full dictation session ran on the bound shortcut.New test fixtures use the events the browser actually sends (
key: " ",code: "Space",altKey: true). The pre-existing fixture used a real U+0020, which is the one input this path never receives, so it passed both before and after the fix.Not covered
Opt+<letter>remains broken for the same underlying reason.Opt+E/I/N/Ureportkey: "Dead", sonormalizeCapturedKeyreturnsnull, the keydown is dropped and the recorder stays onAltindefinitely;Opt+Areportsæon a French layout, which no layout resolves. Fixing that needs the base character for a physical code, which the frontend cannot obtain in WKWebView (navigator.keyboard.getLayoutMapis Chromium-only). A Tauri command prefetching acode → base charactermap atstartCapturewould keep the keydown handler synchronous. Happy to open a separate issue or PR if that direction is wanted.