Skip to content

Commit a8d17fa

Browse files
j-piaseckitomekzaw
andauthored
Fix Gesture Handlers getting stuck due to missing up event when using the new web implementation (#2442)
## Description Sometimes the view didn't receive the `pointerup` event when moving the pointer really fast, even though it was captured. This was causing a problem where the gesture would never be finished, preventing every other handler from activating. Funny thing is, despite not receiving the `pointerup` event, `lostpointercapture` event was still there. I used this fact to fill the missing `up` event, so the gesture can correctly handle it. I've only been able to reproduce it in Chrome, when using external display. ## Test plan Tested on the Example app, specifically the `Draggable` example. --------- Co-authored-by: Tomek Zawadzki <tomekzawadzki98@gmail.com>
1 parent eafd9e3 commit a8d17fa

9 files changed

+32
-39
lines changed

src/web/handlers/FlingGestureHandler.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,6 @@ export default class FlingGestureHandler extends GestureHandler {
159159
this.endFling();
160160
}
161161

162-
protected onPointerCancel(event: AdaptedEvent): void {
163-
super.onPointerCancel(event);
164-
this.reset();
165-
}
166-
167162
public activate(force?: boolean): void {
168163
super.activate(force);
169164
this.end();

src/web/handlers/GestureHandler.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,9 @@ export default abstract class GestureHandler {
352352
if (this.config.needsPointerData) {
353353
this.sendTouchEvent(event);
354354
}
355+
356+
this.cancel();
357+
this.reset();
355358
}
356359
protected onPointerOutOfBounds(event: AdaptedEvent): void {
357360
this.tryToSendMoveEvent(true);

src/web/handlers/ManualGestureHandler.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,4 @@ export default class ManualGestureHandler extends GestureHandler {
4040
super.onPointerRemove(event);
4141
this.tracker.removeFromTracker(event.pointerId);
4242
}
43-
44-
protected onPointerCancel(event: AdaptedEvent): void {
45-
super.onPointerCancel(event);
46-
this.reset();
47-
}
4843
}

src/web/handlers/NativeViewGestureHandler.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,6 @@ export default class NativeViewGestureHandler extends GestureHandler {
115115
}
116116
}
117117

118-
protected onPointerCancel(event: AdaptedEvent): void {
119-
super.onPointerCancel(event);
120-
this.cancel();
121-
this.reset();
122-
}
123-
124118
public shouldRecognizeSimultaneously(handler: GestureHandler): boolean {
125119
if (super.shouldRecognizeSimultaneously(handler)) {
126120
return true;

src/web/handlers/PanGestureHandler.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,6 @@ export default class PanGestureHandler extends GestureHandler {
306306
super.onPointerMove(event);
307307
}
308308

309-
protected onPointerCancel(event: AdaptedEvent): void {
310-
super.onPointerCancel(event);
311-
312-
this.reset();
313-
}
314309
protected onPointerOutOfBounds(event: AdaptedEvent): void {
315310
if (this.getShouldCancelWhenOutside()) {
316311
return;

src/web/handlers/PinchGestureHandler.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,6 @@ export default class PinchGestureHandler extends GestureHandler {
127127
super.onPointerOutOfBounds(event);
128128
}
129129

130-
protected onPointerCancel(event: AdaptedEvent): void {
131-
super.onPointerCancel(event);
132-
this.reset();
133-
}
134-
135130
private tryBegin(): void {
136131
if (this.currentState !== State.UNDETERMINED) {
137132
return;

src/web/handlers/RotationGestureHandler.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,6 @@ export default class RotationGestureHandler extends GestureHandler {
148148
this.tracker.removeFromTracker(event.pointerId);
149149
}
150150

151-
protected onPointerCancel(event: AdaptedEvent): void {
152-
super.onPointerCancel(event);
153-
this.end();
154-
155-
this.reset();
156-
}
157-
158151
protected tryBegin(): void {
159152
if (this.currentState !== State.UNDETERMINED) {
160153
return;

src/web/handlers/TapGestureHandler.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,6 @@ export default class TapGestureHandler extends GestureHandler {
197197
super.onPointerOutOfBounds(event);
198198
}
199199

200-
protected onPointerCancel(event: AdaptedEvent): void {
201-
super.onPointerCancel(event);
202-
this.tracker.resetTracker();
203-
this.fail();
204-
}
205-
206200
private updateState(event: AdaptedEvent): void {
207201
if (
208202
this.currentMaxNumberOfPointers < this.tracker.getTrackedPointersCount()

src/web/tools/PointerEventManager.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import EventManager from './EventManager';
88
import { isPointerInBounds } from '../utils';
99

1010
export default class PointerEventManager extends EventManager {
11+
private trackedPointers = new Set<number>();
12+
1113
public setListeners(): void {
1214
this.view.addEventListener('pointerdown', (event: PointerEvent): void => {
1315
if (event.pointerType === PointerType.TOUCH) {
@@ -24,6 +26,7 @@ export default class PointerEventManager extends EventManager {
2426

2527
target.setPointerCapture(adaptedEvent.pointerId);
2628
this.markAsInBounds(adaptedEvent.pointerId);
29+
this.trackedPointers.add(adaptedEvent.pointerId);
2730

2831
if (++this.activePointersCounter > 1) {
2932
adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_DOWN;
@@ -51,6 +54,7 @@ export default class PointerEventManager extends EventManager {
5154

5255
target.releasePointerCapture(adaptedEvent.pointerId);
5356
this.markAsOutOfBounds(adaptedEvent.pointerId);
57+
this.trackedPointers.delete(adaptedEvent.pointerId);
5458

5559
if (--this.activePointersCounter > 0) {
5660
adaptedEvent.eventType = EventTypes.ADDITIONAL_POINTER_UP;
@@ -115,7 +119,27 @@ export default class PointerEventManager extends EventManager {
115119
this.onPointerCancel(adaptedEvent);
116120
this.markAsOutOfBounds(adaptedEvent.pointerId);
117121
this.activePointersCounter = 0;
122+
this.trackedPointers.clear();
118123
});
124+
125+
this.view.addEventListener(
126+
'lostpointercapture',
127+
(event: PointerEvent): void => {
128+
const adaptedEvent: AdaptedEvent = this.mapEvent(
129+
event,
130+
EventTypes.CANCEL
131+
);
132+
133+
if (this.trackedPointers.has(adaptedEvent.pointerId)) {
134+
// in some cases the `pointerup` event is not fired, but `lostpointercapture` is
135+
// we simulate the `pointercancel` event here to make sure the gesture handler stops tracking it
136+
this.onPointerCancel(adaptedEvent);
137+
138+
this.activePointersCounter = 0;
139+
this.trackedPointers.clear();
140+
}
141+
}
142+
);
119143
}
120144

121145
protected mapEvent(event: PointerEvent, eventType: EventTypes): AdaptedEvent {
@@ -131,4 +155,9 @@ export default class PointerEventManager extends EventManager {
131155
time: event.timeStamp,
132156
};
133157
}
158+
159+
public resetManager(): void {
160+
super.resetManager();
161+
this.trackedPointers.clear();
162+
}
134163
}

0 commit comments

Comments
 (0)