Skip to content

Add Multitouch rollover support for the gamepad buttons - #29

Open
SerSaumy wants to merge 2 commits into
kitswas:mainfrom
SerSaumy:multitouch-rollover
Open

Add Multitouch rollover support for the gamepad buttons#29
SerSaumy wants to merge 2 commits into
kitswas:mainfrom
SerSaumy:multitouch-rollover

Conversation

@SerSaumy

@SerSaumy SerSaumy commented Aug 7, 2026

Copy link
Copy Markdown

What this does

Replaces the per-button clickable gesture detectors on the D-pad, face buttons,
shoulder buttons, and menu buttons with a shared MultiTouchController that
hit-tests every active pointer against every button's bounds. This adds two
related behaviors:

  • Multi-touch, up to 4 simultaneous fingers (MAX_TRACKED_TOUCH_POINTS in
    the new TouchZoneController.kt) — previously each button's gesture detector
    only knew about its own pointer, with no shared limit or coordination across
    the cluster.
  • Rollover / slide-to-switch: press a button, then without lifting your
    finger, drag it onto a different button — the first releases and the second
    presses automatically. No need to lift and re-tap to switch buttons mid-gesture.

Analog sticks (AnalogStick.kt) and triggers (Trigger.kt) are unchanged
on purpose — they're continuous drag controls, not discrete buttons, so
rollover doesn't apply to them the same way.

Why

Each button previously owned its own MutableInteractionSource + clickable,
so no button's gesture detector could know a finger had slid over from a
neighboring button, and there was no single place to reason about "how many
fingers is this cluster tracking." Rollover requires looking at all buttons'
bounds and all active pointers together, so the touch handling moved to one
shared controller instead.

Changes

  • New: ui/composables/TouchZoneController.ktMultiTouchController
    (zone registration, pointer-to-zone tracking, hit-testing, press/release
    callbacks), Modifier.multiTouchDispatcher (manual low-level pointer
    tracking via awaitPointerEventScope), Modifier.touchZone (per-button
    registration), plus LocalMultiTouchController / LocalTouchContainerCoordinates.
  • Modified: ui/composables/Gamepad.kt — wires the shared controller and
    container coordinates into DrawGamepad via CompositionLocalProvider,
    releases all buttons on teardown so nothing gets stuck "pressed."
  • Modified: ui/composables/FaceButtons.kt, Dpad.kt, CentralButtons.kt
    — swapped Button/OutlinedButton/OutlinedIconButton + clickable for
    Surface + Modifier.touchZone, with an animated background tint on press
    (replacing the ripple lost by moving off clickable).

Testing

Built and tested on-device (not just emulator, since emulators generally only
simulate 1-2 touch points). Verified:

  • Multiple fingers on different buttons register and stay independent
  • Holding a button and sliding to another correctly releases/presses across
    the transition
  • Holding 4 buttons at once works; a 5th simultaneous touch is ignored rather
    than stealing a tracking slot
  • No buttons get stuck "pressed" after rotating the screen or navigating away
    mid-touch

Notes

  • MAX_TRACKED_TOUCH_POINTS is a single constant if this limit should be
    raised/lowered later.
  • Happy to split this into smaller commits or adjust the zone-id scheme
    (face_A, dpad_UP, shoulder_LEFT, etc.) if you'd prefer a different
    convention.

w-zz-w-zz-w and others added 2 commits August 7, 2026 13:45
- Add MultiTouchController (ui/composables/TouchZoneController.kt) that
  hit-tests every active pointer against registered button bounds instead
  of relying on one clickable per button.
- MAX_TRACKED_TOUCH_POINTS = 4: explicit, tunable cap on simultaneously
  tracked fingers on the button layer.
- Rollover: dragging an already-down finger from one button directly into
  a neighbouring one releases the first and presses the second, without
  lifting off the screen.
- Wire the controller into DrawGamepad (ui/composables/Gamepad.kt) via
  CompositionLocalProvider.
- Migrate FaceButtons.kt, Dpad.kt, CentralButtons.kt from
  Button/OutlinedButton/OutlinedIconButton + clickable to Surface +
  Modifier.touchZone, with an animated press-color for visual feedback
  (replacing the lost ripple).
- Trigger.kt and AnalogStick.kt intentionally left untouched (drag-based
  analog controls, not discrete buttons).
@sonarqubecloud

sonarqubecloud Bot commented Aug 7, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
13.4% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants