Skip to content

Configurable keybindings and consistent terminal link modifiers - #554

Open
tbrownio wants to merge 9 commits into
mainfrom
configurable-keybindings
Open

tbrownio wants to merge 9 commits into
mainfrom
configurable-keybindings

Conversation

@tbrownio

@tbrownio tbrownio commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Description

Cataloged Pane application commands now use one persistent shortcut model, shared across repositories and worktrees in the same Pane data directory. Settings → Shortcuts can record, unassign, and reset bindings, shows conflicts with snippets and custom commands, and supplies the same effective keys to Help, menus, renderer dispatch, terminal interception, and embedded-browser forwarding. For example, remapping Add Claude Code to Alt+F6 replaces its default chord and launches one terminal from ordinary UI, xterm, or a TUI.

Terminal HTTP(S), OSC-8, and Git links share a modifier router: Command-click on macOS / Control-click elsewhere opens externally; adding Shift opens the session's Browser panel. Project terminals and Pane Chat fall back externally when no Browser surface is available. Modified routing validates credential-free HTTP(S) URLs, and unsupported modifiers/buttons open nothing. Unmodified OSC-8 activation preserves its existing behavior.

Implements the approved brief. Rebased onto 99791ac8d9db3ac27db321c15ca268175fc0a54b, preserving serialized config writes and appearance settings. Closeout fixes also stop remapped continuous scrolling on release (including the webview/preload bridge), preserve same-URL Browser reloads across renderer restarts, and use native table semantics in Shortcuts. Unchanged Shift+Arrow/Page defaults remain native-browser-owned; explicit remaps still forward.

Validation

Head: dc71eb9e5b1c409bfb6cb3e8ba06c5c5d024b587.

  • Final-head CI: Quality Checks + Smoke and main-process tests on macOS and Windows pass. React Doctor reports no new issues; Socket checks pass. RunPane wrapper matrix is skipped by the changed-area filter. No unresolved review threads remain.
  • pnpm lint and pnpm typecheck: pass.
  • pnpm build:frontend and pnpm build:main: pass, including sandboxed-preload and production React Scan exclusion checks.
  • Final-head CI Vitest: frontend 395 pass; main 1,032 pass / two skipped on Linux and macOS, 1,031 pass / three skipped on Windows. CI also passes 29 maintained functional smoke tests and 47 sandboxed-preload routing cases.
  • The actual main callback and bundled preload pass a VM test for key-release forwarding, including release after configuration changes. This is simulated IPC/DOM evidence, not native Electron keyboard QA.
  • Dedicated-port headless Playwright: 23 feature tests pass across shortcuts-settings, launch-shortcuts, and terminal-links. Covers all three agent launches in worktree/main-repo views, Alt+F6 in xterm/TUI focus, continuous-scroll release, recorder/reset/conflict flows, axe checks, narrow layout, and link destinations/counts. Desktop and narrow screenshot cases were re-run after evidence capture changes: both pass.
  • Broader settings.spec.ts: 24 pass; one Remote Access test times out waiting for “This Machine Label.” The same test fails at the same step on clean base 99791ac8 using a separate port. This suite is not claimed green.
  • Two independent automated implementation reviewers cleared their findings after targeted revalidation. Automated review is not human approval.

Remaining desktop QA

These are still open acceptance checks; no native desktop pass is claimed:

  • Real Electron embedded-webview focus and remapped agent launch on macOS, Windows/WSL, and Linux; restart after saving and confirm propagation.
  • macOS Control-click preserves the native context menu; Command+Shift-click twice performs one navigation per activation without an external window.
  • Pane Chat's actual terminal: primary+Shift opens externally once with no hidden Browser panel. Its eligibility predicate is unit-tested; Project fallback is tested through headless xterm.
  • Physical German/AltGr and Option-sensitive layouts, including AltGr+Q typing @ and literal Control+backslash delivering SIGQUIT. Synthetic/unit coverage does not prove OS keyboard translation.
  • Screen-reader and 200% zoom pass. Keyboard-only recording, axe, and narrow viewport checks are automated.

Screenshots

Headless Chromium with the Electron API mock, not native Electron:

Shortcuts settings

Narrow layout

@github-actions

