Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 46 additions & 14 deletions src/main/input/pointer-profile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { MAX_POINTER_DELTA } from '../../shared/protocol';
import { createPointerMovementProfile } from './pointer-profile';

describe('createPointerMovementProfile', () => {
it('creates sensible deltas for a 1280x720 display at 1.5 scale', () => {
it('creates display-relative deltas for a 1280x720 display at 1.5 scale', () => {
const profile = createPointerMovementProfile({
cursor: { x: 100, y: 100 },
display: {
Expand All @@ -18,17 +18,17 @@ describe('createPointerMovementProfile', () => {
bounds: { x: 0, y: 0, width: 1280, height: 720 },
maxDelta: MAX_POINTER_DELTA,
recommendedDeltas: {
small: 32,
medium: 85,
large: 187
small: 21,
medium: 57,
large: 125
},
capabilities: {
noAckMouseMove: true
}
});
});

it('returns native target deltas on a 1x display', () => {
it('preserves current feel on a 1920x1080 display at 1x scale', () => {
expect(
createPointerMovementProfile({
cursor: { x: 100, y: 100 },
Expand All @@ -38,25 +38,57 @@ describe('createPointerMovementProfile', () => {
}
}).recommendedDeltas
).toEqual({
small: 48,
medium: 128,
large: 280
small: 49,
medium: 130,
large: 281
});
});

it('returns small logical deltas on a 3x display', () => {
it('returns larger clamped deltas on a 4K display at 1x scale', () => {
expect(
createPointerMovementProfile({
cursor: { x: 100, y: 100 },
display: {
bounds: { x: 0, y: 0, width: 1920, height: 960 },
scaleFactor: 3
bounds: { x: 0, y: 0, width: 3840, height: 2160 },
scaleFactor: 1
}
}).recommendedDeltas
).toEqual({
small: 97,
medium: 259,
large: MAX_POINTER_DELTA
});
});

it('uses the short edge for ultrawide displays', () => {
expect(
createPointerMovementProfile({
cursor: { x: 100, y: 100 },
display: {
bounds: { x: 0, y: 0, width: 3440, height: 1440 },
scaleFactor: 1
}
}).recommendedDeltas
).toEqual({
small: 65,
medium: 173,
large: 374
});
});

it('still divides by scale factor on high-DPI displays', () => {
expect(
createPointerMovementProfile({
cursor: { x: 100, y: 100 },
display: {
bounds: { x: 0, y: 0, width: 3840, height: 2160 },
scaleFactor: 2
}
}).recommendedDeltas
).toEqual({
small: 16,
medium: 43,
large: 93
small: 49,
medium: 130,
large: 281
});
});

Expand Down
24 changes: 17 additions & 7 deletions src/main/input/pointer-profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { MAX_POINTER_DELTA, NO_ACK_CONTROL_COMMAND_TYPES, type PointerMovementPr
type Point = { x: number; y: number };
type Bounds = { x: number; y: number; width: number; height: number };

const TARGET_NATIVE_DELTAS = {
small: 48,
medium: 128,
large: 280
const TARGET_DISPLAY_FRACTIONS = {
small: 0.045,
medium: 0.12,
large: 0.26
};

export function createPointerMovementProfile(input: {
Expand All @@ -21,16 +21,17 @@ export function createPointerMovementProfile(input: {
const scaleFactor =
Number.isFinite(input.display.scaleFactor) && input.display.scaleFactor > 0 ? input.display.scaleFactor : 1;
const maxDelta = input.maxDelta ?? MAX_POINTER_DELTA;
const targetNativeDeltas = targetNativeDeltasForDisplay(bounds);

return {
displayId: `${bounds.x}:${bounds.y}:${bounds.width}:${bounds.height}:${scaleFactor}`,
scaleFactor,
bounds,
maxDelta,
recommendedDeltas: {
small: toLogicalDelta(TARGET_NATIVE_DELTAS.small, scaleFactor, maxDelta),
medium: toLogicalDelta(TARGET_NATIVE_DELTAS.medium, scaleFactor, maxDelta),
large: toLogicalDelta(TARGET_NATIVE_DELTAS.large, scaleFactor, maxDelta)
small: toLogicalDelta(targetNativeDeltas.small, scaleFactor, maxDelta),
medium: toLogicalDelta(targetNativeDeltas.medium, scaleFactor, maxDelta),
large: toLogicalDelta(targetNativeDeltas.large, scaleFactor, maxDelta)
},
capabilities: {
noAckMouseMove: true,
Expand All @@ -39,6 +40,15 @@ export function createPointerMovementProfile(input: {
};
}

function targetNativeDeltasForDisplay(bounds: Bounds): { small: number; medium: number; large: number } {
const referenceSize = Math.min(bounds.width, bounds.height);
return {
small: Math.round(referenceSize * TARGET_DISPLAY_FRACTIONS.small),
medium: Math.round(referenceSize * TARGET_DISPLAY_FRACTIONS.medium),
large: Math.round(referenceSize * TARGET_DISPLAY_FRACTIONS.large)
};
}

function normalizeBounds(bounds: Bounds): Bounds {
return {
x: finiteOr(bounds.x, 0),
Expand Down