From edae410733eba60d5f89b62e27ce3d8ffdd7be55 Mon Sep 17 00:00:00 2001 From: 07akioni <07akioni2@gmail.com> Date: Mon, 21 Sep 2026 20:06:43 +0800 Subject: [PATCH] feat(desktop): support Command Option I for macOS DevTools --- apps/desktop/README.i18n.yaml | 4 ++-- apps/desktop/README.md | 2 +- apps/desktop/README.zh.md | 2 +- apps/desktop/src/main.ts | 5 ++++- apps/desktop/tests/main-startup.spec.ts | 23 +++++++++++++++++++++++ 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/apps/desktop/README.i18n.yaml b/apps/desktop/README.i18n.yaml index c79f25014d..0493921094 100644 --- a/apps/desktop/README.i18n.yaml +++ b/apps/desktop/README.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write apps/desktop/README.md -README.md: 3defe5c4391ec802de5c20675fbb99a597768728 -README.zh.md: e84dbba6a9c9df2c6695313e077fb2aac55c9cb5 +README.md: 983a3841afadebbb7fb3ae335dd9d5f8fa4472ad +README.zh.md: 67668f5ba310679b66c4e351c680b5238303ebd1 diff --git a/apps/desktop/README.md b/apps/desktop/README.md index 3defe5c439..983a3841af 100644 --- a/apps/desktop/README.md +++ b/apps/desktop/README.md @@ -89,7 +89,7 @@ Recovery waits for Host shutdown before changing plugin activation. The native r pnpm run dev:desktop ``` -Press F12 in the main desktop window to open detached Renderer DevTools, including in packaged builds. On keyboards with media keys, use Fn+F12. Development Harness state defaults to `apps/desktop/.desktop-build/development/home`, the disposable npm project lives at `apps/desktop/.desktop-build/development/project`, and Electron browser data lives at `apps/desktop/.desktop-build/development/electron-user-data`. Sessions, settings, credentials, package links, and browser data therefore stay out of the user's normal Harness home. An explicit `DSH_HOME` replaces only the development Harness home. Renderer DevTools opens automatically; Main, Renderer, and dsh Host debugging listen on ports 9229, 9222, and 9230. `DSH_DESKTOP_MAIN_INSPECT_PORT`, `DSH_DESKTOP_RENDERER_DEBUG_PORT`, and `DSH_DESKTOP_HOST_INSPECT_PORT` replace those ports, while `DSH_DESKTOP_OPEN_DEVTOOLS=0` keeps the detached Renderer tools closed. +Press F12 in the main desktop window to open detached Renderer DevTools, including in packaged builds. On keyboards with media keys, use Fn+F12. macOS also supports Command+Option+I. Development Harness state defaults to `apps/desktop/.desktop-build/development/home`, the disposable npm project lives at `apps/desktop/.desktop-build/development/project`, and Electron browser data lives at `apps/desktop/.desktop-build/development/electron-user-data`. Sessions, settings, credentials, package links, and browser data therefore stay out of the user's normal Harness home. An explicit `DSH_HOME` replaces only the development Harness home. Renderer DevTools opens automatically; Main, Renderer, and dsh Host debugging listen on ports 9229, 9222, and 9230. `DSH_DESKTOP_MAIN_INSPECT_PORT`, `DSH_DESKTOP_RENDERER_DEBUG_PORT`, and `DSH_DESKTOP_HOST_INSPECT_PORT` replace those ports, while `DSH_DESKTOP_OPEN_DEVTOOLS=0` keeps the detached Renderer tools closed. After an explicit build, `start:desktop` reconstructs the disposable project and launches the existing artifacts without building again: diff --git a/apps/desktop/README.zh.md b/apps/desktop/README.zh.md index e84dbba6a9..67668f5ba3 100644 --- a/apps/desktop/README.zh.md +++ b/apps/desktop/README.zh.md @@ -89,7 +89,7 @@ macOS 上自定义应用菜单还会声明标准的 File、Window 和应用菜 pnpm run dev:desktop ``` -在桌面主窗口按 F12 可打开独立的 Renderer DevTools,打包版本同样支持。使用多媒体功能键的键盘需按 Fn+F12。开发 Harness 状态默认写入 `apps/desktop/.desktop-build/development/home`,一次性 npm 项目位于 `apps/desktop/.desktop-build/development/project`,Electron 浏览器数据则位于 `apps/desktop/.desktop-build/development/electron-user-data`。因此,会话、设置、凭据、包链接和浏览器数据都不会进入用户正常使用的 Harness home;显式 `DSH_HOME` 只会替换开发 Harness home。Renderer DevTools 默认自动打开,Main、Renderer 和 dsh Host 调试端口依次为 9229、9222 和 9230。`DSH_DESKTOP_MAIN_INSPECT_PORT`、`DSH_DESKTOP_RENDERER_DEBUG_PORT` 与 `DSH_DESKTOP_HOST_INSPECT_PORT` 可以替换这些端口,`DSH_DESKTOP_OPEN_DEVTOOLS=0` 则保持 Renderer 调试窗口关闭。 +在桌面主窗口按 F12 可打开独立的 Renderer DevTools,打包版本同样支持。使用多媒体功能键的键盘需按 Fn+F12。macOS 也支持 Command+Option+I。开发 Harness 状态默认写入 `apps/desktop/.desktop-build/development/home`,一次性 npm 项目位于 `apps/desktop/.desktop-build/development/project`,Electron 浏览器数据则位于 `apps/desktop/.desktop-build/development/electron-user-data`。因此,会话、设置、凭据、包链接和浏览器数据都不会进入用户正常使用的 Harness home;显式 `DSH_HOME` 只会替换开发 Harness home。Renderer DevTools 默认自动打开,Main、Renderer 和 dsh Host 调试端口依次为 9229、9222 和 9230。`DSH_DESKTOP_MAIN_INSPECT_PORT`、`DSH_DESKTOP_RENDERER_DEBUG_PORT` 与 `DSH_DESKTOP_HOST_INSPECT_PORT` 可以替换这些端口,`DSH_DESKTOP_OPEN_DEVTOOLS=0` 则保持 Renderer 调试窗口关闭。 显式构建完成后,`start:desktop` 会重新生成一次性项目,并跳过构建直接启动已有产物: diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index 29619e85ae..2f1f519379 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -155,7 +155,10 @@ function createWindow(preload: string, show = false, primary = false): BrowserWi }) if (primary) { window.webContents.on('before-input-event', (event, input) => { - if (input.type !== 'keyDown' || input.key !== 'F12' || input.isAutoRepeat) return + if (input.type !== 'keyDown' || input.isAutoRepeat) return + const macShortcut = process.platform === 'darwin' && input.code === 'KeyI' + && input.meta && input.alt && !input.control && !input.shift + if (input.key !== 'F12' && !macShortcut) return event.preventDefault() window.webContents.openDevTools({ mode: 'detach' }) }) diff --git a/apps/desktop/tests/main-startup.spec.ts b/apps/desktop/tests/main-startup.spec.ts index 6b562283a6..de4d4405ea 100644 --- a/apps/desktop/tests/main-startup.spec.ts +++ b/apps/desktop/tests/main-startup.spec.ts @@ -386,6 +386,29 @@ describe('desktop main startup', () => { expect(contents.openDevTools).toHaveBeenCalledExactlyOnceWith({ mode: 'detach' }) }) + it.each(['darwin', 'win32'])('handles Command+Option+I only on macOS (platform=%s)', async (platform) => { + vi.stubGlobal('process', { ...process, platform }) + await readyForUpdate() + const contents = harness.windows[0]!.webContents + const event = { preventDefault: vi.fn() } + const input = { type: 'keyDown', key: 'ˆ', code: 'KeyI', meta: true, alt: true, + control: false, shift: false, isAutoRepeat: false } + for (const change of [ + { type: 'keyUp' }, { isAutoRepeat: true }, { code: 'KeyJ' }, + { meta: false }, { alt: false }, { control: true }, { shift: true }, + ]) contents.emit('before-input-event', event, { ...input, ...change }) + expect(contents.openDevTools).not.toHaveBeenCalled() + expect(event.preventDefault).not.toHaveBeenCalled() + contents.emit('before-input-event', event, input) + if (platform === 'darwin') { + expect(contents.openDevTools).toHaveBeenCalledExactlyOnceWith({ mode: 'detach' }) + expect(event.preventDefault).toHaveBeenCalledOnce() + } else { + expect(contents.openDevTools).not.toHaveBeenCalled() + expect(event.preventDefault).not.toHaveBeenCalled() + } + }) + it.each([ ['darwin', true, 'en-US'], ['darwin', false, 'zh-CN'],