Pull Request Overview
- Opened on August 31, 2026
- Status Merged
- Commit count 2 with first commit August 31, 2026
Total Delta
Open Days
Test Delta
How long has this pull request spent in each phase of its lifecycle?
Data pending calculation for pull request
JS-9868: fix Space key silently breaking the global search shortcut
Closes JS-9868.
Problem
Recording any Space-containing combo in Settings โ Shortcuts silently kills the OS-level global search shortcut. The panel shows what looks like a valid binding; nothing is registered with the OS, and no error surfaces anywhere.
Root cause
keyboard.eventKey() returns e.key.toLowerCase(), and for the Space key e.key is a literal " " โ not the canonical "space" the J.Shortcut defaults use ([ cmdKey, 'shift', 'space' ]). The recorder in popup/shortcut.tsx only strips key/digit prefixes off e.code, so Space fell through to pressed.push(key) and persisted " ".
Everything downstream then broke, quietly:
-
MenuManager.getAccelerator()emittedCmdOrCtrl+Shift+ -
globalShortcut.register()threwError processing argument at index 0, conversion failure - the
try/catchininitGlobalShortcuts()swallowed the throw and leftglobalShortcutRegistered = false -
getSymbolsFromKeys()rendered" "as a blank chip, so the UI showed a shortcut that had never been registered
Changes
-
Recorder โ resolve Space through the existingspecial/J.Keypath (J.Key.space == 32), so it stores the canonical'space'. Root cause. -
getAccelerator()โ anamedKeysmap (alongside the existingarrowKeys) coveringspace, a legacy' ', andcomma. Configs already written by0.56.8-betaheal themselves instead of staying dead. -
Storage.getShortcuts()โ normalize a legacy' 'on read, guarded withArray.isArray. This matters beyond global search: stored keys feedJ.Shortcut.getItems(), so any in-app shortcut recorded with Space was affected too. -
initGlobalShortcuts()โ log theregister()failure instead of discarding it. A swallowed throw here is indistinguishable from a shortcut that just never fires, which is what made this hard to see.
From code review
-
commahad the identical defect and is fixed by the same map. It was already in the recorder'sspecialarray before this branch, so it has always persisted the literal string'comma', whichgetAccelerator()uppercased toCOMMAโ unparseable, throws exactly like" ". Reachable today by binding anything toโ,;newTab/close/selectAlland seven other menu accelerators have no in-app fallback, so such a binding is simply dead. -
Capped a chord at one non-modifier. Adding'space'tospecialmade a bad state reachable: that loop had no equivalent of thecodeCheckscodesguard, so tappingAthen Space inside the 200 ms save window stored['cmd','shift','a','space']where Space was previously discarded. The OS acceptsCmdOrCtrl+Shift+A+Space(verified REGISTERED) but in-app matching builds its chord from a single keydown and can never produce two non-modifiers โ so the binding silently diverges from what the panel displays.codesnow means "a non-modifier was captured" and gates all three push sites. -
Array.isArrayguard.shortcutImportJSON.parses an arbitrary user file with no validation;.map()on a non-array value would throw at boot viakeyboard.initShortcuts.
Verification
Driving the real MenuManager.getAccelerator() from a bundled menu.ts inside an Electron 41.9.0 process on macOS 26.5.2:
| stored keys | before | after |
|---|---|---|
| ["cmd","shift"," "] | CmdOrCtrl+Shift+ โ THREW | CmdOrCtrl+Shift+Space โ REGISTERED |
| ["cmd","shift","comma"] | CmdOrCtrl+Shift+COMMA โ THREW | CmdOrCtrl+Shift+, โ REGISTERED |
| ["cmd","shift","space"] | REGISTERED | REGISTERED |
| letter / digit / arrow / + / no override | REGISTERED | unchanged |
src/ts/lib/storage.test.ts gains 5 cases; 4 of them fail against origin/develop and the fifth is a deliberate no-change guard. Suite passes 8/8. bunx tsc -p tsconfig.electron.json exits 0; the renderer typecheck reports only 3 pre-existing Cannot find module errors for gitignored codegen artifacts, byte-identical on a stashed origin/develop baseline. ESLint and the biome/eslint pre-commit hooks pass.
Known adjacent issues, deliberately NOT in this PR
Review surfaced more of the same root cause. All pre-existing, none introduced here, each wants its own change:
-
Non-Latin layouts.codeChecksrecovers letters/digits positionally, but every othere.codefalls through to the layout-localizede.key.ะ ะฅ ะ ะฎ ะญ ะ รค รถ รผ รall produce throwing accelerators โ verified against the parser. -
Modifier-only chords are saveable. With only modifiers held the recorder saves after 1500 ms, and theglobalSearchguard requires โฅ1 modifier but never a non-modifier.['cmd','shift']โCmdOrCtrl+Shiftโ throws. -
The red-alert misdiagnoses.registered == falserenders "used by another application", but a malformed accelerator (throw) and an OS-taken one (false) are indistinguishable at that boundary.globalShortcutUnavailableis Linux+Wayland only, so macOS/Windows get no correct explanation โ and the alert isisGlobal-gated, so the other 18 menu accelerators get nothing at all. -
getAcceleratorcollapses Ctrl into Cmd on macOS ((keyLower == 'ctrl') || (keyLower == 'cmd')โCmdOrCtrl). The shipped defaultshortcut: ['ctrl','space']displays and matches asโSpacein-app but registers asโSpacein the Help menu. -
Dead keys / IME.e.keyis'Dead'for accent keys and'Process'while a CJK IME composes; both throw. -
Numpad records the main-row digit (NumLock on) or'End'(off).
The structural fix for most of these is to extract getAccelerator into a pure module with no imports โ every one of them flows through it, and it is currently unreachable from vitest because menu.ts imports electron plus five managers at module scope.
Scope note
Found while investigating a separate report that global search does not work on macOS 27 beta. This is not that bug โ macOS 27 also assigns Cmd+Shift+Space to Visual Intelligence system-wide, and the reporter says rebinding does not help either. That investigation continues in the original issue; this fix stands on its own and affects every platform.
Affects v0.56.8-beta only (feature landed in f7527e3490, 2026-08-26). Not in any stable release.
PR was closed without comments.