diff --git a/src/shared/keybindings-conflicts.test.ts b/src/shared/keybindings-conflicts.test.ts index b8c4ffba541..55192024590 100644 --- a/src/shared/keybindings-conflicts.test.ts +++ b/src/shared/keybindings-conflicts.test.ts @@ -92,6 +92,8 @@ describe('keybindings', () => { }) ).toContain('view.tasks') expect(findKeybindingActionsForBinding('Mod+F', 'darwin')).not.toContain('editor.find') + // A German '+' key types Mod+Plus without Shift, the same chord as zoom.in's Mod+Shift+Plus. + expect(findKeybindingActionsForBinding('Mod+Plus', 'linux')).toContain('zoom.in') }) it('reports quick-command menu conflicts with global shortcuts and digit ranges', () => { diff --git a/src/shared/keybindings-keyboard-layout.test.ts b/src/shared/keybindings-keyboard-layout.test.ts index 282c59cbb67..f9ff5865935 100644 --- a/src/shared/keybindings-keyboard-layout.test.ts +++ b/src/shared/keybindings-keyboard-layout.test.ts @@ -22,6 +22,31 @@ describe('keybindings', () => { ).toBe(true) }) + it('zooms in on the plus key whether or not the layout needs Shift for it', () => { + const plusKey = { meta: false, control: true, alt: false } + // German/Swiss put '+' on BracketRight and Nordic layouts on Minus, both unshifted. + for (const platform of ['darwin', 'win32', 'linux'] as const) { + const mod = platform === 'darwin' ? { meta: true, control: false } : {} + for (const input of [ + { key: '+', code: 'BracketRight', shift: false }, + { key: '+', code: 'Minus', shift: false }, + { key: '+', code: 'Equal', shift: true } + ]) { + expect(keybindingMatchesAction('zoom.in', { ...plusKey, ...mod, ...input }, platform)).toBe( + true + ) + } + // Shift on the German '+' key types '*', which must not zoom. + expect( + keybindingMatchesAction( + 'zoom.in', + { ...plusKey, ...mod, key: '*', code: 'BracketRight', shift: true }, + platform + ) + ).toBe(false) + } + }) + it('matches file explorer undo and redo by produced logical key', () => { expect(getEffectiveKeybindingsForAction('fileExplorer.undo', 'darwin')).toEqual(['Mod+Z']) expect(getEffectiveKeybindingsForAction('fileExplorer.redo', 'darwin')).toEqual(['Mod+Shift+Z']) diff --git a/src/shared/keybindings/matching-key.ts b/src/shared/keybindings/matching-key.ts index 919b0214418..da63c58ccf7 100644 --- a/src/shared/keybindings/matching-key.ts +++ b/src/shared/keybindings/matching-key.ts @@ -23,6 +23,13 @@ export function platformModifiers( } } +// Why: '+' and '_' need Shift on US keyboards but not on others (German '+', AZERTY '_'), so Shift is how the layout spells them. +const SHIFT_AGNOSTIC_KEY_TOKENS = new Set(['Plus', 'Underscore']) + +export function isShiftAgnosticKeyToken(key: string): boolean { + return SHIFT_AGNOSTIC_KEY_TOKENS.has(key) +} + export function modifierStateMatches( parsed: ParsedKeybinding, input: KeybindingInput, @@ -33,7 +40,7 @@ export function modifierStateMatches( hasModifier(input, 'meta') === expected.meta && hasModifier(input, 'control') === expected.control && hasModifier(input, 'alt') === expected.alt && - hasModifier(input, 'shift') === expected.shift + (isShiftAgnosticKeyToken(parsed.key) || hasModifier(input, 'shift') === expected.shift) ) } diff --git a/src/shared/keybindings/matching.ts b/src/shared/keybindings/matching.ts index 1a3cd5f26aa..6f6a70278b2 100644 --- a/src/shared/keybindings/matching.ts +++ b/src/shared/keybindings/matching.ts @@ -12,6 +12,7 @@ import { modifierStateMatches, keyMatches, digitKeyMatches, + isShiftAgnosticKeyToken, resolveModifierToken } from './matching-key' import { @@ -57,7 +58,7 @@ export function keybindingConflictIdentityForParsed( modifiers.meta ? 'Meta' : '', modifiers.control ? 'Control' : '', modifiers.alt ? 'Alt' : '', - modifiers.shift ? 'Shift' : '', + modifiers.shift && !isShiftAgnosticKeyToken(parsed.key) ? 'Shift' : '', parsed.key ].join('+') }