fix: allow pause action items to appear before any pointer movement - #1246
Conversation
W3C clients (e.g. Selenium) pad shorter pointer action sequences with zero-duration pause items to align tick counts across multiple pointers, sometimes placing that pause before the first pointerMove. Since a pause never touches the screen, it should not require a preceding item to resolve its position. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G67QwebqZCxEYN6XmJDGJs
The pointerDown-after-move dedup check in FBPointerDownItem was hardcoded to absolute index 1, assuming pointerMove is always the first action item. With a leading pause now allowed, this shifted pointerDown to index 2 and the check silently stopped firing, causing WDA to synthesize a second, separate touch-down at the same point. Make the check semantic (only pauses may precede the pointerMove) instead of index-based. Also drop the now-obsolete erroneous-gesture case that asserted a leading pause must fail, and add a regression test that inspects the synthesized XCPointerEventPath/XCPointerEvent stream directly rather than relying on the gesture's visible side effect. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G67QwebqZCxEYN6XmJDGJs
| // Unlike other gesture items, a pause never touches the screen, so it may | ||
| // legally be the first item in a sequence (e.g. used by clients to align | ||
| // ticks across multiple pointers/devices) | ||
| return self.previousItem.atPosition ?: [self hitpointWithElement:nil |
There was a problem hiding this comment.
[P2] Preserve cross-source tick timing
A zero-duration pause still occupies a tick whose duration is the maximum duration of all actions in that tick (W3C algorithm). For example, if finger 1 has a 100 ms pointerMove in tick 0 while finger 2 has this leading pause(0), finger 2’s next action must start at 100 ms. On this PR head, a focused diagnostic showed finger 2’s synthesized path starting at 0.0 rather than 0.1 seconds because each FBW3CGestureItemsChain accumulates only its own item durations. Thus the newly accepted Selenium-padded sequence can still execute with the fingers temporally misaligned. Could the event offsets be based on a global per-tick schedule, with a regression using a nonzero concurrent action?
There was a problem hiding this comment.
it was always working like that before. Changing/fixing this algorithm would be a breaking change for this repo
A pause has no position of its own, so let it stay nil instead of defaulting to (0,0) when nothing real precedes it yet. Items that actually need a position (pointerDown/pointerUp, and relative pointerMove) now check previousItem.atPosition explicitly and error if it's unresolved, so the first real touch action in a sequence must still supply a real coordinate via an absolute pointerMove. This also closes a gap where pause immediately followed by pointerDown (no move at all) would have silently synthesized a touch at (0,0); it now correctly errors, covered by two new erroneous-gesture cases. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G67QwebqZCxEYN6XmJDGJs
## [16.12.2](v16.12.1...v16.12.2) (2026-09-03) ### Bug Fixes * allow pause action items to appear before any pointer movement ([#1246](#1246)) ([282478a](282478a))
|
🎉 This PR is included in version 16.12.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |
W3C clients (e.g. Selenium) pad shorter pointer action sequences with zero-duration pause items to align tick counts across multiple pointers, sometimes placing that pause before the first pointerMove. Since a pause never touches the screen, it should not require a preceding item to resolve its position.