Web: Migrate touch input to unified Pointer Events API#2799
Web: Migrate touch input to unified Pointer Events API#2799
Conversation
…on web. - Replace touch events with pointer events for touch input handling. - Refactor `initEvents` to consolidate pointer event handling into a loop. - Remove duplicate event processing for touch and mouse inputs. - Add `setPointerCapture` for better pointer management across elements. - Disable default browser touch handling via `touch-action: none`. Fixes https://youtrack.jetbrains.com/issue/CMP-9745
- Add support for `getCoalescedEvents` to process multiple pointer events. - Refactor `ComposeScenePointer` logic to handle event coalescing. - Ignore invalid touch events (`Enter` or `Exit`) sent by Firefox.
…cy TouchEvent code. - Replace `TouchEvent` logic with `PointerEvent` to streamline event handling. - Remove unused `TouchEvent` classes and related utilities. - Update tests to use `PointerEvent` for consistency. - Improve handling of coalesced events and fallback scenarios.
…mouse input handling logic.
| ) | ||
| if (isTouch) { | ||
| if (eventType == PointerEventType.Enter || eventType == PointerEventType.Exit) { | ||
| //Firefox sends such touch events, so we need to ignore them |
There was a problem hiding this comment.
Did you observe some bad behaviour on firefox before you added this early return?
There was a problem hiding this comment.
yes. the problem is I remove an active pointer from the map on an up event. And then I get one more exit event
There was a problem hiding this comment.
What about Safari? Quite often Safari has a 3rd way of sending events :D
| private val activeTouchPointers = mutableMapOf<Int, TouchEventWithContainerOffset>() | ||
|
|
||
| private fun onPointerEvent(event: PointerEvent) { | ||
| val isTouch = event.pointerType == "touch" |
There was a problem hiding this comment.
To make the touch handler a bit cheaper we can try to call some js interop helper function which would return integers instead of strings (strings are more expensive when transferred from js to wasm).
And then map Integeres to Compose values.
Since the handler is called quite often, it might be beneficial.
There was a problem hiding this comment.
Are you sure this is a problem? I see a lot the same strings manipulations already
There was a problem hiding this comment.
There is a difference:
String time = 1.4ms
Int time = 0s
Are you sure this is a problem?
If we want to make the touch handlers cheaper, then it's worth it.
I see a lot the same strings manipulations already
IMO, sometimes it's okay to prefer the simplicity. In frequent calls such as (touch, key, mouse) event handlers it's worth to reduce the costs.
| } | ||
|
|
||
| keyboardModeState = KeyboardModeState.Hardware | ||
| private val activeTouchPointers = mutableMapOf<Int, TouchEventWithContainerOffset>() |
| val composePointers: List<ComposeScenePointer> by lazy { | ||
| val coalesced = getCoalescedEvents(event).toList() | ||
| val list = coalesced.takeIf { it.isNotEmpty() } ?: listOf(event) | ||
| list.map { e -> |
| "pointerup", | ||
| "pointerleave", | ||
| "pointercancel" | ||
| ).forEach { name -> |
| "pointerleave", | ||
| "pointercancel" | ||
| ).forEach { name -> | ||
| addTypedEvent<PointerEvent>(name, passive = false) { onPointerEvent(it) } |
There was a problem hiding this comment.
| addTypedEvent<PointerEvent>(name, passive = false) { onPointerEvent(it) } | |
| addTypedEvent<PointerEvent>(name, passive = false, handler = ::onPointerEvent) |
Fixes https://youtrack.jetbrains.com/issue/CMP-9745
Testing
Migrate touch tests.
Release Notes
N/A