diff --git a/.docs/quick-start.md b/.docs/quick-start.md index 2206d53ee..c83498ae5 100644 --- a/.docs/quick-start.md +++ b/.docs/quick-start.md @@ -4,7 +4,7 @@ # Development (with hot reload) bun run dev -# Desktop development +# Desktop development (works on Windows too) bun run dev:desktop # Desktop development on an isolated port set @@ -17,6 +17,9 @@ bun run start # Build a shareable macOS .dmg (arm64 by default) bun run dist:desktop:dmg +# Build a shareable Windows installer (.exe via NSIS) +bun run dist:desktop:win + # Or from any project directory after publishing: npx t3 ``` diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index 945f1d279..f28d9f147 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -15,6 +15,7 @@ import { NetService } from "@t3tools/shared/Net"; import { RotatingFileSink } from "@t3tools/shared/logging"; import { showDesktopConfirmDialog } from "./confirmDialog"; import { fixPath } from "./fixPath"; +import { isWindowsZoomInShortcut } from "./zoomShortcuts"; import { getAutoUpdateDisabledReason, shouldBroadcastDownloadProgress, @@ -1115,6 +1116,11 @@ function createWindow(): BrowserWindow { }); window.webContents.setWindowOpenHandler(() => ({ action: "deny" })); + window.webContents.on("before-input-event", (event, input) => { + if (!isWindowsZoomInShortcut(input)) return; + event.preventDefault(); + window.webContents.setZoomLevel(window.webContents.getZoomLevel() + 0.5); + }); window.on("page-title-updated", (event) => { event.preventDefault(); window.setTitle(APP_DISPLAY_NAME); diff --git a/apps/desktop/src/zoomShortcuts.test.ts b/apps/desktop/src/zoomShortcuts.test.ts new file mode 100644 index 000000000..9897fadc6 --- /dev/null +++ b/apps/desktop/src/zoomShortcuts.test.ts @@ -0,0 +1,72 @@ +import { describe, expect, it } from "vitest"; + +import { isWindowsZoomInShortcut } from "./zoomShortcuts"; + +describe("isWindowsZoomInShortcut", () => { + it("matches Ctrl++ from the main keyboard on Windows", () => { + expect( + isWindowsZoomInShortcut( + { + type: "keyDown", + control: true, + shift: true, + key: "+", + code: "Equal", + }, + "win32", + ), + ).toBe(true); + expect( + isWindowsZoomInShortcut( + { + type: "keyDown", + control: true, + shift: true, + key: "=", + code: "Equal", + }, + "win32", + ), + ).toBe(true); + }); + + it("matches Ctrl+numpad plus on Windows", () => { + expect( + isWindowsZoomInShortcut( + { + type: "keyDown", + control: true, + key: "+", + code: "NumpadAdd", + }, + "win32", + ), + ).toBe(true); + }); + + it("does not match unrelated shortcuts or other platforms", () => { + expect( + isWindowsZoomInShortcut( + { + type: "keyDown", + control: true, + key: "-", + code: "Minus", + }, + "win32", + ), + ).toBe(false); + expect( + isWindowsZoomInShortcut( + { + type: "keyDown", + control: true, + shift: true, + key: "+", + code: "Equal", + }, + "linux", + ), + ).toBe(false); + }); +}); diff --git a/apps/desktop/src/zoomShortcuts.ts b/apps/desktop/src/zoomShortcuts.ts new file mode 100644 index 000000000..1bffa16b0 --- /dev/null +++ b/apps/desktop/src/zoomShortcuts.ts @@ -0,0 +1,24 @@ +interface ZoomShortcutInput { + alt?: boolean; + code?: string; + control?: boolean; + key?: string; + meta?: boolean; + shift?: boolean; + type?: string; +} + +export function isWindowsZoomInShortcut( + input: ZoomShortcutInput, + platform = process.platform, +): boolean { + if (platform !== "win32") return false; + if (input.type !== "keyDown") return false; + if (!input.control || input.alt || input.meta) return false; + + return ( + input.key === "+" || + input.code === "NumpadAdd" || + (input.shift === true && (input.key === "=" || input.code === "Equal")) + ); +}