Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions lib/web_ui/lib/src/engine/pointer_binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
@override
void setup() {
_addPointerEventListener('pointerdown', (html.PointerEvent event) {
final int device = event.pointerId!;
final int device = _getPointerId(event);
final List<ui.PointerData> pointerData = <ui.PointerData>[];
final _ButtonSanitizer sanitizer = _ensureSanitizer(device);
final _SanitizedDetails? up =
Expand All @@ -528,7 +528,7 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
});

_addPointerEventListener('pointermove', (html.PointerEvent event) {
final int device = event.pointerId!;
final int device = _getPointerId(event);
final _ButtonSanitizer sanitizer = _ensureSanitizer(device);
final List<ui.PointerData> pointerData = <ui.PointerData>[];
final List<html.PointerEvent> expandedEvents = _expandEvents(event);
Expand All @@ -544,7 +544,7 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
}, acceptOutsideGlasspane: true);

_addPointerEventListener('pointerup', (html.PointerEvent event) {
final int device = event.pointerId!;
final int device = _getPointerId(event);
final List<ui.PointerData> pointerData = <ui.PointerData>[];
final _SanitizedDetails? details = _getSanitizer(device).sanitizeUpEvent(buttons: event.buttons);
_removePointerIfUnhoverable(event);
Expand All @@ -557,7 +557,7 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
// A browser fires cancel event if it concludes the pointer will no longer
// be able to generate events (example: device is deactivated)
_addPointerEventListener('pointercancel', (html.PointerEvent event) {
final int device = event.pointerId!;
final int device = _getPointerId(event);
final List<ui.PointerData> pointerData = <ui.PointerData>[];
final _SanitizedDetails details = _getSanitizer(device).sanitizeCancelEvent();
_removePointerIfUnhoverable(event);
Expand All @@ -581,10 +581,6 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
assert(event != null); // ignore: unnecessary_null_comparison
assert(details != null); // ignore: unnecessary_null_comparison
final ui.PointerDeviceKind kind = _pointerTypeToDeviceKind(event.pointerType!);
// We force `device: _mouseDeviceId` on mouse pointers because Wheel events
// might come before any PointerEvents, and since wheel events don't contain
// pointerId we always assign `device: _mouseDeviceId` to them.
final int device = kind == ui.PointerDeviceKind.mouse ? _mouseDeviceId : event.pointerId!;
final double tilt = _computeHighestTilt(event);
final Duration timeStamp = _BaseAdapter._eventTimeStampToDuration(event.timeStamp!);
_pointerDataConverter.convert(
Expand All @@ -593,7 +589,7 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
timeStamp: timeStamp,
kind: kind,
signalKind: ui.PointerSignalKind.none,
device: device,
device: _getPointerId(event),
physicalX: event.client.x.toDouble() * ui.window.devicePixelRatio,
physicalY: event.client.y.toDouble() * ui.window.devicePixelRatio,
buttons: details.buttons,
Expand Down Expand Up @@ -632,6 +628,14 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
}
}

int _getPointerId(html.PointerEvent event) {
// We force `device: _mouseDeviceId` on mouse pointers because Wheel events
// might come before any PointerEvents, and since wheel events don't contain
// pointerId we always assign `device: _mouseDeviceId` to them.
final ui.PointerDeviceKind kind = _pointerTypeToDeviceKind(event.pointerType!);
return kind == ui.PointerDeviceKind.mouse ? _mouseDeviceId : event.pointerId!;
}

/// Tilt angle is -90 to + 90. Take maximum deflection and convert to radians.
double _computeHighestTilt(html.PointerEvent e) =>
(e.tiltX!.abs() > e.tiltY!.abs() ? e.tiltX : e.tiltY)!.toDouble() /
Expand Down
66 changes: 60 additions & 6 deletions lib/web_ui/test/engine/pointer_binding_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2090,6 +2090,60 @@ void testMain() {
},
);

_testEach<_PointerEventContext>(
[
_PointerEventContext(),
],
'handles random pointer id on up events',
(_PointerEventContext context) {
PointerBinding.instance.debugOverrideDetector(context);
// This happens with pens that are simulated with mouse events
// (e.g. Wacom). It sends events with the pointer type "mouse", and
// assigns a random pointer ID to each event.
//
// For more info, see: https://github.com/flutter/flutter/issues/75559

List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};

glassPane.dispatchEvent(context.mouseDown(
pointerId: 12,
button: 0,
buttons: 1,
clientX: 10.0,
clientY: 10.0,
));

expect(packets, hasLength(1));
expect(packets.single.data, hasLength(2));

expect(packets.single.data[0].change, equals(ui.PointerChange.add));
expect(packets.single.data[0].synthesized, equals(true));
expect(packets.single.data[1].change, equals(ui.PointerChange.down));
packets.clear();

expect(
() {
glassPane.dispatchEvent(context.mouseUp(
pointerId: 41,
button: 0,
buttons: 0,
clientX: 10.0,
clientY: 10.0,
));
},
returnsNormally,
);

expect(packets, hasLength(1));
expect(packets.single.data, hasLength(1));

expect(packets.single.data[0].change, equals(ui.PointerChange.up));
},
);

// TOUCH ADAPTER

_testEach(
Expand Down Expand Up @@ -2537,9 +2591,9 @@ class _PointerEventContext extends _BasicEventContext

@override
html.Event mouseDown(
{double clientX, double clientY, int button, int buttons}) {
{double clientX, double clientY, int button, int buttons, int pointerId = 1}) {
return _downWithFullDetails(
pointer: 1,
pointer: pointerId,
buttons: buttons,
button: button,
clientX: clientX,
Expand Down Expand Up @@ -2581,9 +2635,9 @@ class _PointerEventContext extends _BasicEventContext

@override
html.Event mouseMove(
{double clientX, double clientY, int button, int buttons}) {
{double clientX, double clientY, int button, int buttons, int pointerId = 1}) {
return _moveWithFullDetails(
pointer: 1,
pointer: pointerId,
buttons: buttons,
button: button,
clientX: clientX,
Expand Down Expand Up @@ -2623,9 +2677,9 @@ class _PointerEventContext extends _BasicEventContext
}

@override
html.Event mouseUp({double clientX, double clientY, int button, int buttons}) {
html.Event mouseUp({double clientX, double clientY, int button, int buttons, int pointerId = 1}) {
return _upWithFullDetails(
pointer: 1,
pointer: pointerId,
button: button,
buttons: buttons,
clientX: clientX,
Expand Down