From cda6f96abb77d3411e9d7a967eaf17ba8937dbe1 Mon Sep 17 00:00:00 2001 From: "Timo S." <18382402+sti0@users.noreply.github.com> Date: Sun, 15 Nov 2026 09:30:07 +0100 Subject: [PATCH 1/2] fix(web): Ctrl+B reaches a focused terminal again The sidebar toggle listens for mod+b in the capture phase and ignored terminal focus, so on Linux and Windows it swallowed Ctrl+B before the terminal saw it. tmux with its default prefix was unusable. The toggle now skips Ctrl chords while a terminal has focus. Cmd never reaches the terminal, so Cmd+B still toggles the sidebar from a focused terminal on macOS. Written by Claude Opus 5.5 in T3 Code. Co-Authored-By: Claude Opus 5.5 --- apps/web/src/components/AppSidebarLayout.tsx | 21 ++++++++------- apps/web/src/keybindings.test.ts | 28 ++++++++++++++++++++ apps/web/src/keybindings.ts | 10 +++++++ 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/apps/web/src/components/AppSidebarLayout.tsx b/apps/web/src/components/AppSidebarLayout.tsx index 8e4baf20451c8..7fc5a2b6be00b 100644 --- a/apps/web/src/components/AppSidebarLayout.tsx +++ b/apps/web/src/components/AppSidebarLayout.tsx @@ -20,6 +20,7 @@ import { import { getLocalStorageItem, removeLocalStorageItem } from "../hooks/useLocalStorage"; import { isRichTextBoldShortcut, + isSidebarToggleShortcut, resolveShortcutCommand, shortcutLabelForCommand, } from "../keybindings"; @@ -347,15 +348,17 @@ function SidebarControl({ showSidebar }: { readonly showSidebar: boolean }) { // the toggle stays available everywhere else. return; } - const command = resolveShortcutCommand(event, keybindings, { - context: { - terminalFocus: isTerminalFocused(), - previewFocus: isPreviewFocused(), - ...readRoutePanelsOpen(router), - usagePageOpen, - }, - }); - if (command !== "sidebar.toggle") return; + if ( + !isSidebarToggleShortcut(event, keybindings, { + context: { + terminalFocus: isTerminalFocused(), + previewFocus: isPreviewFocused(), + ...readRoutePanelsOpen(router), + usagePageOpen, + }, + }) + ) + return; event.preventDefault(); event.stopPropagation(); diff --git a/apps/web/src/keybindings.test.ts b/apps/web/src/keybindings.test.ts index 3b596f838fa0d..fb6f719bb2346 100644 --- a/apps/web/src/keybindings.test.ts +++ b/apps/web/src/keybindings.test.ts @@ -15,6 +15,7 @@ import { effectiveShortcutsForCommand, formatShortcutLabel, isRichTextBoldShortcut, + isSidebarToggleShortcut, isTerminalNewShortcut, isTerminalSplitShortcut, resolveChatShortcutCommand, @@ -813,6 +814,33 @@ describe("isRichTextBoldShortcut", () => { }); }); +describe("isSidebarToggleShortcut", () => { + it("leaves Ctrl+B to a focused terminal, where it is the tmux prefix", () => { + const ctrlB = event({ key: "b", ctrlKey: true }); + assert.isFalse( + isSidebarToggleShortcut(ctrlB, DEFAULT_BINDINGS, { + platform: "Linux", + context: { terminalFocus: true }, + }), + ); + assert.isTrue( + isSidebarToggleShortcut(ctrlB, DEFAULT_BINDINGS, { + platform: "Linux", + context: { terminalFocus: false }, + }), + ); + }); + + it("keeps Cmd+B toggling the sidebar from a focused terminal on macOS", () => { + assert.isTrue( + isSidebarToggleShortcut(event({ key: "b", metaKey: true }), DEFAULT_BINDINGS, { + platform: "MacIntel", + context: { terminalFocus: true }, + }), + ); + }); +}); + describe("composer and pull request shortcuts", () => { it("uses the dictation chord outside the terminal and preserves terminal split", () => { const chord = event({ key: "d", ctrlKey: true, shiftKey: true }); diff --git a/apps/web/src/keybindings.ts b/apps/web/src/keybindings.ts index 75f617d3cca86..19ad652cfb555 100644 --- a/apps/web/src/keybindings.ts +++ b/apps/web/src/keybindings.ts @@ -379,6 +379,16 @@ export function isDiffToggleShortcut( return matchesCommandShortcut(event, keybindings, "diff.toggle", options); } +export function isSidebarToggleShortcut( + event: ShortcutEventLike, + keybindings: ResolvedKeybindingsConfig, + options?: ShortcutMatchOptions, +): boolean { + // Ctrl+letter is a control character the terminal needs (tmux's prefix is Ctrl+B); Cmd never reaches it. + if (event.ctrlKey && options?.context?.terminalFocus) return false; + return matchesCommandShortcut(event, keybindings, "sidebar.toggle", options); +} + export function isOpenFavoriteEditorShortcut( event: ShortcutEventLike, keybindings: ResolvedKeybindingsConfig, From 9a5a2b189af9a4353f330d0eb0570bddf4a08a13 Mon Sep 17 00:00:00 2001 From: "Timo S." <18382402+sti0@users.noreply.github.com> Date: Sun, 15 Nov 2026 09:30:10 +0100 Subject: [PATCH 2/2] docs(web): note that a focused terminal keeps Ctrl chords from the sidebar toggle Co-Authored-By: Claude Opus 5.5 --- apps/web/src/keybindings.ts | 2 +- docs/user/keybindings.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/web/src/keybindings.ts b/apps/web/src/keybindings.ts index 19ad652cfb555..88a30f76b675d 100644 --- a/apps/web/src/keybindings.ts +++ b/apps/web/src/keybindings.ts @@ -384,7 +384,7 @@ export function isSidebarToggleShortcut( keybindings: ResolvedKeybindingsConfig, options?: ShortcutMatchOptions, ): boolean { - // Ctrl+letter is a control character the terminal needs (tmux's prefix is Ctrl+B); Cmd never reaches it. + // A focused terminal owns Ctrl chords, such as tmux's Ctrl+B prefix; Cmd never reaches it. if (event.ctrlKey && options?.context?.terminalFocus) return false; return matchesCommandShortcut(event, keybindings, "sidebar.toggle", options); } diff --git a/docs/user/keybindings.md b/docs/user/keybindings.md index 3e4d47e7c9433..ff1e8d06cefdb 100644 --- a/docs/user/keybindings.md +++ b/docs/user/keybindings.md @@ -206,6 +206,8 @@ if the browser takes it first. Many defaults include `!terminalFocus` so they do not intercept terminal input. Keep that condition when remapping them if you want the same behavior. +`sidebar.toggle` never takes a Ctrl chord from a focused terminal, so tmux's `Ctrl+B` +prefix reaches it. On macOS, `Cmd+B` still toggles the sidebar there. ## Desktop quit shortcut