diff --git a/electron/native-bridge/cursor/recording/windowsNativeRecordingSession.ts b/electron/native-bridge/cursor/recording/windowsNativeRecordingSession.ts index c7a057fea..d2d2f0cc8 100644 --- a/electron/native-bridge/cursor/recording/windowsNativeRecordingSession.ts +++ b/electron/native-bridge/cursor/recording/windowsNativeRecordingSession.ts @@ -186,7 +186,10 @@ export class WindowsNativeRecordingSession implements CursorRecordingSession { } if (payload.asset?.id && !this.assets.has(payload.asset.id)) { - const assetDisplay = screen.getDisplayNearestPoint({ x: payload.x, y: payload.y }); + // payload.x/y are physical screen pixels; `screen` works in DIPs. + const assetDisplay = screen.getDisplayNearestPoint( + screen.screenToDipPoint({ x: payload.x, y: payload.y }), + ); this.assets.set(payload.asset.id, { id: payload.asset.id, platform: "win32", diff --git a/electron/native/wgc-capture/src/cursor-sampler.cpp b/electron/native/wgc-capture/src/cursor-sampler.cpp index 21558c79a..fc68ebf28 100644 --- a/electron/native/wgc-capture/src/cursor-sampler.cpp +++ b/electron/native/wgc-capture/src/cursor-sampler.cpp @@ -410,6 +410,14 @@ static void runSamplingLoop(int intervalMs, HWND targetWindow, const CLSID& pngC // main // ───────────────────────────────────────────────────────────────────────────── int main(int argc, char* argv[]) { + // Without this the process is DPI-unaware and Win32 virtualises every + // coordinate it hands back — GetCursorInfo().ptScreenPos and GetWindowRect + // come out divided by the primary display's scale factor — while the WGC + // capture and the consumer both work in physical pixels. On any scaled + // display the cursor then lands short of its real position, by more the + // further it is from the origin (getopenscreen/openscreen#272). + SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + if (argc < 2) { std::cerr << "Usage: cursor-sampler [windowHandle]" << std::endl; return 1;