android: fix touchpad analog stick hitbox to be circular - #19420
Conversation
The touchpad handler for analog sticks was using hardcoded rectangular zones (360x360 square) instead of circular hitboxes. This change makes the analog stick hitboxes circular by calculating distance from center and only applying input within the radius.
|
Is that not going to affect the ability to hit full values in diagonals for cores that actually expect square zones? |
|
Thanks for the PR! The circular hitbox idea makes sense as a feel improvement, and the geometry checks out (786 matches the old x -= 606 center), but there are a few problems with the implementation as it stands. The big one: the else branch zeroes all four analog axes. This handler exists for two thumbs on the pad at once — if one pointer is holding the left stick deflected and a second pointer lands in the dead strip (or drifts just past a circle edge), that pointer's loop iteration wipes the other stick. With MOVE events firing continuously you end up with the two pointers fighting each other every event. The old code just ignored dead-zone coordinates and never touched the other stick's axes — any version of this needs to only ever write the axes belonging to the zone that pointer is actually in. Second, rejecting input outside the radius creates a diagonal cliff. Pushing to the physical corner of the square — which is the natural full-diagonal gesture on a rectangular pad — now produces no input at all, and just inside the circle edge diagonals cap out at ~0.707 (±23169). A circular gate should clamp, not reject: if dist > RADIUS, scale dx/dy by RADIUS/dist so direction is preserved and magnitude caps at the circle. Zone assignment can stay a coarse test (e.g. x < 483 → left, else right) independent of the radius. Third, once the zero-all is removed, the release path leaks state: lift your finger while outside both circles and nothing gets cleared, so the stick sticks. Better to track which stick each pointer_id owns (TOUCHSTATE is already static per-pointer, so adding a field is easy) and clear that stick's two axes unconditionally on UP/CANCEL. That would also properly fix a pre-existing bug where sliding into the 360–605 dead strip and lifting leaves the left stick stuck — which your patch currently only masks by accident. One smaller thing: dxdx + dydy in int is fine for Xperia Play coordinates, but this path fires for any AINPUT_SOURCE_TOUCHPAD device and axis ranges are device-defined, so a pad reporting large coords could overflow. Doing the distance math in float (you're converting anyway) sidesteps it. Also, uppercase block-scope locals aren't really the convention here — lowercase or #defines would fit better. Happy to review a v2 with clamp-instead-of-reject and per-pointer stick ownership — I think that version would be mergeable. |
The touchpad handler for analog sticks was using hardcoded rectangular zones (360x360 square) instead of circular hitboxes. This change makes the analog stick hitboxes circular by calculating distance from center and only applying input within the radius.