Skip to content

fix(cursor): align editable cursor overlay with window-mode recordings#44

Closed
marktolson wants to merge 1 commit into
getopenscreen:mainfrom
marktolson:fix/macos-window-cursor-alignment
Closed

fix(cursor): align editable cursor overlay with window-mode recordings#44
marktolson wants to merge 1 commit into
getopenscreen:mainfrom
marktolson:fix/macos-window-cursor-alignment

Conversation

@marktolson

@marktolson marktolson commented Jun 29, 2026

Copy link
Copy Markdown

Summary

Fixes editable-cursor overlay misalignment when recording a single window on macOS. Previously, during playback the overlay cursor was offset from the real cursor by a significant amount on both X and Y — clicks landed on elements the visible cursor wasn't over.

Root cause

Cursor telemetry was normalized against the whole display's bounds, but a window recording's video only contains the window. The overlay was therefore placed at the cursor's position relative to the full screen instead of relative to the captured window — offset by the window's on-screen origin and scaled by the display/window size ratio.

// before — always the display, even for window capture
const bounds = this.options.getDisplayBounds() ?? screen.getDisplayNearestPoint(cursor).bounds;

Fix

Mirrors the existing Windows cursor sampler, which already reports per-sample window bounds:

  • The macOS cursor helper now accepts the target windowId and, each sample, reads that window's live on-screen frame via CGWindowListCopyWindowInfo (top-left points — the same coordinate space as Electron's screen.getCursorScreenPoint()) and emits it as bounds. Reading it per sample also keeps alignment correct if the window is moved mid-recording.
  • MacNativeCursorRecordingSession normalizes against the emitted window bounds when present, falling back to display bounds otherwise, via a new pure normalizeCursorToBounds helper.
  • The source id is threaded through the factory so the session can detect window capture and pass the windowId to the helper.

Display (full-screen) capture is unchanged — with no windowId the helper emits no bounds and the display fallback is used.

Tests

  • New unit tests for normalizeCursorToBounds, including a regression test showing the same physical point maps correctly to the window vs. the previously-used (misaligned) display-relative coordinates.
  • Full suite: 277 tests passing.

Verification

  • tsc --noEmit clean
  • ✅ Biome clean on changed files
  • vitest — 277 passing (incl. the new regression test)
  • ✅ Both native helpers compile (swiftc, macOS 13 target)
  • Manually verified on macOS: recorded a window with the editable cursor, clicked UI elements, and the overlay cursor now lands exactly on the clicked elements during playback.

Notes

  • Touches the macOS native cursor helper (OpenScreenMacOSCursorHelper), so a npm run build:native:mac is needed to ship the updated helper.

Summary by CodeRabbit

  • New Features

    • Improved cursor capture for window-based recording on macOS, so cursor positions now align more accurately with the selected window.
    • Added support for passing window-specific bounds through cursor sampling.
  • Bug Fixes

    • Fixed cursor normalization to use the window frame instead of the full display during window capture.
    • Added regression coverage for cursor positioning and out-of-bounds handling.

When recording a single window on macOS, the editable cursor overlay was
offset from the real cursor by a significant amount on both axes, so clicks
in playback landed on elements the visible cursor wasn't over.

Root cause: cursor telemetry was normalized against the whole display's
bounds, but a window recording's video only contains the window. The
overlay was therefore placed at the cursor's position relative to the full
screen instead of relative to the captured window, offset by the window's
on-screen origin (and scaled by the display/window size ratio).

