Switch to PointerData API (#6131)
Now dart:ui does the decoding of the pointer data itself, which means we don't need to do it in the framework.
This commit is contained in:
parent
2a530f78d4
commit
c9eda86b0e
@ -8,10 +8,6 @@
|
||||
import 'dart:ui' as ui;
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:mojo/bindings.dart' as bindings;
|
||||
import 'package:mojo/core.dart' as core;
|
||||
import 'package:flutter_services/pointer.dart';
|
||||
|
||||
ui.Color color;
|
||||
|
||||
ui.Picture paint(ui.Rect paintBounds) {
|
||||
@ -80,26 +76,18 @@ void beginFrame(Duration timeStamp) {
|
||||
ui.window.render(scene);
|
||||
}
|
||||
|
||||
// Pointer input arrives as an array of bytes. The format for the data is
|
||||
// defined by pointer.mojom, which generates serializes and parsers for a
|
||||
// number of languages, including Dart, C++, Java, and Go.
|
||||
void handlePointerPacket(ByteData serializedPacket) {
|
||||
// We wrap the byte data up into a Mojo Message object, which we then
|
||||
// deserialize according to the mojom definition.
|
||||
bindings.Message message = new bindings.Message(serializedPacket, <core.MojoHandle>[], serializedPacket.lengthInBytes, 0);
|
||||
PointerPacket packet = PointerPacket.deserialize(message);
|
||||
|
||||
// The deserialized pointer packet contains a number of pointer movements,
|
||||
// which we iterate through and process.
|
||||
for (Pointer pointer in packet.pointers) {
|
||||
if (pointer.type == PointerType.down) {
|
||||
void handlePointerDataPacket(ui.PointerDataPacket packet) {
|
||||
// The pointer packet contains a number of pointer movements, which we iterate
|
||||
// through and process.
|
||||
for (ui.PointerData pointer in packet.pointers) {
|
||||
if (pointer.change == ui.PointerChange.down) {
|
||||
// If the pointer went down, we change the color of the circle to blue.
|
||||
color = const ui.Color(0xFF0000FF);
|
||||
// Rather than calling paint() synchronously, we ask the engine to
|
||||
// schedule a frame. The engine will call onBeginFrame when it is actually
|
||||
// time to produce the frame.
|
||||
ui.window.scheduleFrame();
|
||||
} else if (pointer.type == PointerType.up) {
|
||||
} else if (pointer.change == ui.PointerChange.up) {
|
||||
// Similarly, if the pointer went up, we change the color of the circle to
|
||||
// green and schedule a frame. It's harmless to call scheduleFrame many
|
||||
// times because the engine will ignore redundant requests up until the
|
||||
@ -117,9 +105,9 @@ void main() {
|
||||
color = const ui.Color(0xFF00FF00);
|
||||
// The engine calls onBeginFrame whenever it wants us to produce a frame.
|
||||
ui.window.onBeginFrame = beginFrame;
|
||||
// The engine calls onPointerPacket whenever it had updated information about
|
||||
// the pointers directed at our app.
|
||||
ui.window.onPointerPacket = handlePointerPacket;
|
||||
// The engine calls onPointerDataPacket whenever it had updated information
|
||||
// about the pointers directed at our app.
|
||||
ui.window.onPointerDataPacket = handlePointerDataPacket;
|
||||
// Here we kick off the whole process by asking the engine to schedule a new
|
||||
// frame. The engine will eventually call onBeginFrame when it is time for us
|
||||
// to actually produce the frame.
|
||||
|
@ -4,13 +4,9 @@
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui' as ui show window;
|
||||
import 'dart:ui' as ui show window, PointerDataPacket;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:mojo/bindings.dart' as mojo_bindings;
|
||||
import 'package:mojo/core.dart' as mojo_core;
|
||||
import 'package:flutter_services/pointer.dart';
|
||||
|
||||
import 'arena.dart';
|
||||
import 'converter.dart';
|
||||
@ -25,21 +21,14 @@ abstract class GestureBinding extends BindingBase implements HitTestable, HitTes
|
||||
void initInstances() {
|
||||
super.initInstances();
|
||||
_instance = this;
|
||||
ui.window.onPointerPacket = _handlePointerPacket;
|
||||
ui.window.onPointerDataPacket = _handlePointerDataPacket;
|
||||
}
|
||||
|
||||
/// The singleton instance of this object.
|
||||
static GestureBinding get instance => _instance;
|
||||
static GestureBinding _instance;
|
||||
|
||||
void _handlePointerPacket(ByteData serializedPacket) {
|
||||
final mojo_bindings.Message message = new mojo_bindings.Message(
|
||||
serializedPacket,
|
||||
<mojo_core.MojoHandle>[],
|
||||
serializedPacket.lengthInBytes,
|
||||
0
|
||||
);
|
||||
final PointerPacket packet = PointerPacket.deserialize(message);
|
||||
void _handlePointerDataPacket(ui.PointerDataPacket packet) {
|
||||
_pendingPointerEvents.addAll(PointerEventConverter.expand(packet.pointers, ui.window.devicePixelRatio));
|
||||
_flushPointerEventQueue();
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_services/pointer.dart' as mojom;
|
||||
import 'dart:ui' as ui show PointerData, PointerChange;
|
||||
|
||||
import 'events.dart';
|
||||
|
||||
@ -37,14 +37,13 @@ class PointerEventConverter {
|
||||
static Map<int, _PointerState> _pointers = <int, _PointerState>{};
|
||||
|
||||
/// Expand the given packet of pointer data into a sequence of framework pointer events.
|
||||
static Iterable<PointerEvent> expand(Iterable<mojom.Pointer> packet, double devicePixelRatio) sync* {
|
||||
for (mojom.Pointer datum in packet) {
|
||||
Point position = new Point(datum.x, datum.y) / devicePixelRatio;
|
||||
Duration timeStamp = new Duration(microseconds: datum.timeStamp);
|
||||
assert(_pointerKindMap.containsKey(datum.kind));
|
||||
PointerDeviceKind kind = _pointerKindMap[datum.kind];
|
||||
switch (datum.type) {
|
||||
case mojom.PointerType.down:
|
||||
static Iterable<PointerEvent> expand(Iterable<ui.PointerData> data, double devicePixelRatio) sync* {
|
||||
for (ui.PointerData datum in data) {
|
||||
final Point position = new Point(datum.physicalX, datum.physicalY) / devicePixelRatio;
|
||||
final Duration timeStamp = datum.timeStamp;
|
||||
final PointerDeviceKind kind = datum.kind;
|
||||
switch (datum.change) {
|
||||
case ui.PointerChange.down:
|
||||
assert(!_pointers.containsKey(datum.pointer));
|
||||
_PointerState state = _pointers.putIfAbsent(
|
||||
datum.pointer,
|
||||
@ -87,7 +86,7 @@ class PointerEventConverter {
|
||||
tilt: datum.tilt
|
||||
);
|
||||
break;
|
||||
case mojom.PointerType.move:
|
||||
case ui.PointerChange.move:
|
||||
// If the service starts supporting hover pointers, then it must also
|
||||
// start sending us ADDED and REMOVED data points.
|
||||
// See also: https://github.com/flutter/flutter/issues/720
|
||||
@ -118,8 +117,8 @@ class PointerEventConverter {
|
||||
tilt: datum.tilt
|
||||
);
|
||||
break;
|
||||
case mojom.PointerType.up:
|
||||
case mojom.PointerType.cancel:
|
||||
case ui.PointerChange.up:
|
||||
case ui.PointerChange.cancel:
|
||||
assert(_pointers.containsKey(datum.pointer));
|
||||
_PointerState state = _pointers[datum.pointer];
|
||||
assert(state.down);
|
||||
@ -156,7 +155,7 @@ class PointerEventConverter {
|
||||
}
|
||||
assert(position == state.lastPosition);
|
||||
state.setUp();
|
||||
if (datum.type == mojom.PointerType.up) {
|
||||
if (datum.change == ui.PointerChange.up) {
|
||||
yield new PointerUpEvent(
|
||||
timeStamp: timeStamp,
|
||||
pointer: state.pointer,
|
||||
@ -210,11 +209,4 @@ class PointerEventConverter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const Map<mojom.PointerKind, PointerDeviceKind> _pointerKindMap = const <mojom.PointerKind, PointerDeviceKind>{
|
||||
mojom.PointerKind.touch: PointerDeviceKind.touch,
|
||||
mojom.PointerKind.mouse: PointerDeviceKind.mouse,
|
||||
mojom.PointerKind.stylus: PointerDeviceKind.stylus,
|
||||
mojom.PointerKind.invertedStylus: PointerDeviceKind.invertedStylus,
|
||||
};
|
||||
}
|
||||
|
@ -2,26 +2,11 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' show Point, Offset;
|
||||
import 'dart:ui' show Point, Offset, PointerDeviceKind;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
export 'dart:ui' show Point, Offset;
|
||||
|
||||
/// The kind of pointer device.
|
||||
enum PointerDeviceKind {
|
||||
/// A touch-based pointer device.
|
||||
touch,
|
||||
|
||||
/// A pointer device with a stylus.
|
||||
stylus,
|
||||
|
||||
/// A pointer device with a stylus that has been inverted.
|
||||
invertedStylus,
|
||||
|
||||
/// A mouse-based pointer device.
|
||||
mouse
|
||||
}
|
||||
export 'dart:ui' show Point, Offset, PointerDeviceKind;
|
||||
|
||||
/// The bit of [PointerEvent.buttons] that corresponds to the primary mouse button.
|
||||
///
|
||||
|
@ -6,8 +6,6 @@ import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:mojo/bindings.dart' as mojo_bindings;
|
||||
import 'package:flutter_services/pointer.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
typedef void HandleEventCallback(PointerEvent event);
|
||||
@ -35,42 +33,35 @@ void main() {
|
||||
setUp(ensureTestGestureBinding);
|
||||
|
||||
test('Pointer tap events', () {
|
||||
mojo_bindings.Encoder encoder = new mojo_bindings.Encoder();
|
||||
|
||||
PointerPacket packet = new PointerPacket();
|
||||
packet.pointers = <Pointer>[new Pointer(), new Pointer()];
|
||||
packet.pointers[0].type = PointerType.down;
|
||||
packet.pointers[0].kind = PointerKind.touch;
|
||||
packet.pointers[1].type = PointerType.up;
|
||||
packet.pointers[1].kind = PointerKind.touch;
|
||||
packet.encode(encoder);
|
||||
ui.PointerDataPacket packet = new ui.PointerDataPacket(
|
||||
pointers: <ui.PointerData>[
|
||||
new ui.PointerData(change: ui.PointerChange.down),
|
||||
new ui.PointerData(change: ui.PointerChange.up),
|
||||
]
|
||||
);
|
||||
|
||||
List<PointerEvent> events = <PointerEvent>[];
|
||||
_binding.callback = (PointerEvent event) => events.add(event);
|
||||
|
||||
ui.window.onPointerPacket(encoder.message.buffer);
|
||||
ui.window.onPointerDataPacket(packet);
|
||||
expect(events.length, 2);
|
||||
expect(events[0].runtimeType, equals(PointerDownEvent));
|
||||
expect(events[1].runtimeType, equals(PointerUpEvent));
|
||||
});
|
||||
|
||||
test('Pointer move events', () {
|
||||
mojo_bindings.Encoder encoder = new mojo_bindings.Encoder();
|
||||
|
||||
PointerPacket packet = new PointerPacket();
|
||||
packet.pointers = <Pointer>[new Pointer(), new Pointer(), new Pointer()];
|
||||
packet.pointers[0].type = PointerType.down;
|
||||
packet.pointers[0].kind = PointerKind.touch;
|
||||
packet.pointers[1].type = PointerType.move;
|
||||
packet.pointers[1].kind = PointerKind.touch;
|
||||
packet.pointers[2].type = PointerType.up;
|
||||
packet.pointers[2].kind = PointerKind.touch;
|
||||
packet.encode(encoder);
|
||||
ui.PointerDataPacket packet = new ui.PointerDataPacket(
|
||||
pointers: <ui.PointerData>[
|
||||
new ui.PointerData(change: ui.PointerChange.down),
|
||||
new ui.PointerData(change: ui.PointerChange.move),
|
||||
new ui.PointerData(change: ui.PointerChange.up),
|
||||
]
|
||||
);
|
||||
|
||||
List<PointerEvent> events = <PointerEvent>[];
|
||||
_binding.callback = (PointerEvent event) => events.add(event);
|
||||
|
||||
ui.window.onPointerPacket(encoder.message.buffer);
|
||||
ui.window.onPointerDataPacket(packet);
|
||||
expect(events.length, 3);
|
||||
expect(events[0].runtimeType, equals(PointerDownEvent));
|
||||
expect(events[1].runtimeType, equals(PointerMoveEvent));
|
||||
@ -78,26 +69,25 @@ void main() {
|
||||
});
|
||||
|
||||
test('Synthetic move events', () {
|
||||
mojo_bindings.Encoder encoder = new mojo_bindings.Encoder();
|
||||
|
||||
PointerPacket packet = new PointerPacket();
|
||||
packet.pointers = <Pointer>[new Pointer(), new Pointer()];
|
||||
packet.pointers[0]
|
||||
..type = PointerType.down
|
||||
..kind = PointerKind.touch
|
||||
..x = 1.0
|
||||
..y = 3.0;
|
||||
packet.pointers[1]
|
||||
..type = PointerType.up
|
||||
..kind = PointerKind.touch
|
||||
..x = 10.0
|
||||
..y = 15.0;
|
||||
packet.encode(encoder);
|
||||
ui.PointerDataPacket packet = new ui.PointerDataPacket(
|
||||
pointers: <ui.PointerData>[
|
||||
new ui.PointerData(
|
||||
change: ui.PointerChange.down,
|
||||
physicalX: 1.0,
|
||||
physicalY: 3.0,
|
||||
),
|
||||
new ui.PointerData(
|
||||
change: ui.PointerChange.up,
|
||||
physicalX: 10.0,
|
||||
physicalY: 15.0,
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
List<PointerEvent> events = <PointerEvent>[];
|
||||
_binding.callback = (PointerEvent event) => events.add(event);
|
||||
|
||||
ui.window.onPointerPacket(encoder.message.buffer);
|
||||
ui.window.onPointerDataPacket(packet);
|
||||
expect(events.length, 3);
|
||||
expect(events[0].runtimeType, equals(PointerDownEvent));
|
||||
expect(events[1].runtimeType, equals(PointerMoveEvent));
|
||||
@ -106,35 +96,29 @@ void main() {
|
||||
});
|
||||
|
||||
test('Pointer cancel events', () {
|
||||
mojo_bindings.Encoder encoder = new mojo_bindings.Encoder();
|
||||
|
||||
PointerPacket packet = new PointerPacket();
|
||||
packet.pointers = <Pointer>[new Pointer(), new Pointer()];
|
||||
packet.pointers[0].type = PointerType.down;
|
||||
packet.pointers[0].kind = PointerKind.touch;
|
||||
packet.pointers[1].type = PointerType.cancel;
|
||||
packet.pointers[1].kind = PointerKind.touch;
|
||||
packet.encode(encoder);
|
||||
ui.PointerDataPacket packet = new ui.PointerDataPacket(
|
||||
pointers: <ui.PointerData>[
|
||||
new ui.PointerData(change: ui.PointerChange.down),
|
||||
new ui.PointerData(change: ui.PointerChange.cancel),
|
||||
]
|
||||
);
|
||||
|
||||
List<PointerEvent> events = <PointerEvent>[];
|
||||
_binding.callback = (PointerEvent event) => events.add(event);
|
||||
|
||||
ui.window.onPointerPacket(encoder.message.buffer);
|
||||
ui.window.onPointerDataPacket(packet);
|
||||
expect(events.length, 2);
|
||||
expect(events[0].runtimeType, equals(PointerDownEvent));
|
||||
expect(events[1].runtimeType, equals(PointerCancelEvent));
|
||||
});
|
||||
|
||||
test('Can cancel pointers', () {
|
||||
mojo_bindings.Encoder encoder = new mojo_bindings.Encoder();
|
||||
|
||||
PointerPacket packet = new PointerPacket();
|
||||
packet.pointers = <Pointer>[new Pointer(), new Pointer()];
|
||||
packet.pointers[0].type = PointerType.down;
|
||||
packet.pointers[0].kind = PointerKind.touch;
|
||||
packet.pointers[1].type = PointerType.up;
|
||||
packet.pointers[1].kind = PointerKind.touch;
|
||||
packet.encode(encoder);
|
||||
ui.PointerDataPacket packet = new ui.PointerDataPacket(
|
||||
pointers: <ui.PointerData>[
|
||||
new ui.PointerData(change: ui.PointerChange.down),
|
||||
new ui.PointerData(change: ui.PointerChange.up),
|
||||
]
|
||||
);
|
||||
|
||||
List<PointerEvent> events = <PointerEvent>[];
|
||||
_binding.callback = (PointerEvent event) {
|
||||
@ -143,7 +127,7 @@ void main() {
|
||||
_binding.cancelPointer(event.pointer);
|
||||
};
|
||||
|
||||
ui.window.onPointerPacket(encoder.message.buffer);
|
||||
ui.window.onPointerDataPacket(packet);
|
||||
expect(events.length, 2);
|
||||
expect(events[0].runtimeType, equals(PointerDownEvent));
|
||||
expect(events[1].runtimeType, equals(PointerCancelEvent));
|
||||
|
Loading…
x
Reference in New Issue
Block a user