github-actions Bot commented Aug 29, 2026

Copy link
Copy Markdown

React Doctor found no new issues. 🎉

Reviewed by React Doctor for commit dc71eb9.

Tyler Brown added 8 commits September 16, 2026 16:20
…ctive-binding dispatch

Phase 1 of configurable keybindings: one typed catalog of every registry-backed
command, keyboardShortcutOverrides in the global config (sparse: override or
null), a chord->candidates hotkey index that runs neither command on an
ambiguous chord, terminal release and webview forwarding driven by the
configured catalog, a config:updated relay for live propagation, and agent
launch presets referencing catalog ids instead of literal hotkeys.

Claude-Session: https://claude.ai/code/session_016CuGxyYX4yEZ1dfUZZDm36
…eset

Phase 2 of configurable keybindings. Settings → Shortcuts gains a searchable,
category-grouped key-binding table sourced from the shared catalog plus the
current snippet and custom-command bindings: effective and default chords,
activation scope, customized/unassigned/invalid state, and per-environment
availability. An accessible recorder (window-capture while armed, Escape
cancels without closing Settings, Backspace unassigns, terminal-reserved chords
refused, recording a row's default removes the override) writes a sparse draft;
conflicts are validated globally (no platform gate) and block Apply naming both
owners; per-row Reset deletes the override and Reset all sends {}.

Help renders the same map. The raw override map round-trips untouched
(unknown ids and malformed values are preserved on disk and shown as
"invalid — using default"). ConfigManager validates conflicts globally.

Adds Playwright coverage for the settings map, agent-launch remaps in worktree
and main-repo views (mock now records panel creates/updates/activations and
broadcasts panel:created), plus unit coverage for the map builder and glyphs.

Claude-Session: https://claude.ai/code/session_012BQcLGZB4EmWoxpTTCWrC9
… router

Phase 3 of configurable keybindings. Auto-detected URLs, OSC-8 hyperlinks, and
git SHA/issue links share one pure classifier and router: Primary+Shift opens a
validated, credential-free HTTP(S) URL in the session's Browser panel (reusing
the first one or creating one through a single create-or-navigate helper) and
falls back to the external browser exactly once where no Browser surface exists
(Project/main-repo terminals, Pane Chat, no session context); Primary opens
externally; the macOS Control-click alias applies only to unshifted primary
button activations; Alt and non-primary buttons never qualify; rejected URLs on
the Browser branch open nothing. Hover text names the available gestures per
provider and platform.

The browser-panel:navigate event path is removed; BrowserPanel navigates from
panel state alone, with a monotonic navigationNonce so a repeated same-URL
request reloads. The selection popover shows "Open in Browser" only where a
Browser surface exists; HTML previews reuse the same helper.

Also fixes a pre-existing off-by-one in the file and git link providers: xterm
passes a 1-based buffer line to provideLinks, so they read the row below and
emitted ranges one row off, which meant their links never matched the pointer.

Claude-Session: https://claude.ai/code/session_012BQcLGZB4EmWoxpTTCWrC9
- Every gesture-driven link sink (Pane Browser, external, and the
  unavailable-surface fallback) now takes only a validated, credential-free
  HTTP(S) URL; rejected targets open nothing. OSC-8 plain click keeps its
  pre-existing pass-through.
- Alt and non-primary-button activations are classified as rejected so OSC-8
  cannot treat them as plain clicks.
- Shortcuts settings: the key-binding Apply and the snippet Apply are each
  blocked while the other draft is unsaved, since conflicts are validated
  across both drafts but persisted separately.
- HTML previews retitle a reused Browser panel again.
- Drop three unused type exports flagged by Knip.

Claude-Session: https://claude.ai/code/session_012BQcLGZB4EmWoxpTTCWrC9
Recording an unmodified named key (Tab, Enter, Space, arrows, paging…) would
hijack focus navigation and typing app-wide, and mod+c / mod+shift+c is the
terminal's copy shortcut; both are now refused with live status text.

Claude-Session: https://claude.ai/code/session_012BQcLGZB4EmWoxpTTCWrC9
@tbrownio
tbrownio force-pushed the configurable-keybindings branch from d630469 to 16fbc75 Compare September 16, 2026 23:27
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