Skip to content

feat(desktop): support Ctrl/Cmd + mouse wheel zoom - #40414

Closed
liuhao1024 wants to merge 2 commits into
NousResearch:mainfrom
liuhao1024:feat/desktop-wheel-zoom
Closed

feat(desktop): support Ctrl/Cmd + mouse wheel zoom#40414
liuhao1024 wants to merge 2 commits into
NousResearch:mainfrom
liuhao1024:feat/desktop-wheel-zoom

Conversation

@liuhao1024

Copy link
Copy Markdown
Contributor

Summary

Adds the standard desktop/browser zoom gesture: Ctrl (Windows/Linux) or Cmd (macOS) + mouse wheel up/down to zoom in/out.

This is the most common zoom gesture in desktop applications and browsers. Hermes Desktop already supports keyboard shortcuts (Ctrl/Cmd + +/-/0) and View menu zoom actions, but this gesture was missing.

Implementation

  • Main process (main.cjs): installWheelZoom() injects a lightweight wheel event listener into the renderer via executeJavaScript on dom-ready and did-finish-load
  • Renderer listener: detects Ctrl/Cmd + wheel, calls e.preventDefault() to block page scroll, sends a zoom delta over IPC (hermes:zoom:adjust)
  • IPC handler: clamps zoom level to [-9, 9] with 0.1 step — matching the existing keyboard zoom step from installZoomShortcuts
  • Preload (preload.cjs): exposes zoomAdjust(delta) via ipcRenderer.send
  • Types (global.d.ts): adds zoomAdjust?: (delta: number) => void to the hermesDesktop interface

Behavior

Gesture Action
Ctrl/Cmd + wheel up Zoom in (+0.1)
Ctrl/Cmd + wheel down Zoom out (-0.1)
Ctrl/Cmd + 0 Reset to 100% (existing)

Testing

  1. Open Hermes Desktop
  2. Hold Ctrl (or Cmd on macOS) and scroll the mouse wheel up → text should get larger
  3. Hold Ctrl/Cmd and scroll down → text should get smaller
  4. Press Ctrl/Cmd+0 → zoom resets to 100%
  5. Zoom persists across SPA route changes (re-injected on did-finish-load)

Closes #40295

Add the standard desktop/browser zoom gesture: Ctrl (Windows/Linux) or
Cmd (macOS) + mouse wheel up/down to zoom in/out.

Implementation:
- Inject a lightweight wheel event listener into the renderer via
  executeJavaScript on dom-ready and did-finish-load
- Listener detects Ctrl/Cmd + wheel, prevents default scroll, and sends
  a zoom delta over IPC (hermes:zoom:adjust)
- Main process clamps zoom level to [-9, 9] with 0.1 step (matching the
  existing keyboard zoom step from installZoomShortcuts)

Closes NousResearch#40295
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have labels Jun 6, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the useful desktop ergonomics contribution. The gesture remains worth salvaging, but this implementation needs a current-main port.

Problems

  • apps/desktop/electron/main.cjs and preload.cjs were renamed to TypeScript in 39d09453f; neither CJS path is tracked on current main.
  • The added wc.setZoomLevel(next) bypasses current main's setAndPersistZoomLevel() at apps/desktop/electron/main.ts:4766-4780, which persists zoom and emits hermes:zoom:changed for the settings UI.
  • Current IPC targets the sender's window at apps/desktop/electron/main.ts:7442-7455; preserve that per-window routing because zoom is wired for both primary and secondary chat windows (apps/desktop/electron/main.ts:6972-6981, 7063, 7307).

Suggested changes

  • Port the listener and bridge to main.ts / preload.ts, and route adjustments through the existing sender-derived zoom path and setAndPersistZoomLevel().
  • Add coverage for modifier/direction plus persistence and settings synchronization.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 14, 2026
teknium1 pushed a commit that referenced this pull request Jul 18, 2026
Ground-truth reapply of PR #40414 by @liuhao1024. The original branch
predates the ts-ify migration and implemented the gesture by injecting
a DOM wheel listener via executeJavaScript + a new IPC channel. Current
Electron surfaces the modifier+wheel gesture natively as the main-process
webContents 'zoom-changed' event, so the salvage uses that instead:
no renderer injection, no new preload surface, no new IPC channel.

The handler routes through setAndPersistZoomLevel — the same
persist+notify funnel as the keyboard shortcuts — so wheel zoom uses
the same 0.1 half-step, persists to zoom-state.json across restarts,
and keeps the settings Scale control in sync. Session windows get the
gesture automatically via wireCommonWindowHandlers; the pet overlay
stays opted out via zoomWiringForWindowKind.
@teknium1

Copy link
Copy Markdown
Contributor

Merged via PR #67029 (#67029) — the Ctrl/Cmd + wheel zoom gesture is on main with your authorship preserved via rebase-merge. Thanks for the contribution and the clear writeup!

One implementation note: your branch predated the desktop TypeScript migration, so the change was reapplied under your authorship rather than cherry-picked — and in the process we found Electron now surfaces the modifier+wheel gesture natively as the main-process zoom-changed event. The merged version listens to that instead of injecting a renderer script + IPC channel, and routes through the shared zoom funnel so the gesture picks up persistence (zoom survives restarts) and settings-UI sync for free.

Closing this PR in favor of the merged salvage. Thanks again!

@teknium1 teknium1 closed this Jul 18, 2026
@teknium1 teknium1 added the area/install-update Installer, updater, packaging, wheels, doctor label Jul 19, 2026
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
Ground-truth reapply of PR NousResearch#40414 by @liuhao1024. The original branch
predates the ts-ify migration and implemented the gesture by injecting
a DOM wheel listener via executeJavaScript + a new IPC channel. Current
Electron surfaces the modifier+wheel gesture natively as the main-process
webContents 'zoom-changed' event, so the salvage uses that instead:
no renderer injection, no new preload surface, no new IPC channel.

The handler routes through setAndPersistZoomLevel — the same
persist+notify funnel as the keyboard shortcuts — so wheel zoom uses
the same 0.1 half-step, persists to zoom-state.json across restarts,
and keeps the settings Scale control in sync. Session windows get the
gesture automatically via wireCommonWindowHandlers; the pet overlay
stays opted out via zoomWiringForWindowKind.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/install-update Installer, updater, packaging, wheels, doctor P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Desktop UX]: Support Ctrl/Cmd + mouse wheel zoom

3 participants