Gesture handler never releases touches cancelled by touchcancel
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
### Bug description
The `Gesture` singleton (`src/vs/base/browser/touch.ts`) listens for `touchstart`, `touchmove` and `touchend` but never for `touchcancel`. When the browser takes over a touch (system gesture, palm rejection, navigation), it delivers `touchcancel` instead of `touchend`, so `onTouchEnd` never runs and the entry in `activeTouches` stays forever.
Consequences per leaked entry:
- the DOM node reference in `activeTouches` is pinned (no garbage collection while the page lives),
- `Gesture.addTarget` bookkeeping on that node is never undone,
- with exactly one remaining active touch, the inertia dispatch branch treats the session as multi-touch, so single-finger inertia scrolling stops working after a few cancelled swipes.
`grep -r touchcancel src/vs` finds no match: nothing under `src/vs/` handles cancellation today.
### Steps to reproduce
1. On a touch device, start a scroll gesture and trigger a UA takeover mid-gesture (e.g. invoke the system edge swipe) a few times.
2. Single-finger inertia scrolling stops responding afterwards; DevTools shows stale entries in `Gesture`'s internal touch map.
### Expected behavior
`touchcancel` releases the cancelled touch identifiers silently: no tap, context menu or inertia dispatch for an interrupted gesture, and the internal state is cleaned up like a normal end.
### Version tested
Commit `38ec3d57f91b` on `main`; verified by executing the compiled Gesture handler with synthesized cancel events. A fix is ready.
Contributor guide
Assessment
This issue has not been assessed yet.