diff --git a/apps/desktop/src/shared/hotkeys.test.ts b/apps/desktop/src/shared/hotkeys.test.ts index 0a2f1ab405b..7731b283e48 100644 --- a/apps/desktop/src/shared/hotkeys.test.ts +++ b/apps/desktop/src/shared/hotkeys.test.ts @@ -91,4 +91,32 @@ describe("isTerminalReservedEvent", () => { }), ).toBe(true); }); + + // Regression: superset-sh/superset#3365 — ctrl+c/d/z fail under non-Latin IME + // (Turkish, Korean, Russian) because event.key reflects IME-transformed char. + it("detects ctrl+c via event.code when IME mangles event.key (Turkish)", () => { + expect( + isTerminalReservedEvent({ + key: "ç", // Turkish IME emits 'ç' instead of 'c' + code: "KeyC", + ctrlKey: true, + shiftKey: false, + altKey: false, + metaKey: false, + }), + ).toBe(true); + }); + + it("detects ctrl+d via event.code when IME mangles event.key (Korean)", () => { + expect( + isTerminalReservedEvent({ + key: "ㅇ", // Korean 2-Set IME emits Hangul jamo for 'd' + code: "KeyD", + ctrlKey: true, + shiftKey: false, + altKey: false, + metaKey: false, + }), + ).toBe(true); + }); }); diff --git a/apps/desktop/src/shared/hotkeys.ts b/apps/desktop/src/shared/hotkeys.ts index 2a444f4a7b3..d90a69395bc 100644 --- a/apps/desktop/src/shared/hotkeys.ts +++ b/apps/desktop/src/shared/hotkeys.ts @@ -271,6 +271,15 @@ export function matchesHotkeyEvent( // Use event.code to match digit keys when alt is pressed if (/^[1-9]$/.test(key) && eventCode === `digit${key}`) return true; + // IME / non-Latin keyboard layout fallback (e.g. Turkish, Korean, Russian): + // `event.key` reflects the IME-transformed character (e.g. Turkish dead keys + // or Korean 2-Set), while `event.code` always reports the physical key. + // Without this, Ctrl+C, Ctrl+V, Ctrl+D, Ctrl+Z etc. fail to match when a + // non-Latin layout is active. Fixes superset-sh/superset#3365. + if (key.length === 1 && /^[a-z]$/.test(key) && eventCode === `key${key}`) { + return true; + } + return eventKey === key; }