Skip to content

Commit

Permalink
fix: add pointer props to touch end events
Browse files Browse the repository at this point in the history
  • Loading branch information
jrandolf-2 committed Feb 21, 2024
1 parent 1f33d5f commit 12aebd4
Show file tree
Hide file tree
Showing 5 changed files with 895 additions and 84 deletions.
194 changes: 111 additions & 83 deletions src/bidiMapper/domains/input/ActionDispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,15 +223,23 @@ export class ActionDispatcher {
return;
}
source.pressed.add(button);
const {x, y, subtype: pointerType} = source;
const {width, height, pressure, twist, tangentialPressure} = action;
const {tiltX, tiltY} = getTilt(action);

// --- Platform-specific code begins here ---
source.updateProperties(action);

const {modifiers} = keyState;
switch (pointerType) {
switch (source.subtype) {
case Input.PointerType.Mouse:
case Input.PointerType.Pen:
case Input.PointerType.Pen: {
const {
x,
y,
subtype: pointerType,
tangentialPressure,
twist,
pressure,
} = source;
const {tiltX, tiltY} = getTilt(source);
// TODO: Implement width and height when available.
return this.#context.cdpTarget.cdpClient.sendCommand(
'Input.dispatchMouseEvent',
Expand All @@ -254,27 +262,31 @@ export class ActionDispatcher {
force: pressure,
}
);
case Input.PointerType.Touch:
}
case Input.PointerType.Touch: {
return this.#context.cdpTarget.cdpClient.sendCommand(
'Input.dispatchTouchEvent',
{
type: 'touchStart',
touchPoints: [
{
x,
y,
...getRadii(width ?? 1, height ?? 1),
tangentialPressure,
tiltX,
tiltY,
twist,
force: pressure,
id: source.pointerId,
},
],
touchPoints: this.#inputState
.getPressedTouchPointerSources()
.map((source) => {
// TODO: Implement rotationAngle when available.
return {
x: source.x,
y: source.y,
...getRadii(source),
tangentialPressure: source.tangentialPressure,
...getTilt(source),
twist: source.twist,
force: source.pressure,
id: source.pointerId,
};
}),
modifiers,
}
);
}
}
// --- Platform-specific code ends here ---
}
Expand All @@ -292,6 +304,10 @@ export class ActionDispatcher {
const {x, y, subtype: pointerType} = source;

// --- Platform-specific code begins here ---
if (source.pressed.size === 0) {
source.resetProperties();
}

const {modifiers} = keyState;
switch (pointerType) {
case Input.PointerType.Mouse:
Expand All @@ -315,13 +331,21 @@ export class ActionDispatcher {
'Input.dispatchTouchEvent',
{
type: 'touchEnd',
touchPoints: [
{
x,
y,
id: source.pointerId,
},
],
touchPoints: this.#inputState
.getPressedTouchPointerSources()
.map((source) => {
// TODO: Implement rotationAngle when available.
return {
x: source.x,
y: source.y,
...getRadii(source),
tangentialPressure: source.tangentialPressure,
...getTilt(source),
twist: source.twist,
force: source.pressure,
id: source.pointerId,
};
}),
modifiers,
}
);
Expand All @@ -335,18 +359,17 @@ export class ActionDispatcher {
action: Readonly<Input.PointerMoveAction>
): Promise<void> {
const {x: startX, y: startY, subtype: pointerType} = source;

// --- Platform-specific code begins here ---
source.updateProperties(action);
// --- Platform-specific code ends here ---

const {
width,
height,
pressure,
twist,
tangentialPressure,
x: offsetX,
y: offsetY,
origin = 'viewport',
duration = this.#tickDuration,
} = action;
const {tiltX, tiltY} = getTilt(action);

const {targetX, targetY} = await this.#getCoordinateFromOrigin(
origin,
Expand Down Expand Up @@ -382,7 +405,8 @@ export class ActionDispatcher {
// --- Platform-specific code begins here ---
const {modifiers} = keyState;
switch (pointerType) {
case Input.PointerType.Mouse:
case Input.PointerType.Mouse: {
const {tangentialPressure, twist, pressure} = source;
// TODO: Implement width and height when available.
await this.#context.cdpTarget.cdpClient.sendCommand(
'Input.dispatchMouseEvent',
Expand All @@ -396,61 +420,65 @@ export class ActionDispatcher {
buttons: source.buttons,
pointerType,
tangentialPressure,
tiltX,
tiltY,
...getTilt(source),
twist,
force: pressure,
}
);
break;
case Input.PointerType.Pen:
if (source.pressed.size !== 0) {
// TODO: Implement width and height when available.
await this.#context.cdpTarget.cdpClient.sendCommand(
'Input.dispatchMouseEvent',
{
type: 'mouseMoved',
x,
y,
modifiers,
clickCount: 0,
button: getCdpButton(
source.pressed.values().next().value ?? 5
),
buttons: source.buttons,
pointerType,
tangentialPressure,
tiltX,
tiltY,
twist,
force: pressure,
}
);
}
case Input.PointerType.Pen: {
if (source.pressed.size === 0) {
break;
}
const {tangentialPressure, twist, pressure} = source;
// TODO: Implement width and height when available.
await this.#context.cdpTarget.cdpClient.sendCommand(
'Input.dispatchMouseEvent',
{
type: 'mouseMoved',
x,
y,
modifiers,
clickCount: 0,
button: getCdpButton(source.pressed.values().next().value ?? 5),
buttons: source.buttons,
pointerType,
tangentialPressure,
...getTilt(source),
twist,
force: pressure,
}
);
break;
}
case Input.PointerType.Touch:
if (source.pressed.size !== 0) {
await this.#context.cdpTarget.cdpClient.sendCommand(
'Input.dispatchTouchEvent',
{
type: 'touchMove',
touchPoints: [
{
x,
y,
...getRadii(width ?? 1, height ?? 1),
tangentialPressure,
tiltX,
tiltY,
twist,
force: pressure,
id: source.pointerId,
},
],
modifiers,
}
);
if (source.pressed.size === 0) {
break;
}
await this.#context.cdpTarget.cdpClient.sendCommand(
'Input.dispatchTouchEvent',
{
type: 'touchMove',
touchPoints: this.#inputState
.getPressedTouchPointerSources()
.map((pressedSource) => {
// TODO: Implement rotationAngle when available.
return {
...(pressedSource === source
? {x, y}
: {x: pressedSource.x, y: pressedSource.y}),
...getRadii(pressedSource),
tangentialPressure: pressedSource.tangentialPressure,
...getTilt(pressedSource),
twist: pressedSource.twist,
force: pressedSource.pressure,
id: pressedSource.pointerId,
};
}),
modifiers,
}
);
break;
}
// --- Platform-specific code ends here ---
Expand Down Expand Up @@ -878,10 +906,10 @@ function getTilt(action: {azimuthAngle?: number; altitudeAngle?: number}): {
};
}

