A developer who builds two-finger pinch detection using TouchEvent listeners will ship code that works perfectly on an Android phone and silently does nothing on a Windows laptop. The reason is architectural, not a browser bug: a desktop trackpad does not fire TouchEvent at all. Knowing which events each input device actually produces — and why — is the prerequisite for writing gesture code that works across device categories.
What PointerEvent and TouchEvent are
TouchEvent is the older of the two APIs. Introduced to handle finger input on mobile touchscreens, it delivers a list of active contacts (touches, targetTouches, changedTouches) through events named touchstart, touchmove, touchend, and touchcancel. Each entry in those lists is a Touch object with its own coordinates and identifier. The API was designed specifically for touchscreens, and that origin shows: it has no concept of a mouse, a stylus, or a trackpad.
PointerEvent is the W3C's unified replacement, first shipped in Internet Explorer 11 and now part of every major browser. It handles mouse, pen, and touch through a single event family — pointerdown, pointermove, pointerup, pointercancel — and exposes a pointerType property on each event that names the source: "mouse", "pen", or "touch". The MDN Pointer Events documentation describes the full model; the W3C specification is maintained at w3c.github.io/pointerevents.
What a desktop trackpad actually fires
This is the part that surprises most developers: a laptop trackpad on a desktop OS does not fire TouchEvent, and it does not produce PointerEvent with pointerType: "touch". It fires:
- PointerEvent with
pointerType: "mouse"— single-contact movement and clicks arrive as ordinary pointer-mouse events. The browser cannot tell from the event alone whether the physical input device was a physical mouse or a trackpad. - WheelEvent — two-finger scroll on a trackpad produces a
wheelevent, exactly as a mouse scroll wheel would. ThedeltaXanddeltaYproperties report the scroll amounts. - WheelEvent with
ctrlKey: true— the OS converts a trackpad pinch-to-zoom gesture into awheelevent with thectrlKeyflag set. This is the standard cross-browser signal for trackpad-driven zoom. Web pages that interceptctrl+wheelto implement custom zoom behavior are leveraging exactly this convention.
Touchscreens, by contrast, fire PointerEvent with pointerType: "touch" — and on browsers that still maintain the legacy API, TouchEvent as well. Two fingers on a touchscreen produce two simultaneous pointerdown events, each with a distinct pointerId, which web code can use directly to compute pinch scale by comparing inter-pointer distance.
Why the distinction matters for gesture code
The practical consequences split into three patterns:
- Two-finger pinch on a touchscreen — detectable by tracking two concurrent
pointerdownevents (or two entries inTouchEvent.touches) and computing the distance between them acrosspointermoveevents. This pattern works on mobile but produces nothing useful on a desktop trackpad, because the trackpad never sends two simultaneous pointer contacts to the browser. - Trackpad pinch-to-zoom — detectable only via
wheelevent withctrlKey === true. No two-pointer math is needed or possible. The OS has already converted the two-finger gesture into a scalar zoom delta before the browser sees anything. - Scroll on both devices — converges on the same
wheelevent, making scroll the most portable gesture to handle:addEventListener("wheel", handler)catches two-finger trackpad scroll and touchscreen overscroll delegation equally.
This architectural split is by design. The OS processes raw multi-finger contacts from the touchpad and delivers finished, semantically-labeled events to the browser. The browser then forwards those events to pages. A touchscreen, by contrast, passes raw contact data through to the browser, which is why web code can implement custom pinch logic on a touchscreen but cannot do the same on a desktop trackpad without going outside the standard web platform.
How the tester reflects this design
The tester's GestureDetector module uses this split deliberately. Tap, double-tap, long-press, and swipe are detected via PointerEvent listeners — the same events a trackpad fires as pointerType: "mouse" events. Scroll is detected via wheel event listeners. Pinch, however, is detected via TouchEvent (touchstart, touchmove) — specifically checking for two simultaneous contacts and measuring the change in distance between them. If the distance changes by more than 30 pixels, a pinch is triggered. On a desktop trackpad this path will never fire because no TouchEvent arrives; pinch on a trackpad reaches the browser only as a ctrl+wheel event, which the gesture panel counts under scroll rather than pinch. On a touchscreen, the TouchEvent path fires correctly and the pinch counter increments.
One practical limitation worth noting: neither API exposes raw finger contact data from a desktop trackpad to a web page. A tester tool can observe that a ctrl+wheel event fired, but it cannot report how many fingers produced it or what the raw contact positions were — that information is consumed by the OS before it reaches the browser.
Check yourself: use the tool above on a laptop touchpad and try a two-finger pinch gesture. If the Gesture Detection panel shows no pinch count increasing, you are on a desktop trackpad where pinch arrives asctrl+wheelrather thanTouchEvent. Switch to a touchscreen device and repeat the gesture — the pinch counter should increment, confirming that the two-fingerTouchEventpath is now active.