Fix (mirrors the existing Windows cursor sampler, which already reports
per-sample window bounds):
- The macOS cursor helper now accepts the target windowId and, each sample,
  reads that window's live on-screen frame via CGWindowListCopyWindowInfo
  (top-left points, same space as Electron's getCursorScreenPoint) and emits
  it as `bounds`. Reading it per sample also keeps alignment correct if the
  window is moved mid-recording.
- MacNativeCursorRecordingSession normalizes against the emitted window
  bounds when present, falling back to the display bounds otherwise, via a
  new pure `normalizeCursorToBounds` helper.
- The source id is threaded through the factory so the session can detect
  window capture and pass the windowId to the helper.

Adds unit tests for normalizeCursorToBounds, including a regression test
showing the same physical point maps correctly to the window vs. the
(previously used, misaligned) display-relative coordinates.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: df06154b-290c-4093-b983-9c163fa3c430

📥 Commits

Reviewing files that changed from the base of the PR and between f6b81e7 and 7bf9d0a.

📒 Files selected for processing (4)
  • electron/native-bridge/cursor/recording/factory.ts
  • electron/native-bridge/cursor/recording/macNativeCursorRecordingSession.test.ts
  • electron/native-bridge/cursor/recording/macNativeCursorRecordingSession.ts
  • electron/native/screencapturekit/Sources/OpenScreenMacOSCursorHelper/main.swift

📝 Walkthrough

Walkthrough

Adds window-scoped cursor normalization for macOS window capture. The Swift cursor helper gains a windowId field and emits per-sample window bounds via CGWindowListCopyWindowInfo. The TypeScript session propagates sourceIdwindowId to the helper, receives bounds in sample events, and a new exported normalizeCursorToBounds function replaces inline normalization using those window bounds.

Changes

Window-aware macOS cursor normalization

Layer / File(s) Summary
Swift helper: windowId and bounds emission
electron/native/screencapturekit/Sources/OpenScreenMacOSCursorHelper/main.swift
CursorHelperRequest gains windowId?: UInt32; new windowBounds(for:) queries CGWindowListCopyWindowInfo; each "sample" event now includes an optional bounds payload; default request init updated.
TypeScript types and normalizeCursorToBounds
electron/native-bridge/cursor/recording/macNativeCursorRecordingSession.ts
MacCursorBounds type added; MacNativeCursorRecordingSessionOptions extended with sourceId; MacCursorEvent sample variant gains optional bounds; new exported normalizeCursorToBounds function computes normalized coords and isOutsideBounds.
Session wiring and factory
electron/native-bridge/cursor/recording/macNativeCursorRecordingSession.ts, electron/native-bridge/cursor/recording/factory.ts
start() parses windowId from sourceId and forwards it to the helper; handleEvent passes payload.bounds to captureSample; captureSample selects bounds via windowBounds ?? getDisplayBounds() ?? nearestDisplay; factory passes sourceId to macOS session.
Unit tests
electron/native-bridge/cursor/recording/macNativeCursorRecordingSession.test.ts
Tests normalizeCursorToBounds across bounds-normalization, origin-offset, outside-bounds, and window-frame-vs-display regression scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • getopenscreen/openscreen#22: Directly related — both address the macOS window capture cursor offset problem by propagating window bounds into cursor coordinate normalization.

Suggested reviewers

  • EtienneLescot

🐰 A window's frame, a cursor's place,
Swift queries bounds with CGWindowSpace,
TypeScript normalizes, [0,1] range,
No more offsets feeling strange!
The rabbit hops precisely now. 🎯

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main fix: aligning the editable cursor overlay for macOS window-mode recordings.
Description check ✅ Passed The description thoroughly covers the bug, root cause, fix, and testing, though it does not fully match the repository template sections.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@EtienneLescot

Copy link
Copy Markdown
Collaborator

this issue is already fixed on main.

Commit 3ef2001 (June 23, by giulio333): fix(macos): correct cursor offset in single-window capture addresses the same root cause — cursor normalized against display bounds instead of window bounds during single-window macOS recording.

PR #44 (June 29, by marktolson) is a duplicate fix for the same problem. The commit is already in main and on your current branch. The approach differs slightly (PR #44 modifies the cursor helper and factory; 3ef2001 modifies the ScreenCaptureKit helper + IPC handlers + nativeMacRecording.ts), but they address the identical bug.

closed as a duplicate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants