fix(keybindings): show ⇧ for Shift in Windows/Linux shortcut labels (#35754)

* fix(keybindings): show the ⇧ glyph for Shift on Windows and Linux

Spelled-out Shift made non-mac shortcut labels long (Ctrl+Shift+Backspace).

* test(menu): expect the ⇧ glyph in non-mac app menu hints; align double-tap hint
This commit is contained in:
Neil
2026-10-29 00:08:48 -07:00
committed by GitHub
parent b6ffc2079b
commit 3d812eb9bf
12 changed files with 21 additions and 21 deletions
+3 -3
View File
@@ -128,7 +128,7 @@ describe('registerAppMenu', () => {
expect(buildFromTemplateMock).toHaveBeenCalledTimes(1)
const viewSubmenu = getSubmenu(getTemplate(), 'View')
const expectedForceReloadLabel = `Force Reload\t${isMac ? '⌘⇧R' : 'Ctrl+Shift+R'}`
const expectedForceReloadLabel = `Force Reload\t${isMac ? '⌘⇧R' : 'Ctrl+⇧+R'}`
expect(viewSubmenu).toEqual(
expect.arrayContaining([expect.objectContaining({ label: 'Reload' })])
@@ -254,7 +254,7 @@ describe('registerAppMenu', () => {
registerAppMenu(buildMenuOptions())
const viewSubmenu = getSubmenu(getTemplate(), 'View')
const expectedLabel = `Open Worktree Palette\t${isMac ? '⌘J' : 'Ctrl+Shift+J'}`
const expectedLabel = `Open Worktree Palette\t${isMac ? '⌘J' : 'Ctrl+⇧+J'}`
const paletteItem = viewSubmenu.find((item) => item.label === expectedLabel)
expect(paletteItem).toBeDefined()
@@ -461,7 +461,7 @@ describe('registerAppMenu', () => {
expect(template.find((item) => item.label === 'Orca')).toBeUndefined()
const fileLabels = getSubmenu(template, 'File').map((item) => item.label)
expect(fileLabels).not.toContain(`Export as PDF...\t${isMac ? '⌘⇧E' : 'Ctrl+Shift+E'}`)
expect(fileLabels).not.toContain(`Export as PDF...\t${isMac ? '⌘⇧E' : 'Ctrl+⇧+E'}`)
expect(fileLabels[0]).toBe('Settings')
expect(fileLabels).toEqual(expect.arrayContaining(['Settings', 'Exit']))
@@ -30,7 +30,7 @@ function ActionRow({
const isMac = navigator.userAgent.includes('Mac')
const keys =
shortcut === 'alternate'
? [isMac ? '⇧' : 'Shift', isMac ? '⌘' : 'Ctrl', 'Click']
? ['⇧', isMac ? '⌘' : 'Ctrl', 'Click']
: shortcut === 'primary'
? [isMac ? '⌘' : 'Ctrl', 'Click']
: null
@@ -62,7 +62,7 @@ export function LinkRoutingPreferenceDialogProvider({
const displayHost = displayHostForUrl(displayedRequest?.options.url)
const openLinksInAppDefault = displayedRequest?.options.openLinksInAppDefault === true
const isMac = navigator.userAgent.includes('Mac')
const systemBrowserShortcutKeys = isMac ? ['⇧', '⌘'] : ['Shift', 'Ctrl']
const systemBrowserShortcutKeys = isMac ? ['⇧', '⌘'] : ['⇧', 'Ctrl']
useEffect(() => {
setContextualToursBlockingSurfaceVisible(activeRequest !== null)
@@ -202,7 +202,7 @@ it('updates nominal toggle labels, including an unassigned binding', () => {
vi.stubGlobal('navigator', { userAgent: 'Windows NT 10.0' })
useAppStore.setState({ keybindings: {} })
const view = render(<Harness onSwitchToTerminal={() => {}} />)
expect(view.container.textContent).toContain('Ctrl+Shift+J')
expect(view.container.textContent).toContain('Ctrl+⇧+J')
act(() =>
useAppStore.setState({
keybindings: { 'terminal.toggleNativeChat': ['Mod+Alt+Y', 'Mod+Alt+K'] }
@@ -136,7 +136,7 @@ function KeycapArt({ shortcut }: { shortcut: string | null }): React.JSX.Element
? formatKeybinding(shortcut, platform)
: isMac()
? ['⌘', '⌥', '⇧']
: ['Ctrl', 'Alt', 'Shift']
: ['Ctrl', 'Alt', '⇧']
return (
<div className="absolute inset-0 flex items-center justify-center gap-2.5">
{keys.map((key, index) => (
@@ -72,7 +72,7 @@ export function ShortcutCommandBlock({
const isDigitIndex = isDigitIndexActionId(item.id)
const canEnable = isDisabled && previousBindings.length > 0
const doubleTapHint = platform === 'darwin' ? '⇧⇧' : 'Shift Shift'
const doubleTapHint = platform === 'darwin' ? '⇧⇧' : '⇧ ⇧'
const recordingMessage = translate(
'auto.components.settings.ShortcutCommandBlock.eb72c52c28',
'Press a shortcut, or double-tap a modifier (e.g. {{value0}}). Esc cancels.',
@@ -208,7 +208,7 @@ describe('TerminalContextMenu', () => {
it('uses nominal primary toggle labels, including default and unbound', () => {
for (const [bindings, label] of [
[undefined, 'Ctrl+Shift+J'],
[undefined, 'Ctrl+⇧+J'],
[['Mod+Alt+Y', 'Mod+Alt+K'], 'Ctrl+Alt+Y'],
[[], null]
] as const) {
@@ -236,11 +236,11 @@ describe('TerminalContextMenu', () => {
renderMenu({ keybindings })
expect(shortcuts.list).toContain('Ctrl+Shift+C')
expect(shortcuts.list).toContain('Ctrl+Shift+A')
expect(shortcuts.list).toContain('Ctrl+⇧+C')
expect(shortcuts.list).toContain('Ctrl+⇧+A')
expect(shortcuts.list).toContain('Ctrl+V')
expect(shortcuts.list).toContain('Ctrl+Shift+D')
expect(shortcuts.list).toContain('Alt+Shift+D')
expect(shortcuts.list).toContain('Ctrl+⇧+D')
expect(shortcuts.list).toContain('Alt+⇧+D')
expect(shortcuts.list.some((shortcut) => shortcut.includes(','))).toBe(false)
})
@@ -111,7 +111,7 @@ describe('shortcut label memoization', () => {
const overrides = overridesFor('Mod+Shift+K')
expect(formatShortcutLabel('tab.close', overrides)).toBe('⌘⇧K')
platformRef.current = 'win32'
expect(formatShortcutLabel('tab.close', overrides)).toBe('Ctrl+Shift+K')
expect(formatShortcutLabel('tab.close', overrides)).toBe('Ctrl+⇧+K')
platformRef.current = 'darwin'
expect(formatShortcutLabel('tab.close', overrides)).toBe('⌘⇧K')
})
@@ -53,7 +53,7 @@ describe('keybindings', () => {
'Mod+Shift+A'
])
expect(formatKeybindingList(['Mod+Shift+A'], 'darwin')).toBe('⌘⇧A')
expect(formatKeybindingList(['Mod+Shift+A'], 'linux')).toBe('Ctrl+Shift+A')
expect(formatKeybindingList(['Mod+Shift+A'], 'linux')).toBe('Ctrl+⇧+A')
const macChord = {
key: 'a',
+2 -2
View File
@@ -111,7 +111,7 @@ describe('keybindings', () => {
it('formats double-tap bindings as the modifier glyph twice', () => {
expect(formatKeybinding('DoubleTap+Shift', 'darwin')).toEqual(['⇧', '⇧'])
expect(formatKeybinding('DoubleTap+Shift', 'linux')).toEqual(['Shift', 'Shift'])
expect(formatKeybinding('DoubleTap+Shift', 'linux')).toEqual(['⇧', '⇧'])
expect(formatKeybinding('DoubleTap+Mod', 'darwin')).toEqual(['⌘', '⌘'])
expect(formatKeybinding('DoubleTap+Mod', 'win32')).toEqual(['Ctrl', 'Ctrl'])
expect(formatKeybinding('DoubleTap+Cmd', 'win32')).toEqual(['Cmd', 'Cmd'])
@@ -119,7 +119,7 @@ describe('keybindings', () => {
// Ctrl's glyph ⌃ diverges from Mod's ⌘ on Mac, so cover it explicitly.
expect(formatKeybinding('DoubleTap+Ctrl', 'darwin')).toEqual(['⌃', '⌃'])
expect(formatKeybindingList(['DoubleTap+Shift'], 'darwin')).toBe('⇧ ⇧')
expect(formatKeybindingList(['DoubleTap+Shift'], 'linux')).toBe('Shift Shift')
expect(formatKeybindingList(['DoubleTap+Shift'], 'linux')).toBe('⇧ ⇧')
})
it('reports conflicts across two double-tap bindings', () => {
+2 -2
View File
@@ -169,9 +169,9 @@ describe('keybindings', () => {
it('formats keybindings with platform labels', () => {
expect(formatKeybindingList(['Mod+Shift+J'], 'darwin')).toBe('⌘⇧J')
expect(formatKeybindingList(['Mod+Shift+J'], 'linux')).toBe('Ctrl+Shift+J')
expect(formatKeybindingList(['Mod+Shift+J'], 'linux')).toBe('Ctrl+⇧+J')
expect(formatKeybindingList(['Mod+Shift+Backspace'], 'darwin')).toBe('⌘⇧⌫')
expect(formatKeybindingList(['Mod+Shift+Backspace'], 'linux')).toBe('Ctrl+Shift+Backspace')
expect(formatKeybindingList(['Mod+Shift+Backspace'], 'linux')).toBe('Ctrl+⇧+Backspace')
expect(formatKeybindingList([], 'win32')).toBe('Unassigned')
})
+2 -2
View File
@@ -32,7 +32,7 @@ function formatModifierGlyph(modifier: ModifierToken, isMac: boolean): string {
case 'Alt':
return isMac ? '⌥' : 'Alt'
case 'Shift':
return isMac ? '⇧' : 'Shift'
return '⇧'
}
}
@@ -60,7 +60,7 @@ export function formatKeybinding(binding: string, platform: NodeJS.Platform): st
parts.push(isMac ? '⌥' : 'Alt')
}
if (parsed.shift) {
parts.push(isMac ? '⇧' : 'Shift')
parts.push('⇧')
}
parts.push(formatKeyToken(parsed.key, isMac))
return parts