未验证 提交 3e6d6bc6 编写于 作者: C chunhtai 提交者: GitHub

add pointer data santizing in flutter web engine (#14082)

上级 90e28c02
......@@ -417,6 +417,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/picture.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/platform_views.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/plugins.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/pointer_binding.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/pointer_converter.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/recording_canvas.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/render_vertices.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/rrect_renderer.dart
......
......@@ -62,6 +62,7 @@ part 'engine/picture.dart';
part 'engine/platform_views.dart';
part 'engine/plugins.dart';
part 'engine/pointer_binding.dart';
part 'engine/pointer_converter.dart';
part 'engine/recording_canvas.dart';
part 'engine/render_vertices.dart';
part 'engine/rrect_renderer.dart';
......
......@@ -15,23 +15,17 @@ class PointerBinding {
static PointerBinding get instance => _instance;
static PointerBinding _instance;
// Set of pointerIds that are added before routing hover and mouse wheel
// events.
//
// The device needs to send a one time PointerChange.add before hover and
// wheel events.
Set<int> _activePointerIds = <int>{};
PointerBinding(this.domRenderer) {
if (_instance == null) {
_instance = this;
_pointerDataConverter = PointerDataConverter();
_detector = const PointerSupportDetector();
_adapter = _createAdapter();
}
assert(() {
registerHotRestartListener(() {
_adapter?.clearListeners();
_activePointerIds.clear();
_pointerDataConverter?.clearPointerState();
});
return true;
}());
......@@ -40,7 +34,7 @@ class PointerBinding {
final DomRenderer domRenderer;
PointerSupportDetector _detector;
BaseAdapter _adapter;
PointerDataConverter _pointerDataConverter;
/// Should be used in tests to define custom detection of pointer support.
///
/// ```dart
......@@ -62,22 +56,22 @@ class PointerBinding {
newDetector ??= const PointerSupportDetector();
// When changing the detector, we need to swap the adapter.
if (newDetector != _detector) {
_activePointerIds.clear();
_detector = newDetector;
_adapter?.clearListeners();
_adapter = _createAdapter();
_pointerDataConverter?.clearPointerState();
}
}
BaseAdapter _createAdapter() {
if (_detector.hasPointerEvents) {
return PointerAdapter(_onPointerData, domRenderer);
return PointerAdapter(_onPointerData, domRenderer, _pointerDataConverter);
}
if (_detector.hasTouchEvents) {
return TouchAdapter(_onPointerData, domRenderer);
return TouchAdapter(_onPointerData, domRenderer, _pointerDataConverter);
}
if (_detector.hasMouseEvents) {
return MouseAdapter(_onPointerData, domRenderer);
return MouseAdapter(_onPointerData, domRenderer, _pointerDataConverter);
}
return null;
}
......@@ -123,11 +117,19 @@ class _PressedButton {
/// Common functionality that's shared among adapters.
abstract class BaseAdapter {
static final Map<String, html.EventListener> _listeners =
<String, html.EventListener>{};
BaseAdapter(this._callback, this.domRenderer, this._pointerDataConverter) {
_setup();
}
/// Listeners that are registered through dart to js api.
static final Map<String, html.EventListener> _listeners =
<String, html.EventListener>{};
/// Listeners that are registered through native javascript api.
static final Map<String, html.EventListener> _nativeListeners =
<String, html.EventListener>{};
final DomRenderer domRenderer;
PointerDataCallback _callback;
PointerDataConverter _pointerDataConverter;
// A set of the buttons that are currently being pressed.
Set<_PressedButton> _pressedButtons = Set<_PressedButton>();
......@@ -144,10 +146,6 @@ abstract class BaseAdapter {
}
}
BaseAdapter(this._callback, this.domRenderer) {
_setup();
}
/// Each subclass is expected to override this method to attach its own event
/// listeners and convert events into pointer events.
void _setup();
......@@ -156,9 +154,21 @@ abstract class BaseAdapter {
void clearListeners() {
final html.Element glassPane = domRenderer.glassPaneElement;
_listeners.forEach((String eventName, html.EventListener listener) {
glassPane.removeEventListener(eventName, listener, true);
glassPane.removeEventListener(eventName, listener, true);
});
// For native listener, we will need to remove it through native javascript
// api.
_nativeListeners.forEach((String eventName, html.EventListener listener) {
js_util.callMethod(
domRenderer.glassPaneElement,
'removeEventListener', <dynamic>[
'wheel',
listener,
]
);
});
_listeners.clear();
_nativeListeners.clear();
}
void _addEventListener(String eventName, html.EventListener handler) {
......@@ -177,6 +187,75 @@ abstract class BaseAdapter {
domRenderer.glassPaneElement
.addEventListener(eventName, loggedHandler, true);
}
/// Converts a floating number timestamp (in milliseconds) to a [Duration] by
/// splitting it into two integer components: milliseconds + microseconds.
Duration _eventTimeStampToDuration(num milliseconds) {
final int ms = milliseconds.toInt();
final int micro =
((milliseconds - ms) * Duration.microsecondsPerMillisecond).toInt();
return Duration(milliseconds: ms, microseconds: micro);
}
List<ui.PointerData> _convertWheelEventToPointerData(
html.WheelEvent event,
) {
const int domDeltaPixel = 0x00;
const int domDeltaLine = 0x01;
const int domDeltaPage = 0x02;
// Flutter only supports pixel scroll delta. Convert deltaMode values
// to pixels.
double deltaX = event.deltaX;
double deltaY = event.deltaY;
switch (event.deltaMode) {
case domDeltaLine:
deltaX *= 32.0;
deltaY *= 32.0;
break;
case domDeltaPage:
deltaX *= ui.window.physicalSize.width;
deltaY *= ui.window.physicalSize.height;
break;
case domDeltaPixel:
default:
break;
}
final List<ui.PointerData> data = <ui.PointerData>[];
_pointerDataConverter.convert(
data,
change: ui.PointerChange.hover,
timeStamp: _eventTimeStampToDuration(event.timeStamp),
kind: ui.PointerDeviceKind.mouse,
signalKind: ui.PointerSignalKind.scroll,
device: _mouseDeviceId,
physicalX: event.client.x * ui.window.devicePixelRatio,
physicalY: event.client.y * ui.window.devicePixelRatio,
buttons: event.buttons,
pressure: 1.0,
pressureMin: 0.0,
pressureMax: 1.0,
scrollDeltaX: deltaX,
scrollDeltaY: deltaY,
);
return data;
}
void _addWheelEventListener(html.EventListener handler) {
final dynamic eventOptions = js_util.newObject();
final html.EventListener jsHandler = js.allowInterop((html.Event event) => handler(event));
_nativeListeners['wheel'] = jsHandler;
js_util.setProperty(eventOptions, 'passive', false);
js_util.callMethod(
domRenderer.glassPaneElement,
'addEventListener', <dynamic>[
'wheel',
jsHandler,
eventOptions
]
);
}
}
const int _kPrimaryMouseButton = 0x1;
......@@ -207,16 +286,17 @@ int _deviceFromHtmlEvent(event) {
/// Adapter class to be used with browsers that support native pointer events.
class PointerAdapter extends BaseAdapter {
PointerAdapter(PointerDataCallback callback, DomRenderer domRenderer)
: super(callback, domRenderer);
PointerAdapter(
PointerDataCallback callback,
DomRenderer domRenderer,
PointerDataConverter _pointerDataConverter
) : super(callback, domRenderer, _pointerDataConverter);
@override
void _setup() {
_addEventListener('pointerdown', (html.Event event) {
final int pointerButton = _pointerButtonFromHtmlEvent(event);
final int device = _deviceFromHtmlEvent(event);
// The pointerdown event will cause an 'add' event on the framework side.
PointerBinding._instance._activePointerIds.add(device);
if (_isButtonDown(device, pointerButton)) {
// TODO(flutter_web): Remove this temporary fix for right click
// on web platform once context guesture is implemented.
......@@ -239,13 +319,6 @@ class PointerAdapter extends BaseAdapter {
? ui.PointerChange.move
: ui.PointerChange.hover,
pointerEvent);
_ensureMouseDeviceAdded(
data,
pointerEvent.client.x,
pointerEvent.client.y,
pointerEvent.buttons,
pointerEvent.timeStamp,
pointerEvent.pointerId);
_callback(data);
});
......@@ -270,7 +343,8 @@ class PointerAdapter extends BaseAdapter {
_callback(_convertEventToPointerData(ui.PointerChange.cancel, event));
});
_addWheelEventListener((html.WheelEvent event) {
_addWheelEventListener((html.Event event) {
assert(event is html.WheelEvent);
if (_debugLogPointerEvents) {
print(event.type);
}
......@@ -289,7 +363,8 @@ class PointerAdapter extends BaseAdapter {
final List<ui.PointerData> data = <ui.PointerData>[];
for (int i = 0; i < allEvents.length; i++) {
final html.PointerEvent event = allEvents[i];
data.add(ui.PointerData(
_pointerDataConverter.convert(
data,
change: change,
timeStamp: _eventTimeStampToDuration(event.timeStamp),
kind: _pointerTypeToDeviceKind(event.pointerType),
......@@ -301,7 +376,7 @@ class PointerAdapter extends BaseAdapter {
pressureMin: 0.0,
pressureMax: 1.0,
tilt: _computeHighestTilt(event),
));
);
}
return data;
}
......@@ -343,8 +418,11 @@ class PointerAdapter extends BaseAdapter {
/// Adapter to be used with browsers that support touch events.
class TouchAdapter extends BaseAdapter {
TouchAdapter(PointerDataCallback callback, DomRenderer domRenderer)
: super(callback, domRenderer);
TouchAdapter(
PointerDataCallback callback,
DomRenderer domRenderer,
PointerDataConverter _pointerDataConverter
) : super(callback, domRenderer, _pointerDataConverter);
@override
void _setup() {
......@@ -381,11 +459,12 @@ class TouchAdapter extends BaseAdapter {
html.TouchEvent event,
) {
final html.TouchList touches = event.changedTouches;
final List<ui.PointerData> data = List<ui.PointerData>(touches.length);
final List<ui.PointerData> data = List<ui.PointerData>();
final int len = touches.length;
for (int i = 0; i < len; i++) {
final html.Touch touch = touches[i];
data[i] = ui.PointerData(
_pointerDataConverter.convert(
data,
change: change,
timeStamp: _eventTimeStampToDuration(event.timeStamp),
kind: ui.PointerDeviceKind.touch,
......@@ -408,8 +487,11 @@ const int _mouseDeviceId = -1;
/// Adapter to be used with browsers that support mouse events.
class MouseAdapter extends BaseAdapter {
MouseAdapter(PointerDataCallback callback, DomRenderer domRenderer)
: super(callback, domRenderer);
MouseAdapter(
PointerDataCallback callback,
DomRenderer domRenderer,
PointerDataConverter _pointerDataConverter
) : super(callback, domRenderer, _pointerDataConverter);
@override
void _setup() {
......@@ -442,7 +524,8 @@ class MouseAdapter extends BaseAdapter {
_callback(_convertEventToPointerData(ui.PointerChange.up, event));
});
_addWheelEventListener((html.WheelEvent event) {
_addWheelEventListener((html.Event event) {
assert(event is html.WheelEvent);
if (_debugLogPointerEvents) {
print(event.type);
}
......@@ -455,16 +538,9 @@ class MouseAdapter extends BaseAdapter {
ui.PointerChange change,
html.MouseEvent event,
) {
final List<ui.PointerData> data = <ui.PointerData>[];
// The mousedown event will cause an 'add' event on the framework side.
if (event.type == 'mousedown') {
PointerBinding._instance._activePointerIds.add(_mouseDeviceId);
}
if (event.type == 'mousemove') {
_ensureMouseDeviceAdded(data, event.client.x, event.client.y,
event.buttons, event.timeStamp, _mouseDeviceId);
}
data.add(ui.PointerData(
List<ui.PointerData> data = <ui.PointerData>[];
_pointerDataConverter.convert(
data,
change: change,
timeStamp: _eventTimeStampToDuration(event.timeStamp),
kind: ui.PointerDeviceKind.mouse,
......@@ -476,101 +552,7 @@ class MouseAdapter extends BaseAdapter {
pressure: 1.0,
pressureMin: 0.0,
pressureMax: 1.0,
));
);
return data;
}
}
/// Convert a floating number timestamp (in milliseconds) to a [Duration] by
/// splitting it into two integer components: milliseconds + microseconds.
Duration _eventTimeStampToDuration(num milliseconds) {
final int ms = milliseconds.toInt();
final int micro =
((milliseconds - ms) * Duration.microsecondsPerMillisecond).toInt();
return Duration(milliseconds: ms, microseconds: micro);
}
void _ensureMouseDeviceAdded(List<ui.PointerData> data, double clientX,
double clientY, int buttons, double timeStamp, int deviceId) {
if (PointerBinding.instance._activePointerIds.contains(deviceId)) {
return;
}
PointerBinding.instance._activePointerIds.add(deviceId);
// Only send [PointerChange.add] the first time.
data.insert(
0,
ui.PointerData(
change: ui.PointerChange.add,
timeStamp: _eventTimeStampToDuration(timeStamp),
kind: ui.PointerDeviceKind.mouse,
// In order for Flutter to actually add this pointer, we need to set the
// signal to none.
signalKind: ui.PointerSignalKind.none,
device: deviceId,
physicalX: clientX * ui.window.devicePixelRatio,
physicalY: clientY * ui.window.devicePixelRatio,
buttons: buttons,
pressure: 1.0,
pressureMin: 0.0,
pressureMax: 1.0,
scrollDeltaX: 0,
scrollDeltaY: 0,
));
}
List<ui.PointerData> _convertWheelEventToPointerData(
html.WheelEvent event,
) {
const int domDeltaPixel = 0x00;
const int domDeltaLine = 0x01;
const int domDeltaPage = 0x02;
// Flutter only supports pixel scroll delta. Convert deltaMode values
// to pixels.
double deltaX = event.deltaX;
double deltaY = event.deltaY;
switch (event.deltaMode) {
case domDeltaLine:
deltaX *= 32.0;
deltaY *= 32.0;
break;
case domDeltaPage:
deltaX *= ui.window.physicalSize.width;
deltaY *= ui.window.physicalSize.height;
break;
case domDeltaPixel:
default:
break;
}
final List<ui.PointerData> data = <ui.PointerData>[];
_ensureMouseDeviceAdded(data, event.client.x, event.client.y, event.buttons,
event.timeStamp, _mouseDeviceId);
data.add(ui.PointerData(
change: ui.PointerChange.hover,
timeStamp: _eventTimeStampToDuration(event.timeStamp),
kind: ui.PointerDeviceKind.mouse,
signalKind: ui.PointerSignalKind.scroll,
device: _mouseDeviceId,
physicalX: event.client.x * ui.window.devicePixelRatio,
physicalY: event.client.y * ui.window.devicePixelRatio,
buttons: event.buttons,
pressure: 1.0,
pressureMin: 0.0,
pressureMax: 1.0,
scrollDeltaX: deltaX,
scrollDeltaY: deltaY,
));
return data;
}
void _addWheelEventListener(void listener(html.WheelEvent e)) {
final dynamic eventOptions = js_util.newObject();
js_util.setProperty(eventOptions, 'passive', false);
js_util.callMethod(PointerBinding.instance.domRenderer.glassPaneElement,
'addEventListener', <dynamic>[
'wheel',
js.allowInterop((html.WheelEvent event) => listener(event)),
eventOptions
]);
}
此差异已折叠。
......@@ -56,7 +56,11 @@ void main() {
}));
expect(packets, hasLength(3));
expect(packets[0].data[0].change, equals(ui.PointerChange.down));
// An add will be synthesized.
expect(packets[0].data, hasLength(2));
expect(packets[0].data[0].change, equals(ui.PointerChange.add));
expect(packets[0].data[0].synthesized, equals(true));
expect(packets[0].data[1].change, equals(ui.PointerChange.down));
expect(packets[1].data[0].change, equals(ui.PointerChange.up));
expect(packets[2].data[0].change, equals(ui.PointerChange.down));
});
......@@ -78,10 +82,20 @@ void main() {
}));
expect(packets, hasLength(2));
expect(packets[0].data[0].change, equals(ui.PointerChange.down));
// An add will be synthesized.
expect(packets[0].data, hasLength(2));
expect(packets[0].data[0].change, equals(ui.PointerChange.add));
expect(packets[0].data[0].synthesized, equals(true));
expect(packets[0].data[0].device, equals(1));
expect(packets[1].data[0].change, equals(ui.PointerChange.down));
expect(packets[0].data[1].change, equals(ui.PointerChange.down));
expect(packets[0].data[1].device, equals(1));
// An add will be synthesized.
expect(packets[1].data, hasLength(2));
expect(packets[1].data[0].change, equals(ui.PointerChange.add));
expect(packets[1].data[0].synthesized, equals(true));
expect(packets[1].data[0].device, equals(2));
expect(packets[1].data[1].change, equals(ui.PointerChange.down));
expect(packets[1].data[1].device, equals(2));
});
test('creates an add event if the first pointer activity is a hover', () {
......@@ -99,10 +113,11 @@ void main() {
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.hover));
});
test('does not create an add event if got a pointerdown', () {
test('does create an add event if got a pointerdown', () {
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
......@@ -114,9 +129,247 @@ void main() {
}));
expect(packets, hasLength(1));
expect(packets.single.data, hasLength(1));
expect(packets.single.data, hasLength(2));
expect(packets.single.data[0].change, equals(ui.PointerChange.add));
expect(packets.single.data[1].change, equals(ui.PointerChange.down));
});
test('does calculate delta and pointer identifier correctly', () {
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
glassPane.dispatchEvent(html.PointerEvent('pointermove', {
'pointerId': 1,
'button': 1,
'clientX': 10.0,
'clientY': 10.0,
}));
glassPane.dispatchEvent(html.PointerEvent('pointermove', {
'pointerId': 1,
'button': 1,
'clientX': 20.0,
'clientY': 20.0,
}));
glassPane.dispatchEvent(html.PointerEvent('pointerdown', {
'pointerId': 1,
'button': 1,
'clientX': 20.0,
'clientY': 20.0,
}));
glassPane.dispatchEvent(html.PointerEvent('pointermove', {
'pointerId': 1,
'button': 1,
'clientX': 40.0,
'clientY': 30.0,
}));
glassPane.dispatchEvent(html.PointerEvent('pointerup', {
'pointerId': 1,
'button': 1,
'clientX': 40.0,
'clientY': 30.0,
}));
glassPane.dispatchEvent(html.PointerEvent('pointermove', {
'pointerId': 1,
'button': 1,
'clientX': 20.0,
'clientY': 10.0,
}));
glassPane.dispatchEvent(html.PointerEvent('pointerdown', {
'pointerId': 1,
'button': 1,
'clientX': 20.0,
'clientY': 10.0,
}));
expect(packets, hasLength(7));
expect(packets[0].data, hasLength(2));
expect(packets[0].data[0].change, equals(ui.PointerChange.add));
expect(packets[0].data[0].pointerIdentifier, equals(0));
expect(packets[0].data[0].synthesized, equals(true));
expect(packets[0].data[0].physicalX, equals(10.0));
expect(packets[0].data[0].physicalY, equals(10.0));
expect(packets[0].data[0].physicalDeltaX, equals(0.0));
expect(packets[0].data[0].physicalDeltaY, equals(0.0));
expect(packets[0].data[1].change, equals(ui.PointerChange.hover));
expect(packets[0].data[1].pointerIdentifier, equals(0));
expect(packets[0].data[1].synthesized, equals(false));
expect(packets[0].data[1].physicalX, equals(10.0));
expect(packets[0].data[1].physicalY, equals(10.0));
expect(packets[0].data[1].physicalDeltaX, equals(0.0));
expect(packets[0].data[1].physicalDeltaY, equals(0.0));
expect(packets[1].data, hasLength(1));
expect(packets[1].data[0].change, equals(ui.PointerChange.hover));
expect(packets[1].data[0].pointerIdentifier, equals(0));
expect(packets[1].data[0].synthesized, equals(false));
expect(packets[1].data[0].physicalX, equals(20.0));
expect(packets[1].data[0].physicalY, equals(20.0));
expect(packets[1].data[0].physicalDeltaX, equals(10.0));
expect(packets[1].data[0].physicalDeltaY, equals(10.0));
expect(packets[2].data, hasLength(1));
expect(packets[2].data[0].change, equals(ui.PointerChange.down));
expect(packets[2].data[0].pointerIdentifier, equals(1));
expect(packets[2].data[0].synthesized, equals(false));
expect(packets[2].data[0].physicalX, equals(20.0));
expect(packets[2].data[0].physicalY, equals(20.0));
expect(packets[2].data[0].physicalDeltaX, equals(0.0));
expect(packets[2].data[0].physicalDeltaY, equals(0.0));
expect(packets[3].data, hasLength(1));
expect(packets[3].data[0].change, equals(ui.PointerChange.move));
expect(packets[3].data[0].pointerIdentifier, equals(1));
expect(packets[3].data[0].synthesized, equals(false));
expect(packets[3].data[0].physicalX, equals(40.0));
expect(packets[3].data[0].physicalY, equals(30.0));
expect(packets[3].data[0].physicalDeltaX, equals(20.0));
expect(packets[3].data[0].physicalDeltaY, equals(10.0));
expect(packets[4].data, hasLength(1));
expect(packets[4].data[0].change, equals(ui.PointerChange.up));
expect(packets[4].data[0].pointerIdentifier, equals(1));
expect(packets[4].data[0].synthesized, equals(false));
expect(packets[4].data[0].physicalX, equals(40.0));
expect(packets[4].data[0].physicalY, equals(30.0));
expect(packets[4].data[0].physicalDeltaX, equals(0.0));
expect(packets[4].data[0].physicalDeltaY, equals(0.0));
expect(packets[5].data, hasLength(1));
expect(packets[5].data[0].change, equals(ui.PointerChange.hover));
expect(packets[5].data[0].pointerIdentifier, equals(1));
expect(packets[5].data[0].synthesized, equals(false));
expect(packets[5].data[0].physicalX, equals(20.0));
expect(packets[5].data[0].physicalY, equals(10.0));
expect(packets[5].data[0].physicalDeltaX, equals(-20.0));
expect(packets[5].data[0].physicalDeltaY, equals(-20.0));
expect(packets[6].data, hasLength(1));
expect(packets[6].data[0].change, equals(ui.PointerChange.down));
expect(packets[6].data[0].pointerIdentifier, equals(2));
expect(packets[6].data[0].synthesized, equals(false));
expect(packets[6].data[0].physicalX, equals(20.0));
expect(packets[6].data[0].physicalY, equals(10.0));
expect(packets[6].data[0].physicalDeltaX, equals(0.0));
expect(packets[6].data[0].physicalDeltaY, equals(0.0));
});
test('does synthesize add or hover or more for scroll', () {
List<ui.PointerDataPacket> packets = <ui.PointerDataPacket>[];
ui.window.onPointerDataPacket = (ui.PointerDataPacket packet) {
packets.add(packet);
};
glassPane.dispatchEvent(html.WheelEvent('wheel',
button: 1,
clientX: 10,
clientY: 10,
deltaX: 10,
deltaY: 10,
));
glassPane.dispatchEvent(html.WheelEvent('wheel',
button: 1,
clientX: 20,
clientY: 50,
deltaX: 10,
deltaY: 10,
));
glassPane.dispatchEvent(html.PointerEvent('pointerdown', {
'pointerId': -1,
'button': 1,
'clientX': 20.0,
'clientY': 50.0,
}));
glassPane.dispatchEvent(html.WheelEvent('wheel',
button: 1,
clientX: 30,
clientY: 60,
deltaX: 10,
deltaY: 10,
));
expect(packets, hasLength(4));
// An add will be synthesized.
expect(packets[0].data, hasLength(2));
expect(packets[0].data[0].change, equals(ui.PointerChange.add));
expect(packets[0].data[0].pointerIdentifier, equals(0));
expect(packets[0].data[0].synthesized, equals(true));
expect(packets[0].data[0].physicalX, equals(10.0));
expect(packets[0].data[0].physicalY, equals(10.0));
expect(packets[0].data[0].physicalDeltaX, equals(0.0));
expect(packets[0].data[0].physicalDeltaY, equals(0.0));
expect(packets[0].data[1].change, equals(ui.PointerChange.hover));
expect(packets[0].data[1].signalKind, equals(ui.PointerSignalKind.scroll));
expect(packets[0].data[1].pointerIdentifier, equals(0));
expect(packets[0].data[1].synthesized, equals(false));
expect(packets[0].data[1].physicalX, equals(10.0));
expect(packets[0].data[1].physicalY, equals(10.0));
expect(packets[0].data[1].physicalDeltaX, equals(0.0));
expect(packets[0].data[1].physicalDeltaY, equals(0.0));
// A hover will be synthesized.
expect(packets[1].data, hasLength(2));
expect(packets[1].data[0].change, equals(ui.PointerChange.hover));
expect(packets[1].data[0].pointerIdentifier, equals(0));
expect(packets[1].data[0].synthesized, equals(true));
expect(packets[1].data[0].physicalX, equals(20.0));
expect(packets[1].data[0].physicalY, equals(50.0));
expect(packets[1].data[0].physicalDeltaX, equals(10.0));
expect(packets[1].data[0].physicalDeltaY, equals(40.0));
expect(packets[1].data[1].change, equals(ui.PointerChange.hover));
expect(packets[1].data[1].signalKind, equals(ui.PointerSignalKind.scroll));
expect(packets[1].data[1].pointerIdentifier, equals(0));
expect(packets[1].data[1].synthesized, equals(false));
expect(packets[1].data[1].physicalX, equals(20.0));
expect(packets[1].data[1].physicalY, equals(50.0));
expect(packets[1].data[1].physicalDeltaX, equals(0.0));
expect(packets[1].data[1].physicalDeltaY, equals(0.0));
// No synthetic pointer data for down event.
expect(packets[2].data, hasLength(1));
expect(packets[2].data[0].change, equals(ui.PointerChange.down));
expect(packets[2].data[0].signalKind, equals(null));
expect(packets[2].data[0].pointerIdentifier, equals(1));
expect(packets[2].data[0].synthesized, equals(false));
expect(packets[2].data[0].physicalX, equals(20.0));
expect(packets[2].data[0].physicalY, equals(50.0));
expect(packets[2].data[0].physicalDeltaX, equals(0.0));
expect(packets[2].data[0].physicalDeltaY, equals(0.0));
// A move will be synthesized instead of hover because the button is currently down.
expect(packets[3].data, hasLength(2));
expect(packets[3].data[0].change, equals(ui.PointerChange.move));
expect(packets[3].data[0].pointerIdentifier, equals(1));
expect(packets[3].data[0].synthesized, equals(true));
expect(packets[3].data[0].physicalX, equals(30.0));
expect(packets[3].data[0].physicalY, equals(60.0));
expect(packets[3].data[0].physicalDeltaX, equals(10.0));
expect(packets[3].data[0].physicalDeltaY, equals(10.0));
expect(packets.single.data[0].change, equals(ui.PointerChange.down));
expect(packets[3].data[1].change, equals(ui.PointerChange.hover));
expect(packets[3].data[1].signalKind, equals(ui.PointerSignalKind.scroll));
expect(packets[3].data[1].pointerIdentifier, equals(1));
expect(packets[3].data[1].synthesized, equals(false));
expect(packets[3].data[1].physicalX, equals(30.0));
expect(packets[3].data[1].physicalY, equals(60.0));
expect(packets[3].data[1].physicalDeltaX, equals(0.0));
expect(packets[3].data[1].physicalDeltaY, equals(0.0));
});
});
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册