function getRadii(
width: number,
height: number
): {radiusX: number; radiusY: number} {
function getRadii({width, height}: {width: number; height: number}): {
radiusX: number;
radiusY: number;
} {
return {
radiusX: width ? width / 2 : 0.5,
radiusY: height ? height / 2 : 0.5,
Expand Down
53 changes: 52 additions & 1 deletion src/bidiMapper/domains/input/InputSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,32 @@ export class KeySource {
}
}

export class PointerSource {
export interface PointerProperties {
altitudeAngle: number;
azimuthAngle: number;
height: number;
pressure: number;
tangentialPressure: number;
twist: number;
width: number;
}

export class PointerSource implements PointerProperties {
type = SourceType.Pointer as const;
subtype: Input.PointerType;
pointerId: number;
pressed = new Set<number>();
x = 0;
y = 0;

altitudeAngle = Math.PI / 2;
azimuthAngle = 0;
height = 1;
pressure = 0.5;
tangentialPressure = 0;
twist = 0;
width = 1;

constructor(id: number, subtype: Input.PointerType) {
this.pointerId = id;
this.subtype = subtype;
Expand Down Expand Up @@ -111,6 +129,39 @@ export class PointerSource {
}

// --- Platform-specific code starts here ---
updateProperties(properties: Partial<PointerProperties>) {
if (properties.altitudeAngle !== undefined) {
this.altitudeAngle = properties.altitudeAngle;
}
if (properties.azimuthAngle !== undefined) {
this.azimuthAngle = properties.azimuthAngle;
}
if (properties.height !== undefined) {
this.height = properties.height;
}
if (properties.pressure !== undefined) {
this.pressure = properties.pressure;
}
if (properties.tangentialPressure !== undefined) {
this.tangentialPressure = properties.tangentialPressure;
}
if (properties.twist !== undefined) {
this.twist = properties.twist;
}
if (properties.width !== undefined) {
this.width = properties.width;
}
}
resetProperties() {
this.altitudeAngle = Math.PI / 2;
this.azimuthAngle = 0;
this.height = 1;
this.pressure = 0.5;
this.tangentialPressure = 0;
this.twist = 0;
this.width = 1;
}

// Input.dispatchMouseEvent doesn't know the concept of double click, so we
// need to create the logic, similar to how it's done for OSes:
// https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:ui/events/event.cc;l=479
Expand Down
12 changes: 12 additions & 0 deletions src/bidiMapper/domains/input/InputState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,18 @@ export class InputState {
return source as InputSourceFor<Type>;
}

getPressedTouchPointerSources(): PointerSource[] {
return [...this.#sources.values()].filter(
(source): source is PointerSource => {
return (
source.type === SourceType.Pointer &&
source.subtype === Input.PointerType.Touch &&
source.pressed.size > 0
);
}
);
}

get(id: string): InputSource {
const source = this.#sources.get(id);
if (!source) {
Expand Down
Loading

0 comments on commit 12aebd4

Please sign in to comment.