Stop the two-finger tap losing its gesture to the pinch - #42
Merged
Merged
Conversation
The two-finger right click added in 1.0.6 never fired. Pinch and pan both claim two touches as soon as they land, and whichever begins first takes the gesture, so the tap was read as a zoom of roughly no magnitude — nothing visibly happened and no click was sent. Pinch and pan now wait for the two-finger tap to fail before they can begin, expressed through shouldRequireFailureOf rather than require(toFail:) because the delegate method can be exercised directly in a test. The cost is negligible: any real zoom or scroll moves the fingers, which fails the tap at about the same threshold those recognizers need to begin anyway. Only holding two fingers still defers them, and that is the tap itself. A one-finger tap is deliberately excluded from the requirement, since it can never block a pinch and waiting on it would only add latency. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XU7Ck7AbZ9KpRhdPbRzNj8
GestureHarness is a UI-test host that puts the real PointerCaptureView on screen with capture forced on and surfaces emitted reports in a label. GestureHarnessUITests drives real multi-touch against it. Recognizer arbitration cannot be reached from a unit test, and it is where both of the recent gesture bugs lived. It immediately paid for itself twice, and once against expectation: - The first version of this fix made both pan and pinch wait for the tap to fail. That starves the pinch completely: a spread fired a right click and did not zoom. Caught before shipping. - Running the harness against the 1.0.6 code showed a pinch there emits a right click as well as zooming, because the delegate allowed the tap and the pinch to recognize simultaneously. That is a real defect in the shipped build, and separate from the reported one. So the arbitration is now asymmetric: the pan waits for the tap to fail, which is what makes the tap fire at all; the pinch does not wait and is kept off the tap by mutual exclusion instead. Honest limitation: the harness does NOT reproduce the reported bug. The two-finger tap test passes against the 1.0.6 code, because XCUITest synthesizes two perfectly simultaneous touches with no drift and real fingers have plenty. The pan-waits-for-tap fix therefore still rests on inference and needs hardware confirmation. The harness has its own scheme and stays out of CI, so PR runs keep their current shape. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XU7Ck7AbZ9KpRhdPbRzNj8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
The two-finger right click added in #41 never fired. Pinch and pan both claim two touches the moment they land, and whichever begins first takes the gesture — so the tap was consumed as a zoom of roughly no magnitude. Nothing visibly happened and no click was sent, which matches the reported symptom exactly.
My comment in #41 asserted that "a stationary two-finger tap starts neither the pan nor the pinch — both need movement." That was wrong in practice: fingers drift, and the recognizers claim the touches before the tap can complete.
Trackpad right click is unaffected and confirmed working — it arrives as an indirect secondary click on a different recognizer.
The fix
Pinch and pan now wait for the two-finger tap to fail before they can begin.
Expressed through the
shouldRequireFailureOfdelegate method rather thanrequire(toFail:). They're equivalent in behaviour, butrequire(toFail:)has no public getter, so it can only be verified by reading the code — the delegate method can be called directly with the view's real recognizers in a test.The latency cost is negligible: any real zoom or scroll moves the fingers, which fails the tap at roughly the same threshold those recognizers need to begin anyway. A one-finger tap is deliberately excluded, since it can never block a pinch and waiting on it would only add latency.
What is and isn't verified
test_pinchAndPanWaitForTheTwoFingerTapToFailTest plan
🤖 Generated with Claude Code