Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 2062e57

Browse files
authored
Add trackpad gesture PointerData types (#28571)
* Implement trackpad gestures in engine * Remove the platform implementations * Add new device type for trackpad * Add back the necessary changes for Android * Address feedback * Fix doc typos
1 parent fe08734 commit 2062e57

File tree

13 files changed

+356
-6
lines changed

13 files changed

+356
-6
lines changed

lib/ui/platform_dispatcher.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ class PlatformDispatcher {
341341
// * pointer_data.cc
342342
// * pointer.dart
343343
// * AndroidTouchProcessor.java
344-
static const int _kPointerDataFieldCount = 29;
344+
static const int _kPointerDataFieldCount = 35;
345345

346346
static PointerDataPacket _unpackPointerDataPacket(ByteData packet) {
347347
const int kStride = Int64List.bytesPerElement;
@@ -381,6 +381,12 @@ class PlatformDispatcher {
381381
platformData: packet.getInt64(kStride * offset++, _kFakeHostEndian),
382382
scrollDeltaX: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
383383
scrollDeltaY: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
384+
panX: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
385+
panY: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
386+
panDeltaX: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
387+
panDeltaY: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
388+
scale: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
389+
rotation: packet.getFloat64(kStride * offset++, _kFakeHostEndian),
384390
));
385391
assert(offset == (i + 1) * _kPointerDataFieldCount);
386392
}

lib/ui/pointer.dart

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ enum PointerChange {
3636

3737
/// The pointer has stopped making contact with the device.
3838
up,
39+
40+
/// A pan/zoom has started on this pointer.
41+
panZoomStart,
42+
43+
/// The pan/zoom on this pointer has updated.
44+
panZoomUpdate,
45+
46+
/// The pan/zoom on this pointer has ended.
47+
panZoomEnd,
3948
}
4049

4150
/// The kind of pointer device.
@@ -52,6 +61,9 @@ enum PointerDeviceKind {
5261
/// A pointer device with a stylus that has been inverted.
5362
invertedStylus,
5463

64+
/// A touch-based pointer device with an indirect surface.
65+
trackpad,
66+
5567
/// An unknown pointer device.
5668
unknown
5769
}
@@ -101,6 +113,12 @@ class PointerData {
101113
this.platformData = 0,
102114
this.scrollDeltaX = 0.0,
103115
this.scrollDeltaY = 0.0,
116+
this.panX = 0.0,
117+
this.panY = 0.0,
118+
this.panDeltaX = 0.0,
119+
this.panDeltaY = 0.0,
120+
this.scale = 0.0,
121+
this.rotation = 0.0,
104122
});
105123

106124
/// Unique identifier that ties the [PointerEvent] to embedder event created it.
@@ -265,6 +283,40 @@ class PointerData {
265283
/// The amount to scroll in the y direction, in physical pixels.
266284
final double scrollDeltaY;
267285

286+
/// For events with change of PointerChange.panZoomUpdate:
287+
///
288+
/// The current panning magnitude of the pan/zoom in the x direction, in
289+
/// physical pixels.
290+
final double panX;
291+
292+
/// For events with change of PointerChange.panZoomUpdate:
293+
///
294+
/// The current panning magnitude of the pan/zoom in the y direction, in
295+
/// physical pixels.
296+
final double panY;
297+
298+
/// For events with change of PointerChange.panZoomUpdate:
299+
///
300+
/// The difference in panning of the pan/zoom in the x direction since the
301+
/// latest panZoomUpdate event, in physical pixels.
302+
final double panDeltaX;
303+
304+
/// For events with change of PointerChange.panZoomUpdate:
305+
///
306+
/// The difference in panning of the pan/zoom in the y direction since the
307+
/// last panZoomUpdate event, in physical pixels.
308+
final double panDeltaY;
309+
310+
/// For events with change of PointerChange.panZoomUpdate:
311+
///
312+
/// The current scale of the pan/zoom (unitless), with 1.0 as the initial scale.
313+
final double scale;
314+
315+
/// For events with change of PointerChange.panZoomUpdate:
316+
///
317+
/// The current angle of the pan/zoom in radians, with 0.0 as the initial angle.
318+
final double rotation;
319+
268320
@override
269321
String toString() => 'PointerData(x: $physicalX, y: $physicalY)';
270322

@@ -298,7 +350,13 @@ class PointerData {
298350
'tilt: $tilt, '
299351
'platformData: $platformData, '
300352
'scrollDeltaX: $scrollDeltaX, '
301-
'scrollDeltaY: $scrollDeltaY'
353+
'scrollDeltaY: $scrollDeltaY, '
354+
'panX: $panX, '
355+
'panY: $panY, '
356+
'panDeltaX: $panDeltaX, '
357+
'panDeltaY: $panDeltaY, '
358+
'scale: $scale, '
359+
'rotation: $rotation'
302360
')';
303361
}
304362
}

