mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-22 20:05:23 +00:00
fix: stop random hotkeys from snapping desktop zoom to 1
The main process was resetting webContents zoom to 1 on every \zoom-changed\ event, which fires not just for native Chromium zoom gestures but also for the renderer's own setZoomFactor IPC calls. Paired with a keydown listener that re-sent the current zoom on every ctrl-combination (ctrl+backspace, ctrl+z, ctrl+v, ...), this created a self-triggered race that intermittently snapped the factor back to 1. Make the renderer the single source of zoom truth: keyboard, wheel, and menu all drive the same Solid signal, preventDefault blocks Chromium's built-in accelerators before they race, and the main process disables pinch zoom and no longer listens to zoom-changed.
This commit is contained in:
@@ -75,9 +75,9 @@ export function createMenu(deps: Deps) {
|
||||
{ role: "reload" },
|
||||
{ role: "toggleDevTools" },
|
||||
{ type: "separator" },
|
||||
{ role: "resetZoom" },
|
||||
{ role: "zoomIn" },
|
||||
{ role: "zoomOut" },
|
||||
{ label: "Actual Size", accelerator: "Cmd+0", click: () => deps.trigger("zoom.reset") },
|
||||
{ label: "Zoom In", accelerator: "Cmd+=", click: () => deps.trigger("zoom.in") },
|
||||
{ label: "Zoom Out", accelerator: "Cmd+-", click: () => deps.trigger("zoom.out") },
|
||||
{ type: "separator" },
|
||||
{ role: "togglefullscreen" },
|
||||
],
|
||||
|
||||
@@ -159,7 +159,9 @@ function injectGlobals(win: BrowserWindow, globals: Globals) {
|
||||
|
||||
function wireZoom(win: BrowserWindow) {
|
||||
win.webContents.setZoomFactor(1)
|
||||
win.webContents.on("zoom-changed", () => {
|
||||
win.webContents.setZoomFactor(1)
|
||||
})
|
||||
// Disable Chromium's touch/pinch zoom. Keyboard and wheel zoom are handled
|
||||
// in the renderer so the Solid `webviewZoom` signal stays the single source
|
||||
// of truth; a stray `zoom-changed` handler here would race with the renderer
|
||||
// and intermittently snap the factor back to 1.
|
||||
void win.webContents.setVisualZoomLevelLimits(1, 1).catch(() => undefined)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import { render } from "solid-js/web"
|
||||
import pkg from "../../package.json"
|
||||
import { initI18n, t } from "./i18n"
|
||||
import { UPDATER_ENABLED } from "./updater"
|
||||
import { webviewZoom } from "./webview-zoom"
|
||||
import { webviewZoom, zoomIn, zoomOut, zoomReset } from "./webview-zoom"
|
||||
import "./styles.css"
|
||||
import { Button } from "@opencode-ai/ui/button"
|
||||
import { Splash } from "@opencode-ai/ui/logo"
|
||||
@@ -265,6 +265,9 @@ const createPlatform = (): Platform => {
|
||||
|
||||
let menuTrigger = null as null | ((id: string) => void)
|
||||
window.api.onMenuCommand((id) => {
|
||||
if (id === "zoom.in") return zoomIn()
|
||||
if (id === "zoom.out") return zoomOut()
|
||||
if (id === "zoom.reset") return zoomReset()
|
||||
menuTrigger?.(id)
|
||||
})
|
||||
listenForDeepLinks()
|
||||
|
||||
@@ -11,28 +11,73 @@ const OS_NAME = (() => {
|
||||
return "unknown"
|
||||
})()
|
||||
|
||||
const MIN_ZOOM = 0.2
|
||||
const MAX_ZOOM = 10
|
||||
const KEY_STEP = 0.2
|
||||
const WHEEL_STEP = 0.1
|
||||
|
||||
const clamp = (value: number) => Math.min(Math.max(value, MIN_ZOOM), MAX_ZOOM)
|
||||
|
||||
const [webviewZoom, setWebviewZoom] = createSignal(1)
|
||||
|
||||
const MAX_ZOOM_LEVEL = 10
|
||||
const MIN_ZOOM_LEVEL = 0.2
|
||||
|
||||
const clamp = (value: number) => Math.min(Math.max(value, MIN_ZOOM_LEVEL), MAX_ZOOM_LEVEL)
|
||||
|
||||
const applyZoom = (next: number) => {
|
||||
setWebviewZoom(next)
|
||||
void window.api.setZoomFactor(next)
|
||||
const apply = (next: number) => {
|
||||
const clamped = clamp(next)
|
||||
if (Math.abs(clamped - webviewZoom()) < 1e-6) return
|
||||
setWebviewZoom(clamped)
|
||||
void window.api.setZoomFactor(clamped).catch(() => undefined)
|
||||
}
|
||||
|
||||
export const zoomIn = () => apply(webviewZoom() + KEY_STEP)
|
||||
export const zoomOut = () => apply(webviewZoom() - KEY_STEP)
|
||||
export const zoomReset = () => apply(1)
|
||||
|
||||
// Seed the signal from the main process so renderer and webContents agree
|
||||
// across cold starts, reloads, and HMR refreshes (which would otherwise
|
||||
// reinitialize the signal to 1 while webContents kept its prior factor).
|
||||
void window.api
|
||||
.getZoomFactor()
|
||||
.then((initial) => {
|
||||
if (typeof initial === "number" && Number.isFinite(initial)) {
|
||||
setWebviewZoom(clamp(initial))
|
||||
}
|
||||
})
|
||||
.catch(() => undefined)
|
||||
|
||||
// Keyboard accelerators. preventDefault stops Chromium's built-in zoom
|
||||
// accelerators from firing in parallel (which previously caused races).
|
||||
window.addEventListener("keydown", (event) => {
|
||||
if (!(OS_NAME === "macos" ? event.metaKey : event.ctrlKey)) return
|
||||
const mod = OS_NAME === "macos" ? event.metaKey : event.ctrlKey
|
||||
if (!mod || event.altKey) return
|
||||
|
||||
let newZoom = webviewZoom()
|
||||
|
||||
if (event.key === "-") newZoom -= 0.2
|
||||
if (event.key === "=" || event.key === "+") newZoom += 0.2
|
||||
if (event.key === "0") newZoom = 1
|
||||
|
||||
applyZoom(clamp(newZoom))
|
||||
if (event.key === "-" || event.key === "_") {
|
||||
event.preventDefault()
|
||||
zoomOut()
|
||||
return
|
||||
}
|
||||
if (event.key === "=" || event.key === "+") {
|
||||
event.preventDefault()
|
||||
zoomIn()
|
||||
return
|
||||
}
|
||||
if (event.key === "0") {
|
||||
event.preventDefault()
|
||||
zoomReset()
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
// Wheel zoom. Chromium synthesizes `wheel` with `ctrlKey: true` for trackpad
|
||||
// pinch on every platform, so checking ctrlKey uniformly covers pinch-to-zoom
|
||||
// as well as real ctrl+scroll / cmd+scroll.
|
||||
window.addEventListener(
|
||||
"wheel",
|
||||
(event) => {
|
||||
if (!event.ctrlKey && !event.metaKey) return
|
||||
event.preventDefault()
|
||||
const step = event.deltaY > 0 ? -WHEEL_STEP : WHEEL_STEP
|
||||
apply(webviewZoom() + step)
|
||||
},
|
||||
{ passive: false },
|
||||
)
|
||||
|
||||
export { webviewZoom }
|
||||
|
||||
Reference in New Issue
Block a user