Skip to content

Commit

Permalink
fix: タッチ操作後に発生するMouseEventの対応を改善
Browse files Browse the repository at this point in the history
Mobile Safari (iPadOS 16.4)における不要なmousedownとmouseupイベントを確実に抑制する
  • Loading branch information
TK11235 committed Apr 4, 2023
1 parent 4c15699 commit 3ccec24
Showing 1 changed file with 43 additions and 12 deletions.
55 changes: 43 additions & 12 deletions src/app/directive/input-handler.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ResettableTimeout } from '@udonarium/core/system/util/resettable-timeout';
import { PointerCoordinate, PointerData } from 'service/pointer-device.service';

const MOUSE_IDENTIFIER = -9999;
Expand All @@ -18,8 +19,11 @@ export class InputHandler {
private callbackOnTouch = this.onTouch.bind(this);
private callbackOnMenu = this.onMenu.bind(this);

private lastPointers: PointerData[] = [];
private clearLastPointerTimer = new ResettableTimeout(this.clearLastPointer.bind(this), 2000, false);

private firstPointer: PointerData = { x: 0, y: 0, z: 0, identifier: MOUSE_IDENTIFIER }
private lastStartPointers: PointerData[] = [];
private lastMovePointers: PointerData[] = [];
private primaryPointer: PointerData = { x: 0, y: 0, z: 0, identifier: MOUSE_IDENTIFIER }
get startPointer(): PointerCoordinate { return this.firstPointer; }
get pointer(): PointerCoordinate { return this.primaryPointer; }
Expand Down Expand Up @@ -61,13 +65,17 @@ export class InputHandler {

cancel() {
this._isDragging = this._isGrabbing = false;
this.clearLastPointerTimer.reset();
if (!this.option.always) this.removeEventListeners();
}

private onMouse(e: MouseEvent) {
let mosuePointer: PointerData = { x: e.pageX, y: e.pageY, z: 0, identifier: MOUSE_IDENTIFIER };
if (this.isSyntheticEvent(mosuePointer)) return;
this.lastPointers = [mosuePointer];
if (this.isSyntheticEvent(e)) {
this.updateLastPointer(e);
return;
}
this.updateLastPointer(e);
this.primaryPointer = mosuePointer;

this.onPointer(e);
Expand All @@ -76,15 +84,10 @@ export class InputHandler {
private onTouch(e: TouchEvent) {
let length = e.changedTouches.length;
if (length < 1) return;
this.lastPointers = [];
for (let i = 0; i < length; i++) {
let touch = e.changedTouches[i];
let touchPointer: PointerData = { x: touch.pageX, y: touch.pageY, z: 0, identifier: touch.identifier };
this.lastPointers.push(touchPointer);
}
this.updateLastPointer(e);

if (e.type === 'touchstart') {
this.primaryPointer = this.lastPointers[0];
this.primaryPointer = this.lastStartPointers[0];
} else {
let changedTouches = Array.from(e.changedTouches);
let touch = changedTouches.find(touch => touch.identifier === this.primaryPointer.identifier);
Expand All @@ -108,6 +111,7 @@ export class InputHandler {
switch (e.type) {
case 'mousedown':
case 'touchstart':
this.clearLastPointerTimer.stop();
this.firstPointer = this.primaryPointer;
this._isGrabbing = true;
this._isDragging = false;
Expand All @@ -130,8 +134,12 @@ export class InputHandler {
if (this.onContextMenu) this.onContextMenu(e);
}

private isSyntheticEvent(mosuePointer: PointerData, threshold: number = 15): boolean {
for (let pointer of this.lastPointers) {
private isSyntheticEvent(e: MouseEvent, threshold: number = 15): boolean {
let mosuePointer: PointerData = { x: e.pageX, y: e.pageY, z: 0, identifier: MOUSE_IDENTIFIER };
let lastPointers = this.lastMovePointers;
if (e.type !== 'mousemove') lastPointers = lastPointers.concat(this.lastStartPointers);

for (let pointer of lastPointers) {
if (pointer.identifier === mosuePointer.identifier) continue;
if (this.calcMagnitude(mosuePointer, pointer) < threshold ** 2) {
return true;
Expand All @@ -140,6 +148,29 @@ export class InputHandler {
return false;
}

private updateLastPointer(e: MouseEvent | TouchEvent) {
let lastPointers: PointerData[] = [];
if (e instanceof TouchEvent) {
let length = e.touches.length;
for (let i = 0; i < length; i++) {
let touch = e.touches[i];
let touchPointer: PointerData = { x: touch.pageX, y: touch.pageY, z: 0, identifier: touch.identifier };
lastPointers.push(touchPointer);
}
} else {
let mosuePointer: PointerData = { x: e.pageX, y: e.pageY, z: 0, identifier: MOUSE_IDENTIFIER };
lastPointers.push(mosuePointer);
}
this.lastMovePointers = lastPointers;
if (e.type === 'mousedown' || e.type === 'touchstart') this.lastStartPointers = lastPointers;
}

private clearLastPointer() {
this.clearLastPointerTimer.stop();
this.lastStartPointers = [];
this.lastMovePointers = [];
}

private calcMagnitude(a: PointerCoordinate, b: PointerCoordinate) {
return (a.x - b.x) ** 2 + (a.y - b.y) ** 2 + (a.z - b.z) ** 2;
}
Expand Down

0 comments on commit 3ccec24

Please sign in to comment.