We were unable to construct the commit group for this pull request: Author does not currently possess a GitClear subscription seat.

JS-9868: fix Space key silently breaking the global search shortcut #2361

Merged
requilence opened 3:42pm on August 31, 2026 wanted to merge 2 commits into anyproto/anytype-ts develop from
fix/JS-9868-shortcut-space-key

Pull Request Overview

  • Opened on August 31, 2026
  • Status Merged
  • Commit count 2 with first commit August 31, 2026

Total Delta

0 Total Diff Delta

Open Days

Open 15 weekdays

Test Delta

0 Diff Delta in Test Files
Breakdown by Phase

How long has this pull request spent in each phase of its lifecycle?

Data pending calculation for pull request

Author avatar

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() emitted CmdOrCtrl+Shift+


  • globalShortcut.register() threw Error processing argument at index 0, conversion failure

  • the try/catch in initGlobalShortcuts() swallowed the throw and left globalShortcutRegistered = false


  • getSymbolsFromKeys() rendered " " as a blank chip, so the UI showed a shortcut that had never been registered

Changes



  1. Recorder โ€” resolve Space through the existing special/J.Key path (J.Key.space == 32), so it stores the canonical 'space'. Root cause.


  2. getAccelerator() โ€” a namedKeys map (alongside the existing arrowKeys) covering space, a legacy ' ', and comma. Configs already written by 0.56.8-beta heal themselves instead of staying dead.


  3. Storage.getShortcuts() โ€” normalize a legacy ' ' on read, guarded with Array.isArray. This matters beyond global search: stored keys feed J.Shortcut.getItems(), so any in-app shortcut recorded with Space was affected too.


  4. initGlobalShortcuts() โ€” log the register() 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



  1. comma had the identical defect and is fixed by the same map. It was already in the recorder's special array before this branch, so it has always persisted the literal string 'comma', which getAccelerator() uppercased to COMMA โ€” unparseable, throws exactly like " ". Reachable today by binding anything to โŒ˜,; newTab/close/selectAll and seven other menu accelerators have no in-app fallback, so such a binding is simply dead.


  2. Capped a chord at one non-modifier. Adding 'space' to special made a bad state reachable: that loop had no equivalent of the codeChecks codes guard, so tapping A then Space inside the 200 ms save window stored ['cmd','shift','a','space'] where Space was previously discarded. The OS accepts CmdOrCtrl+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. codes now means "a non-modifier was captured" and gates all three push sites.


  3. Array.isArray guard. shortcutImport JSON.parses an arbitrary user file with no validation; .map() on a non-array value would throw at boot via keyboard.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. codeChecks recovers letters/digits positionally, but every other e.code falls through to the layout-localized e.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 the globalSearch guard requires โ‰ฅ1 modifier but never a non-modifier. ['cmd','shift'] โ†’ CmdOrCtrl+Shift โ†’ throws.


  • The red-alert misdiagnoses. registered == false renders "used by another application", but a malformed accelerator (throw) and an OS-taken one (false) are indistinguishable at that boundary. globalShortcutUnavailable is Linux+Wayland only, so macOS/Windows get no correct explanation โ€” and the alert is isGlobal-gated, so the other 18 menu accelerators get nothing at all.


  • getAccelerator collapses Ctrl into Cmd on macOS ((keyLower == 'ctrl') || (keyLower == 'cmd') โ†’ CmdOrCtrl). The shipped default shortcut: ['ctrl','space'] displays and matches as โŒƒSpace in-app but registers as โŒ˜Space in the Help menu.


  • Dead keys / IME. e.key is '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.