Skip to content

refactor(web): central keyboard-shortcut registry (groundwork for #43) - #106

Merged
setkyar merged 2 commits into
mainfrom
feat/keybinding-registry
Aug 18, 2026
Merged

refactor(web): central keyboard-shortcut registry (groundwork for #43)#106
setkyar merged 2 commits into
mainfrom
feat/keybinding-registry

Conversation

@setkyar

@setkyarsetkyar commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

PR 1 of 2 toward #43 (customizable keyboard shortcuts). This is a pure refactor with no behavior change — it introduces a central registry for the remappable shortcuts and migrates the scattered inline handlers to consult it. No user-facing change yet.

Turns out the shortcuts were not all in keyboard-nav.js as the issue assumed — they were spread across five handler files. This PR unifies them behind one registry so PR 2 can add the settings UI and per-user overrides without touching each handler again.

What changed

  • New web/src/shared/keybindings.js — the KEY_ACTIONS registry (id, category, default combo) plus matcher helpers (matchesAction, comboMatchesEvent, parseCombo, expectedEventKey). Combo grammar: mod = ⌘/Ctrl, ctrl = Ctrl-only, plus shift/alt.
  • Migrated handlers to matchesAction(id, e):
    • shared/keyboard-nav.js — settings, j/k, ⇧G, ⇧I
    • session/session-globals.js⌘K ⌘B ⌘T ⌘⇧L ⌘⇧N ⌘/
    • routes/SessionsPage.svelte — index ⌘⇧L, ⌘K
    • session/ui/search-filters.jst/o/p
    • components/session/chat/textarea-controls.js⇧Tab, ⌃I/⌃L

Scope (deliberate)

Remappable = global/navigation/composer only. Left hardcoded: structural modal keys (Escape-close, arrow-nav, Tab focus-trap), composer Enter-to-submit, and the multi-key g g sequence — these are UI affordances, not preferences.

Fidelity

The nav keys match the literal produced key char (e.key === 'G') exactly as before, so Caps Lock and every prior path behave identically. The three plain toggles keep their key-only, modifier-agnostic matching. All 722 frontend tests pass with zero changes to the existing handler tests — the parity check for "no behavior change."

Testing

New keybindings.test.js (matcher semantics, aliases, overrides, registry integrity). make build green (incl. export bundle).

Next (PR 2)

Settings UI section, override persistence via the existing settings store + a new settingDefaults key, conflict detection, ShortcutsModal reading the registry (also fixes the current cheatsheet drift), Playwright E2E + screenshots, docs.

Follow-up commit: layout-tolerant punctuation matching

A second commit (9dc6a12) relaxes the matcher for punctuation combos: Shift absence is only enforced where Shift changes meaning (letters, named keys like Tab). On layouts where / is a shifted key (German, French, …), ⌘/ arrives with shiftKey=true and the strict check made the shortcuts-help binding unreachable. event.key is already the shifted result for punctuation, so an unrequested Shift there is layout noise — while ⌘⇧K-style rejection still holds for letters. One existing keyboard-nav test (Cmd+Shift+,) was updated to encode the new semantics: '<' (US layout) still doesn't navigate; ',' with Shift (shifted-comma layouts) does.

Introduce web/src/shared/keybindings.js: a single source of truth for the
remappable global/navigation/composer shortcuts, plus matcher helpers. Migrate
the five inline handlers (keyboard-nav, session-globals, SessionsPage index,
search-filters, textarea-controls) to ask the registry `matchesAction(id, e)`
instead of hardcoding `e.key === …` / modifier checks.
Pure refactor — defaults are unchanged and no override loading exists yet, so
behavior is identical. All 722 frontend tests pass with no changes to the
existing handler tests, confirming parity. Structural modal keys (Escape,
arrows, Tab focus-traps), Enter-to-submit, and the multi-key `g g` sequence are
intentionally left hardcoded; they are UI affordances, not preferences.
Groundwork for #43 (customizable shortcuts). The settings UI, override
persistence, conflict detection, and modal reflection land in a follow-up PR
stacked on this one.
On layouts where '/' is a shifted key (German, French, ...), Cmd+/ arrives
with shiftKey=true and the strict modifier check made the shortcuts-help
binding unreachable. Shift is now only enforced where it changes meaning:
letters and named keys like Tab. For punctuation, event.key is already the
shifted result, so an unrequested Shift is layout noise.
@setkyar
setkyar merged commit 79162bf into mainAug 18, 2026
6 checks passed
@setkyar
setkyar deleted the feat/keybinding-registry branch August 18, 2026 05:59
Sign up for freeto 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

@setkyar