Skip to content

Commit 5bb1b3f

Browse files
committed
fix: recompute cursor visibility when rebasing on capture bounds
Samples hidden against the seeded window frame stayed hidden after the helper's frame arrived and contained them.
1 parent 14c0b47 commit 5bb1b3f

2 files changed

Lines changed: 34 additions & 2 deletions

File tree

‎electron/native-bridge/cursor/recording/macNativeCursorRecordingSession.test.ts‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,30 @@ describe("MacNativeCursorRecordingSession capture bounds", () => {
187187
});
188188
});
189189

190+
it("brings back samples hidden against the seeded frame once the real bounds arrive", async () => {
191+
// Above the seeded window frame, so three samples cross the hide threshold;
192+
// the helper's frame then starts higher and contains them.
193+
mocks.cursor = { x: 700, y: 60 };
194+
const session = new MacNativeCursorRecordingSession({
195+
getDisplayBounds: () => WINDOW_BOUNDS,
196+
maxSamples: 20,
197+
sampleIntervalMs: 33,
198+
startTimeMs: 1_000,
199+
});
200+
const pending = session.start();
201+
await Promise.resolve();
202+
helper.emitEvent({ type: "ready", timestampMs: 1_000 });
203+
await pending;
204+
helper.emitEvent({ type: "sample", timestampMs: 1_100 });
205+
helper.emitEvent({ type: "sample", timestampMs: 1_133 });
206+
helper.emitEvent({ type: "sample", timestampMs: 1_166 });
207+
208+
session.updateCaptureBounds({ x: 200, y: 50, width: 1000, height: 850 });
209+
210+
const data = await session.stop();
211+
expect(data.samples.slice(0, 3).map((sample) => sample.visible)).toEqual([true, true, true]);
212+
});
213+
190214
it("falls back to the display under the pointer when no capture bounds exist", async () => {
191215
// No helper on disk: position-only sampling, and nothing has reported a capture rect.
192216
mocks.accessSync.mockImplementation(() => {

‎electron/native-bridge/cursor/recording/macNativeCursorRecordingSession.ts‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,13 +338,21 @@ export class MacNativeCursorRecordingSession implements CursorRecordingSession {
338338
this.boundsOverride = bounds;
339339
const width = Math.max(1, bounds.width);
340340
const height = Math.max(1, bounds.height);
341+
// Replay the outside streak too, so samples hidden against the old bounds come back.
342+
this.consecutiveOutsideSamples = 0;
341343
for (let index = 0; index < this.samples.length; index++) {
342344
const point = this.screenPoints[index];
343345
if (!point) {
344346
continue;
345347
}
346-
this.samples[index].cx = clamp((point.x - bounds.x) / width, 0, 1);
347-
this.samples[index].cy = clamp((point.y - bounds.y) / height, 0, 1);
348+
const normalizedX = (point.x - bounds.x) / width;
349+
const normalizedY = (point.y - bounds.y) / height;
350+
const isOutside = normalizedX < 0 || normalizedX > 1 || normalizedY < 0 || normalizedY > 1;
351+
this.consecutiveOutsideSamples = isOutside ? this.consecutiveOutsideSamples + 1 : 0;
352+
this.samples[index].cx = clamp(normalizedX, 0, 1);
353+
this.samples[index].cy = clamp(normalizedY, 0, 1);
354+
this.samples[index].visible =
355+
this.consecutiveOutsideSamples < MacNativeCursorRecordingSession.OUTSIDE_HIDE_THRESHOLD;
348356
}
349357
}
350358

0 commit comments

Comments
 (0)