Repository navigation
fix(tab-bar): unstick Ctrl+Tab switcher opened from a focused browser guest - #9954
Jingyue-Wu wants to merge 1 commit into
Conversation
… guest When the Ctrl+Tab gesture starts inside a focused webview guest, main preventDefault-s the chord keydown, and Chromium then suppresses every guest keyup until the next keydown — so the ui:ctrlTabKeyUp commit could never arrive and the switcher overlay stayed stranded open (stablyai#9937). Hand the rest of the held gesture to the renderer window instead: opening the switcher from a guest blurs the webview so advance, release-commit, and Escape all flow through the window key handlers, and commit/cancel return focus to the browser page when appropriate. Also clear the guest's held-chord flag on blur so stale state cannot emit a phantom commit. Fixes stablyai#9937
📝 WalkthroughWalkthroughThe changes reset held Ctrl+Tab and double-tap state when a browser guest blurs. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tests/e2e/browser-ctrl-tab-switcher.spec.ts (1)
64-92: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDedupe webview lookup between
focusGuestPageandsendGuestCtrlTabKeyDown.Both helpers repeat the identical
[data-browser-overlay-tab-id]lookup and "Missing webview" throw. Extracting a sharedgetBrowserGuestWebview(page, browserTabId)helper avoids drift if the selector or error message changes.♻️ Proposed refactor
+async function getBrowserGuestWebview( + page: OrcaPage, + browserTabId: string +): Promise<void> { + // shared lookup logic used by focusGuestPage and sendGuestCtrlTabKeyDown +}Extract the
document.querySelectorAll('[data-browser-overlay-tab-id]')+webviewlookup body from bothpage.evaluatecallbacks into one exported evaluate-able helper string/function reused by both call sites.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 7bbf7080-8f93-4350-8b29-37363fc0423a
📒 Files selected for processing (5)
src/main/browser/browser-guest-ui.test.tssrc/main/browser/browser-guest-ui.tssrc/renderer/src/components/tab-bar/RecentTabSwitcher.test.tsxsrc/renderer/src/components/tab-bar/RecentTabSwitcher.tsxtests/e2e/browser-ctrl-tab-switcher.spec.ts
Summary
Fixes #9937.
Fixed issue where the Ctrl+Tab tab switching overlay gets stuck when activated from within a browser window.
Screen.Recording.2026-07-22.at.12.36.06.PM.mov
Testing
pnpm lintpnpm typecheckpnpm testpnpm buildtests/e2e/browser-ctrl-tab-switcher.spec.ts— reproduced the stuck overlay pre-fix (drives the real guestbefore-input-eventpath viawebview.sendInputEvent), green post-fix: (1) opens from the guest and commits on modifier release; (2) advances while held, commits back to the browser tab, and returns focus to the guest page.RecentTabSwitcher.test.tsx(webview blur on IPC open; focus-request restore on cancel),browser-guest-ui.test.ts(guest blur clears held-chord state).AI Review Report
Reviewed with Claude Code. The root cause was established empirically before writing the fix: an instrumented E2E run showed guest keydowns reaching
before-input-eventwhile every keyup after the prevented Ctrl+Tab keydown was suppressed, ruling out IPC wiring and renderer-listener explanations.Risks checked:
switcherRef) and the active element is a<webview>; restore targets the browser page id resolved from the tab (activePageId), matching whatBrowserPaneconsumes. An earlier draft passed the tab id — the E2E focus-restore test caught it.blurnow clearsctrlTabSwitchingso a later unrelated keyup can't emit a phantomui:ctrlTabKeyUp; a phantom commit is additionally a no-op in the renderer (null switcher guard).activeTabType !== 'browser'.Cross-platform: explicitly checked for macOS, Linux, and Windows. No new chords or labels; matching stays behind
matchesRecentTabSwitcherChord/the keybinding registry (Ctrl+Tabdefault on all platforms), the Chromium keyup-suppression behavior is platform-independent (bug reported on Linux, reproduced on macOS), and the change touches no paths, shell behavior, or platform-conditional Electron APIs. SSH use case unaffected — UI keyboard routing only.Security Audit
ui:ctrlTabKeyDown/ui:ctrlTabKeyUpevents, which originate only from the main process's guest shortcut forwarding — guest page content cannot forge them and no guest-supplied data flows into the new code paths.document.activeElementtag checks; the guest keydown remainspreventDefault()-ed, so pages still never observe the Ctrl+Tab chord.queueBrowserFocusRequestpath already used by the palette; ids come from the renderer store, not from guest content.ELI5
Ctrl+Tab from inside a browser tab could leave the tab switcher stuck on screen. Input is handled so the overlay closes when you release the keys, even when focus was in the browser guest.