From dc1345e2a3974a85d7648130da2ac4e5ff636dd1 Mon Sep 17 00:00:00 2001 From: Aditya Garud Date: Fri, 24 Jul 2026 23:49:09 +0530 Subject: [PATCH] Limit physical key fallback to non-Latin layout output Shortcut matching accepted both the layout-derived key and the physical KeyA-KeyZ position for every keypress. On remapped Latin layouts one physical key then triggered shortcuts for two different letters, and a shortcut like mod+D consumed the key a user needs for mod+A. Keep the physical fallback only when the layout produces something other than a Latin letter, which is the case it was added for: non-Latin layouts and Option-modified symbols on macOS. Fixes #4434 --- apps/web/src/keybindings.test.ts | 29 +++++++++++++++++++++++++++++ apps/web/src/keybindings.ts | 10 ++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/apps/web/src/keybindings.test.ts b/apps/web/src/keybindings.test.ts index c0d326edd55..56e39c96d19 100644 --- a/apps/web/src/keybindings.test.ts +++ b/apps/web/src/keybindings.test.ts @@ -637,6 +637,35 @@ describe("resolveShortcutCommand", () => { "rightPanel.toggle", ); }); + + it("matches non-Latin layout letters using the physical key code", () => { + const keybindings = compile([{ shortcut: modShortcut("d"), command: "diff.toggle" }]); + + assert.strictEqual( + resolveShortcutCommand(event({ key: "в", code: "KeyD", metaKey: true }), keybindings, { + platform: "MacIntel", + }), + "diff.toggle", + ); + }); + + it("ignores the physical key code when the layout types a different Latin letter", () => { + const keybindings = compile([{ shortcut: modShortcut("d"), command: "diff.toggle" }]); + + // On a remapped layout the physical D key types "a"; only the physical + // key whose layout output is "d" may trigger the shortcut. + assert.isNull( + resolveShortcutCommand(event({ key: "a", code: "KeyD", metaKey: true }), keybindings, { + platform: "MacIntel", + }), + ); + assert.strictEqual( + resolveShortcutCommand(event({ key: "d", code: "KeyL", metaKey: true }), keybindings, { + platform: "MacIntel", + }), + "diff.toggle", + ); + }); }); describe("formatShortcutLabel", () => { diff --git a/apps/web/src/keybindings.ts b/apps/web/src/keybindings.ts index 9d6109a7780..6ec9a6fab85 100644 --- a/apps/web/src/keybindings.ts +++ b/apps/web/src/keybindings.ts @@ -71,9 +71,15 @@ function normalizeEventKey(key: string): string { } function resolveEventKeys(event: ShortcutEventLike): Set { - const keys = new Set([normalizeEventKey(event.key)]); + const layoutKey = normalizeEventKey(event.key); + const keys = new Set([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. const letterCode = event.code?.match(/^Key([A-Z])$/)?.[1]; - if (letterCode) { + if (letterCode && !/^[a-z]$/.test(layoutKey)) { keys.add(letterCode.toLowerCase()); } const aliases = event.code ? EVENT_CODE_KEY_ALIASES[event.code] : undefined;