diff --git a/packages/app/src/context/command-keybind.test.ts b/packages/app/src/context/command-keybind.test.ts index c8e2dbb5d0..6ca3240164 100644 --- a/packages/app/src/context/command-keybind.test.ts +++ b/packages/app/src/context/command-keybind.test.ts @@ -32,6 +32,14 @@ describe("command keybind helpers", () => { expect(matchKeybind(keybinds, new KeyboardEvent("keydown", { key: ",", ctrlKey: true, altKey: true }))).toBe(false) }) + test("matchKeybind handles control-letter browser key values", () => { + const keybinds = parseKeybind("ctrl+l") + + expect(matchKeybind(keybinds, new KeyboardEvent("keydown", { key: "\f", code: "KeyL", ctrlKey: true }))).toBe( + true, + ) + }) + test("matchKeybind supports bracket keys", () => { const keybinds = parseKeybind("mod+alt+[, mod+alt+]") const prev = keybinds[0] diff --git a/packages/app/src/context/command.tsx b/packages/app/src/context/command.tsx index 467a1115b5..c2cab1f5f1 100644 --- a/packages/app/src/context/command.tsx +++ b/packages/app/src/context/command.tsx @@ -53,8 +53,15 @@ function signature(key: string, ctrl: boolean, meta: boolean, shift: boolean, al return `${key}:${mask}` } +function normalizeEventKey(event: KeyboardEvent) { + if (event.ctrlKey && event.key.length === 1 && event.key.charCodeAt(0) <= 0x1f && event.code.startsWith("Key")) { + return event.code.slice(3).toLowerCase() + } + return normalizeKey(event.key) +} + function signatureFromEvent(event: KeyboardEvent) { - return signature(normalizeKey(event.key), event.ctrlKey, event.metaKey, event.shiftKey, event.altKey) + return signature(normalizeEventKey(event), event.ctrlKey, event.metaKey, event.shiftKey, event.altKey) } function isAllowedEditableKeybind(id: string | undefined) { @@ -158,7 +165,7 @@ export function parseKeybind(config: string): Keybind[] { } export function matchKeybind(keybinds: Keybind[], event: KeyboardEvent): boolean { - const eventKey = normalizeKey(event.key) + const eventKey = normalizeEventKey(event) for (const kb of keybinds) { const keyMatch = kb.key === eventKey diff --git a/packages/app/src/desktop-menu.test.ts b/packages/app/src/desktop-menu.test.ts index c7e36a7cb7..f5dd58ada4 100644 --- a/packages/app/src/desktop-menu.test.ts +++ b/packages/app/src/desktop-menu.test.ts @@ -2,6 +2,19 @@ import { describe, expect, test } from "bun:test" import { DESKTOP_MENU } from "./desktop-menu" describe("desktop menu", () => { + test("focuses the prompt input from the native macOS menu", () => { + const item = DESKTOP_MENU.flatMap((menu) => menu.items ?? []).find( + (item) => item.type === "item" && item.command === "input.focus", + ) + + expect(item).toEqual({ + type: "item", + label: "Focus Input", + command: "input.focus", + accelerator: { macos: "Ctrl+L" }, + }) + }) + test("exports logs through the desktop command registry", () => { const items = DESKTOP_MENU.flatMap((menu) => menu.items ?? []).filter( (item) => item.type === "item" && item.label === "Export Logs...", diff --git a/packages/app/src/desktop-menu.ts b/packages/app/src/desktop-menu.ts index d3902cd2b2..9fe2e7b29c 100644 --- a/packages/app/src/desktop-menu.ts +++ b/packages/app/src/desktop-menu.ts @@ -144,6 +144,7 @@ export const DESKTOP_MENU: DesktopMenu[] = [ { type: "item", label: "Toggle Sidebar", command: "sidebar.toggle" }, { type: "item", label: "Toggle Terminal", command: "terminal.toggle", accelerator: { macos: "Ctrl+`" } }, { type: "item", label: "Toggle File Tree", command: "fileTree.toggle" }, + { type: "item", label: "Focus Input", command: "input.focus", accelerator: { macos: "Ctrl+L" } }, { type: "separator" }, { type: "item", label: "Reload", action: "view.reload", role: "reload" }, { type: "item", label: "Toggle Developer Tools", action: "view.toggleDevTools", role: "toggleDevTools" },