Skip to content

fix(cursor): make the Windows cursor sampler DPI-aware - #278

Merged
EtienneLescot merged 1 commit into
mainfrom
claude/issue-272-non-reproductible-571189
Aug 5, 2026
Merged

fix(cursor): make the Windows cursor sampler DPI-aware#278
EtienneLescot merged 1 commit into
mainfrom
claude/issue-272-non-reproductible-571189

Conversation

@EtienneLescot

@EtienneLescot EtienneLescot commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Fixes #272.

The bug

The cursor drawn in the editor preview sits short of where it really was, by more the further it is from the top-left of the display. Only on Windows, only on a display (screen) capture, only at a display scaling other than 100%.

Root cause

cursor-sampler.exe ships with no dpiAware manifest and never calls SetProcessDpiAwareness*:

<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
  <trustInfo …><security><requestedPrivileges>
    <requestedExecutionLevel level='asInvoker' uiAccess='false' />
  </requestedPrivileges></security></trustInfo>
</assembly>

So the process is DPI-unaware, and Win32 hands it virtualized coordinates — GetCursorInfo().ptScreenPos and GetWindowRect both come back divided by the primary display's scale factor.

b31bb71f (shipped in v1.7.0, so present in the reported 1.8.0) assumed the opposite — "the cursor-sampler reports raw x/y in physical screen pixels" — and converted the Electron display bounds to physical with dipToScreenRect before normalizing. Numerator and denominator then lived in different spaces:

cx = (x / s) / W_physical        instead of        x / W_physical

The preview cursor lands at 1/s of its true offset from the display origin. At 150% on a 2560px-wide screen that is ~850px short at the right edge. At 100% the two spaces coincide, which is why it was invisible on the dev machines and in the Windows smoke tests.

Window captures were never affected: there the sampler supplies its own GetWindowRect bounds, so both sides were virtualized together and the ratio came out right either way.

The fix

Opt the helper into per-monitor-v2 awareness, rather than walking the normalization back to DIPs. The reported numbers then really are physical — which is what every consumer already assumes — and unlike DIP normalization this also holds on mixed-DPI multi-monitor setups, where virtualization always uses the primary display's scale whatever monitor the cursor is on.

Second hunk: payload.x/y being physical now, the asset's display lookup goes through screenToDipPointscreen.getDisplayNearestPoint works in DIPs and would otherwise pick the wrong monitor.

Verification

GetProcessDpiAwareness
cursor-sampler.exe as shipped in 1.8.0 UNAWARE
rebuilt from this branch PER_MONITOR_AWARE
  • Builds clean (MSVC / Ninja, no new warnings), tsc --noEmit and biome check pass.
  • At 100% scaling the rebuilt sampler reports exactly the same position as before (253,611 == 253,611) — no regression on unscaled displays.
  • End-to-end on a scaled display: the bug reproduces on demand by setting the display to 150% and recording a screen, and is gone on a build from this branch. Confirmed manually — there is no automated coverage for it (see below).

Cross-OS

Platform Status
Windows broken → fixed here
macOS unaffected — the SCK helper reports its capture frame in points (ScreenCaptureRecorder.swift:127), the same space as screen.getCursorScreenPoint()
Linux unaffected — the PipeWire helper normalizes against the stream's own pixel dimensions, which it repeats on every sample, deliberately ignoring Electron's DIP bounds

No test is added: the whole failure lives in a Win32 process attribute, and CI is Linux-only, so a guard here would never run.

Loading
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.

[Bug]: Mouse pointer position is incorrect in the editor preview

1 participant