You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Right panel launcher hotkeys fail on non-Latin keyboard layouts & terminal close dialog UX issues #13427
I searched existing issues and did not find a duplicate.
I included enough detail to reproduce or investigate the problem.
Area
apps/web
Steps to reproduce
Right panel shortcut with non-Latin keyboard layout:
Switch macOS keyboard layout to a non-Latin layout (e.g., Ukrainian).
Press Cmd+Opt+B to open the right panel, then press the key for Terminal (T, which produces е in Ukrainian layout).
Notice nothing happens, or ChatView type-to-focus intercepts the keystroke into composer instead of launching the terminal.
Additionally, when the right panel opens, keyboard focus is not immediately placed in the launcher container, making single-key launcher shortcuts unreliable.
Terminal close confirmation dialog UX:
Open a terminal and press Cmd+W to close it.
Confirmation dialog appears asking to close the terminal.
There is no option to remember the choice or stop asking.
Focus defaults to Cancel rather than Confirm.
Arrow keys do not navigate focus between dialog buttons.
Expected behavior
Right panel launcher shortcuts (such as T for Terminal) should work reliably regardless of active keyboard layout (falling back to physical key codes like KeyT), focus the container when opened, and not be swallowed by the composer.
The terminal close confirmation dialog should provide a "Don't ask again" checkbox (persisted in settings with a toggle under General Settings), default focus to Confirm, and allow arrow key navigation between controls for a full keyboard flow.
Actual behavior
Single-key launcher shortcuts fail on non-Latin keyboard layouts and get captured by composer.
Terminal close dialog lacks "Don't ask again", defaults Enter to Cancel, and does not support arrow keys navigation.
The empty state listens on window in the capture phase while it is mounted, and publishes the same Latin letters on data-surface-launcher-keys (B, T, F, D, P, L, A, M, whichever are available). shouldTypeToFocusComposer bails only when event.key is one of those letters:
// The right-panel surface launcher claims its shortcut letters while it is// visible (data attribute set in RightPanelTabs); those keys open surfaces// instead of typing into the composer.constlauncherKeys=document.querySelector("[data-surface-launcher-keys]")?.getAttribute("data-surface-launcher-keys");if(launcherKeys&&launcherKeys.toLowerCase().includes(event.key.toLowerCase()))returnfalse;
Modified shortcuts already fall back to the physical key when the layout character is not a Latin letter. That is why Cmd+Opt+B still opens the panel on a Ukrainian layout:
functionresolveEventKeys(event: ShortcutEventLike): Set<string>{constlayoutKey=normalizeEventKey(event.key);constkeys=newSet([layoutKey]);// The physical-position fallback exists for layouts that type non-Latin// letters (Cyrillic, Greek) and for Option-modified symbols on macOS.// When the layout already produces a Latin letter, match on it alone;// otherwise a remapped physical key triggers shortcuts for two different// letters at once and shadows system shortcuts on non-QWERTY layouts.constletterCode=event.code?.match(/^Key([A-Z])$/)?.[1];if(letterCode&&!/^[a-z]$/.test(layoutKey)){keys.add(letterCode.toLowerCase());}keys.add(shortcutKeyFromEvent(event));returnkeys;}
The bare T does not use that fallback. On a Ukrainian layout that key reports е with codeKeyT. е is not in the launcher list, so the capture handler returns and type-to-focus inserts it into the composer. The same matcher is used for letter shortcuts inside the add-surface menu.
The empty state does call focus() when its node mounts (focusOnMount in RightPanelTabs). Those letters also do not require the launcher to be the focused element. They do stop when focus is in an input, textarea, select, or contenteditable, which includes the composer. usePanelPresence turns the panel present in an effect after open becomes true, so a letter pressed in that gap still belongs to the composer. After the empty state has mounted, the failure that remains on a non-Latin layout is the event.key comparison.
The fix for this half is the same guard as resolveEventKeys: use codeKeyA–KeyZ only when event.key is not already a Latin letter, in both surfaceShortcutActionForKey and shouldTypeToFocusComposer. A Dvorak or Colemak layout that types a different Latin letter must keep matching event.key alone.
The close dialog matches the other confirmations.
confirmTerminalClose always asks, through the shared host, with variant: "destructive". ConfirmDialogOptions is only that variant. Cancel is the first button, and the host passes no initialFocus, so the dialog opens on Cancel and Enter activates it. Nothing handles arrow keys; Tab moves between the buttons. There is no “Don’t ask again” control. Thread unpin, archive, and delete are switches under Settings → General → Confirmations, with no checkbox in the dialog.
A remembered skip, and arrow-key movement inside this dialog, would be new behavior. Defaulting this host’s initial focus to Confirm would also make Enter confirm delete and the other destructive prompts.
This issue should stay the shortcut bug. The dialog requests belong on their own.
#13428 is the reporter’s PR for both halves. The shortcut half follows the Latin-letter guard above. The new empty-state effect lists shortcutActionsRef in its dependency array before that ref is declared, so rendering the launcher throws. The dialog half also points every confirmation’s initial focus at Confirm.
Same event.key gap, different call sites: #13409 (Mod+B bold) and #13411 (paste-as-text).
Existing work covers the shortcut repair: #21508 is open specifically for non-Latin launcher letters. The composer-interception repair landed in 86fa9e0a0c. The optional terminal-confirmation setting also has an open PR, #16615. No competing implementation is needed.
The remaining requests to change destructive-dialog default focus, add arrow navigation and remember the choice are product changes. The maintainer closing comment on #13428 explicitly directs that confirmation behavior to Ideas. Routing that discussion for maintainer conversion; the non-Latin bug remains covered by the focused open PR.
Activity
juliusmarminge commentedon Sep 24, 2026
Confirmed on
mainat b2b43be. Desktop and web share this UI. Mobile does not use this launcher.Bare launcher letters compare
event.key, so a non-Latin layout never hits them.surfaceShortcutActionForKeyactivates an available surface only whenevent.keyequals the shortcut letter. Modified keys are ignored here.The empty state listens on
windowin the capture phase while it is mounted, and publishes the same Latin letters ondata-surface-launcher-keys(B, T, F, D, P, L, A, M, whichever are available).shouldTypeToFocusComposerbails only whenevent.keyis one of those letters:Modified shortcuts already fall back to the physical key when the layout character is not a Latin letter. That is why
Cmd+Opt+Bstill opens the panel on a Ukrainian layout:The bare
Tdoes not use that fallback. On a Ukrainian layout that key reportsеwithcodeKeyT.еis not in the launcher list, so the capture handler returns and type-to-focus inserts it into the composer. The same matcher is used for letter shortcuts inside the add-surface menu.The empty state does call
focus()when its node mounts (focusOnMountinRightPanelTabs). Those letters also do not require the launcher to be the focused element. They do stop when focus is in an input, textarea, select, or contenteditable, which includes the composer.usePanelPresenceturns the panel present in an effect afteropenbecomes true, so a letter pressed in that gap still belongs to the composer. After the empty state has mounted, the failure that remains on a non-Latin layout is theevent.keycomparison.The fix for this half is the same guard as
resolveEventKeys: usecodeKeyA–KeyZonly whenevent.keyis not already a Latin letter, in bothsurfaceShortcutActionForKeyandshouldTypeToFocusComposer. A Dvorak or Colemak layout that types a different Latin letter must keep matchingevent.keyalone.The close dialog matches the other confirmations.
confirmTerminalClosealways asks, through the shared host, withvariant: "destructive".ConfirmDialogOptionsis only that variant. Cancel is the first button, and the host passes noinitialFocus, so the dialog opens on Cancel and Enter activates it. Nothing handles arrow keys; Tab moves between the buttons. There is no “Don’t ask again” control. Thread unpin, archive, and delete are switches under Settings → General → Confirmations, with no checkbox in the dialog.A remembered skip, and arrow-key movement inside this dialog, would be new behavior. Defaulting this host’s initial focus to Confirm would also make Enter confirm delete and the other destructive prompts.
This issue should stay the shortcut bug. The dialog requests belong on their own.
#13428 is the reporter’s PR for both halves. The shortcut half follows the Latin-letter guard above. The new empty-state effect lists
shortcutActionsRefin its dependency array before that ref is declared, so rendering the launcher throws. The dialog half also points every confirmation’s initial focus at Confirm.Same
event.keygap, different call sites: #13409 (Mod+B bold) and #13411 (paste-as-text).juliusmarminge commentedon Oct 22, 2026
Existing work covers the shortcut repair: #21508 is open specifically for non-Latin launcher letters. The composer-interception repair landed in 86fa9e0a0c. The optional terminal-confirmation setting also has an open PR, #16615. No competing implementation is needed.
The remaining requests to change destructive-dialog default focus, add arrow navigation and remember the choice are product changes. The maintainer closing comment on #13428 explicitly directs that confirmation behavior to Ideas. Routing that discussion for maintainer conversion; the non-Latin bug remains covered by the focused open PR.