lib/ui/window/pointer_data.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
namespace flutter {
1111

1212
// If this value changes, update the pointer data unpacking code in hooks.dart.
13-
static constexpr int kPointerDataFieldCount = 29;
13+
static constexpr int kPointerDataFieldCount = 35;
1414
static constexpr int kBytesPerField = sizeof(int64_t);
1515
// Must match the button constants in events.dart.
1616
enum PointerButtonMouse : int64_t {
@@ -42,6 +42,9 @@ struct alignas(8) PointerData {
4242
kDown,
4343
kMove,
4444
kUp,
45+
kPanZoomStart,
46+
kPanZoomUpdate,
47+
kPanZoomEnd,
4548
};
4649

4750
// Must match the PointerDeviceKind enum in pointer.dart.
@@ -50,6 +53,7 @@ struct alignas(8) PointerData {
5053
kMouse,
5154
kStylus,
5255
kInvertedStylus,
56+
kTrackpad,
5357
};
5458

5559
// Must match the PointerSignalKind enum in pointer.dart.
@@ -87,6 +91,12 @@ struct alignas(8) PointerData {
8791
int64_t platformData;
8892
double scroll_delta_x;
8993
double scroll_delta_y;
94+
double pan_x;
95+
double pan_y;
96+
double pan_delta_x;
97+
double pan_delta_y;
98+
double scale;
99+
double rotation;
90100

91101
void Clear();
92102
};

lib/ui/window/pointer_data_packet_converter.cc

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "flutter/lib/ui/window/pointer_data_packet_converter.h"
66

7+
#include <cmath>
78
#include <cstring>
89

910
#include "flutter/fml/logging.h"
@@ -207,6 +208,88 @@ void PointerDataPacketConverter::ConvertPointerData(
207208
converted_pointers.push_back(pointer_data);
208209
break;
209210
}
211+
case PointerData::Change::kPanZoomStart: {
212+
// Makes sure we have an existing pointer
213+
auto iter = states_.find(pointer_data.device);
214+
PointerState state;
215+
if (iter == states_.end()) {
216+
// Synthesizes add event if the pointer is not previously added.
217+
PointerData synthesized_add_event = pointer_data;
218+
synthesized_add_event.change = PointerData::Change::kAdd;
219+
synthesized_add_event.synthesized = 1;
220+
synthesized_add_event.buttons = 0;
221+
state = EnsurePointerState(synthesized_add_event);
222+
converted_pointers.push_back(synthesized_add_event);
223+
} else {
224+
state = iter->second;
225+
}
226+
FML_DCHECK(!state.is_down);
227+
FML_DCHECK(!state.is_pan_zoom_active);
228+
if (LocationNeedsUpdate(pointer_data, state)) {
229+
// Synthesizes a hover event if the location does not match.
230+
PointerData synthesized_hover_event = pointer_data;
231+
synthesized_hover_event.change = PointerData::Change::kHover;
232+
synthesized_hover_event.synthesized = 1;
233+
synthesized_hover_event.buttons = 0;
234+
235+
UpdateDeltaAndState(synthesized_hover_event, state);
236+
converted_pointers.push_back(synthesized_hover_event);
237+
}
238+
239+
UpdatePointerIdentifier(pointer_data, state, true);
240+
state.is_pan_zoom_active = true;
241+
state.pan_x = 0;
242+
state.pan_y = 0;
243+
state.scale = 1;
244+
state.rotation = 0;
245+
states_[pointer_data.device] = state;
246+
converted_pointers.push_back(pointer_data);
247+
break;
248+
}
249+
case PointerData::Change::kPanZoomUpdate: {
250+
// Makes sure we have an existing pointer in pan_zoom_active state
251+
auto iter = states_.find(pointer_data.device);
252+
FML_DCHECK(iter != states_.end());
253+
PointerState state = iter->second;
254+
FML_DCHECK(!state.is_down);
255+
FML_DCHECK(state.is_pan_zoom_active);
256+
257+
UpdatePointerIdentifier(pointer_data, state, false);
258+
UpdateDeltaAndState(pointer_data, state);
259+
260+
converted_pointers.push_back(pointer_data);
261+
break;
262+
}
263+
case PointerData::Change::kPanZoomEnd: {
264+
// Makes sure we have an existing pointer in pan_zoom_active state
265+
auto iter = states_.find(pointer_data.device);
266+
FML_DCHECK(iter != states_.end());
267+
PointerState state = iter->second;
268+
FML_DCHECK(state.is_pan_zoom_active);
269+
270+
UpdatePointerIdentifier(pointer_data, state, false);
271+
272+
if (LocationNeedsUpdate(pointer_data, state)) {
273+
// Synthesizes an update event if the location does not match.
274+
PointerData synthesized_move_event = pointer_data;
275+
synthesized_move_event.change = PointerData::Change::kPanZoomUpdate;
276+
synthesized_move_event.pan_x = state.pan_x;
277+
synthesized_move_event.pan_y = state.pan_y;
278+
synthesized_move_event.pan_delta_x = 0;
279+
synthesized_move_event.pan_delta_y = 0;
280+
synthesized_move_event.scale = state.scale;
281+
synthesized_move_event.rotation = state.rotation;
282+
synthesized_move_event.synthesized = 1;
283+
284+
UpdateDeltaAndState(synthesized_move_event, state);
285+
converted_pointers.push_back(synthesized_move_event);
286+
}
287+
288+
state.is_pan_zoom_active = false;
289+
states_[pointer_data.device] = state;
290+
converted_pointers.push_back(pointer_data);
291+
break;
292+
}
210293
default: {
211294
converted_pointers.push_back(pointer_data);
212295
break;
@@ -261,8 +344,11 @@ PointerState PointerDataPacketConverter::EnsurePointerState(
261344
PointerState state;
262345
state.pointer_identifier = 0;
263346
state.is_down = false;
347+
state.is_pan_zoom_active = false;
264348
state.physical_x = pointer_data.physical_x;
265349
state.physical_y = pointer_data.physical_y;
350+
state.pan_x = 0;
351+
state.pan_y = 0;
266352
states_[pointer_data.device] = state;
267353
return state;
268354
}
@@ -271,8 +357,14 @@ void PointerDataPacketConverter::UpdateDeltaAndState(PointerData& pointer_data,
271357
PointerState& state) {
272358
pointer_data.physical_delta_x = pointer_data.physical_x - state.physical_x;
273359
pointer_data.physical_delta_y = pointer_data.physical_y - state.physical_y;
360+
pointer_data.pan_delta_x = pointer_data.pan_x - state.pan_x;
361+
pointer_data.pan_delta_y = pointer_data.pan_y - state.pan_y;
274362
state.physical_x = pointer_data.physical_x;
275363
state.physical_y = pointer_data.physical_y;
364+
state.pan_x = pointer_data.pan_x;
365+
state.pan_y = pointer_data.pan_y;
366+
state.scale = pointer_data.scale;
367+
state.rotation = pointer_data.rotation;
276368
states_[pointer_data.device] = state;
277369
}
278370

lib/ui/window/pointer_data_packet_converter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,13 @@ namespace flutter {
3030
struct PointerState {
3131
int64_t pointer_identifier;
3232
bool is_down;
33+
bool is_pan_zoom_active;
3334
double physical_x;
3435
double physical_y;
36+
double pan_x;
37+
double pan_y;
38+
double scale;
39+
double rotation;
3540
int64_t buttons;
3641
};
3742

0 commit comments

Comments
 (0)