Fix edge cases of PointerEventConverter (#29998)
* Fix: ui.PointerChange.remove might contain position change, but we used to expand it into a Cancel and Remove, neither of which allows position change. A Hover event is added, and a test is updated accordingly.
* Fixed the issue where a PointerMoveEvent and a PointerCancelEvent do not receive the correct pressure.
* Refactor the calculation of delta into deltaTo.
diff --git a/packages/flutter/lib/src/gestures/converter.dart b/packages/flutter/lib/src/gestures/converter.dart
index 0364c59..8c0d209 100644
--- a/packages/flutter/lib/src/gestures/converter.dart
+++ b/packages/flutter/lib/src/gestures/converter.dart
@@ -32,6 +32,8 @@
Offset lastPosition;
+ Offset deltaTo(Offset to) => to - lastPosition;
+
@override
String toString() {
return '_PointerState(pointer: $pointer, down: $down, lastPosition: $lastPosition)';
@@ -126,14 +128,12 @@
tilt: datum.tilt,
);
}
- final Offset offset = position - state.lastPosition;
- state.lastPosition = position;
yield PointerHoverEvent(
timeStamp: timeStamp,
kind: kind,
device: datum.device,
position: position,
- delta: offset,
+ delta: state.deltaTo(position),
buttons: datum.buttons,
obscured: datum.obscured,
pressureMin: datum.pressureMin,
@@ -176,14 +176,12 @@
// Not all sources of pointer packets respect the invariant that
// they hover the pointer to the down location before sending the
// down event. We restore the invariant here for our clients.
- final Offset offset = position - state.lastPosition;
- state.lastPosition = position;
yield PointerHoverEvent(
timeStamp: timeStamp,
kind: kind,
device: datum.device,
position: position,
- delta: offset,
+ delta: state.deltaTo(position),
buttons: datum.buttons,
obscured: datum.obscured,
pressureMin: datum.pressureMin,
@@ -231,15 +229,13 @@
assert(_pointers.containsKey(datum.device));
final _PointerState state = _pointers[datum.device];
assert(state.down);
- final Offset offset = position - state.lastPosition;
- state.lastPosition = position;
yield PointerMoveEvent(
timeStamp: timeStamp,
pointer: state.pointer,
kind: kind,
device: datum.device,
position: position,
- delta: offset,
+ delta: state.deltaTo(position),
buttons: datum.buttons,
obscured: datum.obscured,
pressure: datum.pressure,
@@ -255,6 +251,7 @@
tilt: datum.tilt,
platformData: datum.platformData,
);
+ state.lastPosition = position;
break;
case ui.PointerChange.up:
case ui.PointerChange.cancel:
@@ -267,15 +264,13 @@
// event. For example, in the iOS simulator, of you drag outside the
// window, you'll get a stream of pointers that violates that
// invariant. We restore the invariant here for our clients.
- final Offset offset = position - state.lastPosition;
- state.lastPosition = position;
yield PointerMoveEvent(
timeStamp: timeStamp,
pointer: state.pointer,
kind: kind,
device: datum.device,
position: position,
- delta: offset,
+ delta: state.deltaTo(position),
buttons: datum.buttons,
obscured: datum.obscured,
pressure: datum.pressure,
@@ -326,6 +321,7 @@
position: position,
buttons: datum.buttons,
obscured: datum.obscured,
+ pressure: datum.pressure,
pressureMin: datum.pressureMin,
pressureMax: datum.pressureMax,
distance: datum.distance,
@@ -349,8 +345,31 @@
pointer: state.pointer,
kind: kind,
device: datum.device,
+ position: state.lastPosition, // Change position in Hover
+ buttons: datum.buttons,
+ obscured: datum.obscured,
+ pressure: datum.pressure,
+ pressureMin: datum.pressureMin,
+ pressureMax: datum.pressureMax,
+ distance: datum.distance,
+ distanceMax: datum.distanceMax,
+ size: datum.size,
+ radiusMajor: radiusMajor,
+ radiusMinor: radiusMinor,
+ radiusMin: radiusMin,
+ radiusMax: radiusMax,
+ orientation: datum.orientation,
+ tilt: datum.tilt,
+ );
+ }
+ if (position != state.lastPosition) {
+ yield PointerHoverEvent(
+ timeStamp: timeStamp,
+ kind: kind,
+ device: datum.device,
position: position,
buttons: datum.buttons,
+ delta: state.deltaTo(position),
obscured: datum.obscured,
pressureMin: datum.pressureMin,
pressureMax: datum.pressureMax,
@@ -363,6 +382,7 @@
radiusMax: radiusMax,
orientation: datum.orientation,
tilt: datum.tilt,
+ synthesized: true,
);
}
_pointers.remove(datum.device);
@@ -390,8 +410,6 @@
// before sending the scroll event, if necessary, so that clients
// don't have to worry about native ordering of hover and scroll
// events.
- final Offset offset = position - state.lastPosition;
- state.lastPosition = position;
if (state.down) {
yield PointerMoveEvent(
timeStamp: timeStamp,
@@ -399,9 +417,10 @@
kind: kind,
device: datum.device,
position: position,
- delta: offset,
+ delta: state.deltaTo(position),
buttons: datum.buttons,
obscured: datum.obscured,
+ pressure: datum.pressure,
pressureMin: datum.pressureMin,
pressureMax: datum.pressureMax,
distanceMax: datum.distanceMax,
@@ -420,7 +439,7 @@
kind: kind,
device: datum.device,
position: position,
- delta: offset,
+ delta: state.deltaTo(position),
buttons: datum.buttons,
obscured: datum.obscured,
pressureMin: datum.pressureMin,
@@ -437,6 +456,7 @@
synthesized: true,
);
}
+ state.lastPosition = position;
}
final Offset scrollDelta =
Offset(datum.scrollDeltaX, datum.scrollDeltaY) / devicePixelRatio;
diff --git a/packages/flutter/lib/src/gestures/events.dart b/packages/flutter/lib/src/gestures/events.dart
index 6f68aec..dca70a9 100644
--- a/packages/flutter/lib/src/gestures/events.dart
+++ b/packages/flutter/lib/src/gestures/events.dart
@@ -346,21 +346,21 @@
double orientation = 0.0,
double tilt = 0.0,
}) : super(
- timeStamp: timeStamp,
- kind: kind,
- device: device,
- position: position,
- obscured: obscured,
- pressure: pressure,
- pressureMin: pressureMin,
- pressureMax: pressureMax,
- distance: distance,
- distanceMax: distanceMax,
- radiusMin: radiusMin,
- radiusMax: radiusMax,
- orientation: orientation,
- tilt: tilt
- );
+ timeStamp: timeStamp,
+ kind: kind,
+ device: device,
+ position: position,
+ obscured: obscured,
+ pressure: pressure,
+ pressureMin: pressureMin,
+ pressureMax: pressureMax,
+ distance: distance,
+ distanceMax: distanceMax,
+ radiusMin: radiusMin,
+ radiusMax: radiusMax,
+ orientation: orientation,
+ tilt: tilt,
+ );
}
/// The device is no longer tracking the pointer.
@@ -383,18 +383,18 @@
double radiusMin = 0.0,
double radiusMax = 0.0,
}) : super(
- timeStamp: timeStamp,
- kind: kind,
- device: device,
- position: null,
- obscured: obscured,
- pressure: pressure,
- pressureMin: pressureMin,
- pressureMax: pressureMax,
- distanceMax: distanceMax,
- radiusMin: radiusMin,
- radiusMax: radiusMax,
- );
+ timeStamp: timeStamp,
+ kind: kind,
+ device: device,
+ position: null,
+ obscured: obscured,
+ pressure: pressure,
+ pressureMin: pressureMin,
+ pressureMax: pressureMax,
+ distanceMax: distanceMax,
+ radiusMin: radiusMin,
+ radiusMax: radiusMax,
+ );
}
/// The pointer has moved with respect to the device while the pointer is not
@@ -433,28 +433,28 @@
double tilt = 0.0,
bool synthesized = false,
}) : super(
- timeStamp: timeStamp,
- kind: kind,
- device: device,
- position: position,
- delta: delta,
- buttons: buttons,
- down: false,
- obscured: obscured,
- pressure: pressure,
- pressureMin: pressureMin,
- pressureMax: pressureMax,
- distance: distance,
- distanceMax: distanceMax,
- size: size,
- radiusMajor: radiusMajor,
- radiusMinor: radiusMinor,
- radiusMin: radiusMin,
- radiusMax: radiusMax,
- orientation: orientation,
- tilt: tilt,
- synthesized: synthesized,
- );
+ timeStamp: timeStamp,
+ kind: kind,
+ device: device,
+ position: position,
+ delta: delta,
+ buttons: buttons,
+ down: false,
+ obscured: obscured,
+ pressure: pressure,
+ pressureMin: pressureMin,
+ pressureMax: pressureMax,
+ distance: distance,
+ distanceMax: distanceMax,
+ size: size,
+ radiusMajor: radiusMajor,
+ radiusMinor: radiusMinor,
+ radiusMin: radiusMin,
+ radiusMax: radiusMax,
+ orientation: orientation,
+ tilt: tilt,
+ synthesized: synthesized,
+ );
}
/// The pointer has moved with respect to the device while the pointer is not
@@ -493,28 +493,28 @@
double tilt = 0.0,
bool synthesized = false,
}) : super(
- timeStamp: timeStamp,
- kind: kind,
- device: device,
- position: position,
- delta: delta,
- buttons: buttons,
- down: false,
- obscured: obscured,
- pressure: pressure,
- pressureMin: pressureMin,
- pressureMax: pressureMax,
- distance: distance,
- distanceMax: distanceMax,
- size: size,
- radiusMajor: radiusMajor,
- radiusMinor: radiusMinor,
- radiusMin: radiusMin,
- radiusMax: radiusMax,
- orientation: orientation,
- tilt: tilt,
- synthesized: synthesized,
- );
+ timeStamp: timeStamp,
+ kind: kind,
+ device: device,
+ position: position,
+ delta: delta,
+ buttons: buttons,
+ down: false,
+ obscured: obscured,
+ pressure: pressure,
+ pressureMin: pressureMin,
+ pressureMax: pressureMax,
+ distance: distance,
+ distanceMax: distanceMax,
+ size: size,
+ radiusMajor: radiusMajor,
+ radiusMinor: radiusMinor,
+ radiusMin: radiusMin,
+ radiusMax: radiusMax,
+ orientation: orientation,
+ tilt: tilt,
+ synthesized: synthesized,
+ );
/// Creates an enter event from a [PointerHoverEvent].
///
@@ -586,28 +586,28 @@
double tilt = 0.0,
bool synthesized = false,
}) : super(
- timeStamp: timeStamp,
- kind: kind,
- device: device,
- position: position,
- delta: delta,
- buttons: buttons,
- down: false,
- obscured: obscured,
- pressure: pressure,
- pressureMin: pressureMin,
- pressureMax: pressureMax,
- distance: distance,
- distanceMax: distanceMax,
- size: size,
- radiusMajor: radiusMajor,
- radiusMinor: radiusMinor,
- radiusMin: radiusMin,
- radiusMax: radiusMax,
- orientation: orientation,
- tilt: tilt,
- synthesized: synthesized,
- );
+ timeStamp: timeStamp,
+ kind: kind,
+ device: device,
+ position: position,
+ delta: delta,
+ buttons: buttons,
+ down: false,
+ obscured: obscured,
+ pressure: pressure,
+ pressureMin: pressureMin,
+ pressureMax: pressureMax,
+ distance: distance,
+ distanceMax: distanceMax,
+ size: size,
+ radiusMajor: radiusMajor,
+ radiusMinor: radiusMinor,
+ radiusMin: radiusMin,
+ radiusMax: radiusMax,
+ orientation: orientation,
+ tilt: tilt,
+ synthesized: synthesized,
+ );
/// Creates an exit event from a [PointerHoverEvent].
///
@@ -668,27 +668,27 @@
double orientation = 0.0,
double tilt = 0.0,
}) : super(
- timeStamp: timeStamp,
- pointer: pointer,
- kind: kind,
- device: device,
- position: position,
- buttons: buttons,
- down: true,
- obscured: obscured,
- pressure: pressure,
- pressureMin: pressureMin,
- pressureMax: pressureMax,
- distance: 0.0,
- distanceMax: distanceMax,
- size: size,
- radiusMajor: radiusMajor,
- radiusMinor: radiusMinor,
- radiusMin: radiusMin,
- radiusMax: radiusMax,
- orientation: orientation,
- tilt: tilt
- );
+ timeStamp: timeStamp,
+ pointer: pointer,
+ kind: kind,
+ device: device,
+ position: position,
+ buttons: buttons,
+ down: true,
+ obscured: obscured,
+ pressure: pressure,
+ pressureMin: pressureMin,
+ pressureMax: pressureMax,
+ distance: 0.0,
+ distanceMax: distanceMax,
+ size: size,
+ radiusMajor: radiusMajor,
+ radiusMinor: radiusMinor,
+ radiusMin: radiusMin,
+ radiusMax: radiusMax,
+ orientation: orientation,
+ tilt: tilt,
+ );
}
/// The pointer has moved with respect to the device while the pointer is in
@@ -725,30 +725,30 @@
int platformData = 0,
bool synthesized = false,
}) : super(
- timeStamp: timeStamp,
- pointer: pointer,
- kind: kind,
- device: device,
- position: position,
- delta: delta,
- buttons: buttons,
- down: true,
- obscured: obscured,
- pressure: pressure,
- pressureMin: pressureMin,
- pressureMax: pressureMax,
- distance: 0.0,
- distanceMax: distanceMax,
- size: size,
- radiusMajor: radiusMajor,
- radiusMinor: radiusMinor,
- radiusMin: radiusMin,
- radiusMax: radiusMax,
- orientation: orientation,
- tilt: tilt,
- platformData: platformData,
- synthesized: synthesized,
- );
+ timeStamp: timeStamp,
+ pointer: pointer,
+ kind: kind,
+ device: device,
+ position: position,
+ delta: delta,
+ buttons: buttons,
+ down: true,
+ obscured: obscured,
+ pressure: pressure,
+ pressureMin: pressureMin,
+ pressureMax: pressureMax,
+ distance: 0.0,
+ distanceMax: distanceMax,
+ size: size,
+ radiusMajor: radiusMajor,
+ radiusMinor: radiusMinor,
+ radiusMin: radiusMin,
+ radiusMax: radiusMax,
+ orientation: orientation,
+ tilt: tilt,
+ platformData: platformData,
+ synthesized: synthesized,
+ );
}
/// The pointer has stopped making contact with the device.
@@ -777,27 +777,27 @@
double orientation = 0.0,
double tilt = 0.0,
}) : super(
- timeStamp: timeStamp,
- pointer: pointer,
- kind: kind,
- device: device,
- position: position,
- buttons: buttons,
- down: false,
- obscured: obscured,
- pressure: pressure,
- pressureMin: pressureMin,
- pressureMax: pressureMax,
- distance: distance,
- distanceMax: distanceMax,
- size: size,
- radiusMajor: radiusMajor,
- radiusMinor: radiusMinor,
- radiusMin: radiusMin,
- radiusMax: radiusMax,
- orientation: orientation,
- tilt: tilt
- );
+ timeStamp: timeStamp,
+ pointer: pointer,
+ kind: kind,
+ device: device,
+ position: position,
+ buttons: buttons,
+ down: false,
+ obscured: obscured,
+ pressure: pressure,
+ pressureMin: pressureMin,
+ pressureMax: pressureMax,
+ distance: distance,
+ distanceMax: distanceMax,
+ size: size,
+ radiusMajor: radiusMajor,
+ radiusMinor: radiusMinor,
+ radiusMin: radiusMin,
+ radiusMax: radiusMax,
+ orientation: orientation,
+ tilt: tilt,
+ );
}
/// An event that corresponds to a discrete pointer signal.
@@ -815,12 +815,12 @@
int device = 0,
Offset position = Offset.zero,
}) : super(
- timeStamp: timeStamp,
- pointer: pointer,
- kind: kind,
- device: device,
- position: position,
- );
+ timeStamp: timeStamp,
+ pointer: pointer,
+ kind: kind,
+ device: device,
+ position: position,
+ );
}
/// The pointer issued a scroll event.
@@ -843,11 +843,11 @@
assert(position != null),
assert(scrollDelta != null),
super(
- timeStamp: timeStamp,
- kind: kind,
- device: device,
- position: position,
- );
+ timeStamp: timeStamp,
+ kind: kind,
+ device: device,
+ position: position,
+ );
/// The amount to scroll, in logical pixels.
final Offset scrollDelta;
@@ -885,25 +885,25 @@
double orientation = 0.0,
double tilt = 0.0,
}) : super(
- timeStamp: timeStamp,
- pointer: pointer,
- kind: kind,
- device: device,
- position: position,
- buttons: buttons,
- down: false,
- obscured: obscured,
- pressure: pressure,
- pressureMin: pressureMin,
- pressureMax: pressureMax,
- distance: distance,
- distanceMax: distanceMax,
- size: size,
- radiusMajor: radiusMajor,
- radiusMinor: radiusMinor,
- radiusMin: radiusMin,
- radiusMax: radiusMax,
- orientation: orientation,
- tilt: tilt
- );
+ timeStamp: timeStamp,
+ pointer: pointer,
+ kind: kind,
+ device: device,
+ position: position,
+ buttons: buttons,
+ down: false,
+ obscured: obscured,
+ pressure: pressure,
+ pressureMin: pressureMin,
+ pressureMax: pressureMax,
+ distance: distance,
+ distanceMax: distanceMax,
+ size: size,
+ radiusMajor: radiusMajor,
+ radiusMinor: radiusMinor,
+ radiusMin: radiusMin,
+ radiusMax: radiusMax,
+ orientation: orientation,
+ tilt: tilt,
+ );
}
diff --git a/packages/flutter/test/gestures/gesture_binding_test.dart b/packages/flutter/test/gestures/gesture_binding_test.dart
index 31f1477..f2924a6 100644
--- a/packages/flutter/test/gestures/gesture_binding_test.dart
+++ b/packages/flutter/test/gestures/gesture_binding_test.dart
@@ -195,13 +195,14 @@
final List<PointerEvent> events = PointerEventConverter.expand(
packet.data, ui.window.devicePixelRatio).toList();
- expect(events.length, 5);
+ expect(events.length, 6);
expect(events[0].runtimeType, equals(PointerAddedEvent));
expect(events[1].runtimeType, equals(PointerHoverEvent));
expect(events[1].delta, equals(const Offset(5.0, 7.0)));
expect(events[2].runtimeType, equals(PointerDownEvent));
expect(events[3].runtimeType, equals(PointerCancelEvent));
- expect(events[4].runtimeType, equals(PointerRemovedEvent));
+ expect(events[4].runtimeType, equals(PointerHoverEvent));
+ expect(events[5].runtimeType, equals(PointerRemovedEvent));
});
test('Can expand pointer scroll events', () {