Skip to main content

inset_embedder/
pointer_report.rs

1//! Flutter counterpart: the embedder API's `FlutterPointerEvent`
2//! (`engine/src/flutter/shell/platform/embedder/embedder.h`) and its copy into `PointerData` in
3//! `FlutterEngineSendPointerEvent` (`embedder.cc`).
4
5use std::time::Duration;
6
7use crate::{PointerChange, PointerData, PointerDeviceKind, PointerSignalKind, ViewId};
8
9/// What a host saw one pointing device do, as the system reported it.
10///
11/// It holds only what the system says. What the framework also needs, each press's identifier,
12/// how far the device came since the framework last heard of it, and the changes the system left
13/// out, the client adds ([`PointerDataPacketConverter`](crate::PointerDataPacketConverter)).
14#[derive(Clone, Copy, Debug, PartialEq)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16pub struct PointerReport {
17    /// The view the device is over.
18    pub view_id: ViewId,
19
20    /// When the system reported it, on the host's timeline.
21    pub time_stamp: Duration,
22
23    /// The device: one number per mouse, finger, pen or trackpad, the same for each of its
24    /// presses, and different from every other device the host reports.
25    pub device: i64,
26
27    /// The kind of device.
28    pub kind: PointerDeviceKind,
29
30    /// Where the device is, in the view's physical pixels.
31    pub position: [f64; 2],
32
33    /// What the device did.
34    pub change: ReportedChange,
35
36    /// How a finger or a pen meets the surface, where the system says.
37    pub contact: Contact,
38}
39
40/// How a device changed, with what the framework takes of that change.
41#[derive(Clone, Copy, Debug, PartialEq)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43pub enum ReportedChange {
44    /// The device started being tracked, such as the mouse coming into the view.
45    Add,
46
47    /// The device is no longer tracked.
48    Remove,
49
50    /// It moved without touching, with `buttons` held, such as a pen's barrel button.
51    Hover { buttons: i64 },
52
53    /// It touched, or its first button went down, with `buttons` held.
54    Down { buttons: i64 },
55
56    /// It moved while touching, or the buttons it holds changed, to `buttons`.
57    Move { buttons: i64 },
58
59    /// It stopped touching, or its last button was released, with `buttons` still held.
60    Up { buttons: i64 },
61
62    /// The system took its press away, with `buttons` held.
63    Cancel { buttons: i64 },
64
65    /// A wheel or a trackpad scrolled by `delta`, in physical pixels, positive towards the
66    /// content's end.
67    Scroll { delta: [f64; 2] },
68
69    /// A touch stopped the system's own scrolling momentum.
70    ScrollInertiaCancel,
71
72    /// A zoom by `scale`, such as a browser's for a wheel turned with Control held.
73    Scale { scale: f64 },
74
75    /// A trackpad gesture, panning, zooming and rotating together, started.
76    PanZoomStart,
77
78    /// The gesture so far, each the total since it started: `pan` in physical pixels, `scale`
79    /// from 1.0, and `rotation` in radians, clockwise, from 0.0.
80    PanZoomUpdate {
81        pan: [f64; 2],
82        scale: f64,
83        rotation: f64,
84    },
85
86    /// The gesture ended.
87    PanZoomEnd,
88}
89
90/// How a finger or a pen meets the surface: [`PointerData`]'s fields of the same names. The
91/// default is a device that detects none of it, such as a mouse, whose pressure reads 1.0.
92#[derive(Clone, Copy, Debug, PartialEq)]
93#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
94pub struct Contact {
95    pub pressure: f64,
96    pub pressure_min: f64,
97    pub pressure_max: f64,
98    pub distance: f64,
99    pub distance_max: f64,
100    pub size: f64,
101    pub radius_major: f64,
102    pub radius_minor: f64,
103    pub radius_min: f64,
104    pub radius_max: f64,
105    pub orientation: f64,
106    pub tilt: f64,
107}
108
109impl Default for Contact {
110    fn default() -> Contact {
111        Contact {
112            pressure: 1.0,
113            pressure_min: 1.0,
114            pressure_max: 1.0,
115            distance: 0.0,
116            distance_max: 0.0,
117            size: 0.0,
118            radius_major: 0.0,
119            radius_minor: 0.0,
120            radius_min: 0.0,
121            radius_max: 0.0,
122            orientation: 0.0,
123            tilt: 0.0,
124        }
125    }
126}
127
128impl From<PointerReport> for PointerData {
129    /// The datum the converter starts from: what the system said, with what only the converter
130    /// knows, the press's identifier, the deltas and `synthesized`, left at zero, and no
131    /// `embedder_id`, as `embedder.cc` gives none.
132    fn from(report: PointerReport) -> PointerData {
133        let contact = report.contact;
134        let mut data = PointerData {
135            view_id: report.view_id,
136            time_stamp: report.time_stamp,
137            kind: report.kind,
138            device: report.device,
139            physical_x: report.position[0],
140            physical_y: report.position[1],
141            pressure: contact.pressure,
142            pressure_min: contact.pressure_min,
143            pressure_max: contact.pressure_max,
144            distance: contact.distance,
145            distance_max: contact.distance_max,
146            size: contact.size,
147            radius_major: contact.radius_major,
148            radius_minor: contact.radius_minor,
149            radius_min: contact.radius_min,
150            radius_max: contact.radius_max,
151            orientation: contact.orientation,
152            tilt: contact.tilt,
153            ..PointerData::default()
154        };
155        report.change.write_into(&mut data);
156        data
157    }
158}
159
160impl ReportedChange {
161    /// Sets `data`'s change, and the fields this change carries.
162    fn write_into(self, data: &mut PointerData) {
163        let (change, buttons) = match self {
164            ReportedChange::Add => (PointerChange::Add, 0),
165            ReportedChange::Remove => (PointerChange::Remove, 0),
166            ReportedChange::Hover { buttons } => (PointerChange::Hover, buttons),
167            ReportedChange::Down { buttons } => (PointerChange::Down, buttons),
168            ReportedChange::Move { buttons } => (PointerChange::Move, buttons),
169            ReportedChange::Up { buttons } => (PointerChange::Up, buttons),
170            ReportedChange::Cancel { buttons } => (PointerChange::Cancel, buttons),
171            // A signal is no change of the device, which the framework reads as a hover.
172            ReportedChange::Scroll { delta } => {
173                data.signal_kind = Some(PointerSignalKind::Scroll);
174                [data.scroll_delta_x, data.scroll_delta_y] = delta;
175                (PointerChange::Hover, 0)
176            }
177            ReportedChange::ScrollInertiaCancel => {
178                data.signal_kind = Some(PointerSignalKind::ScrollInertiaCancel);
179                (PointerChange::Hover, 0)
180            }
181            ReportedChange::Scale { scale } => {
182                data.signal_kind = Some(PointerSignalKind::Scale);
183                data.scale = scale;
184                (PointerChange::Hover, 0)
185            }
186            ReportedChange::PanZoomStart => (PointerChange::PanZoomStart, 0),
187            ReportedChange::PanZoomUpdate {
188                pan,
189                scale,
190                rotation,
191            } => {
192                [data.pan_x, data.pan_y] = pan;
193                data.scale = scale;
194                data.rotation = rotation;
195                (PointerChange::PanZoomUpdate, 0)
196            }
197            ReportedChange::PanZoomEnd => (PointerChange::PanZoomEnd, 0),
198        };
199        data.change = change;
200        data.buttons = buttons;
201    }
202}
203
204#[cfg(test)]
205mod tests {
206    use super::*;
207
208    fn report(change: ReportedChange) -> PointerReport {
209        PointerReport {
210            view_id: ViewId(3),
211            time_stamp: Duration::from_millis(5),
212            device: 2,
213            kind: PointerDeviceKind::Mouse,
214            position: [10.0, 20.0],
215            change,
216            contact: Contact::default(),
217        }
218    }
219
220    #[test]
221    fn a_report_is_the_datum_with_what_only_the_converter_knows_left_at_zero() {
222        let data = PointerData::from(report(ReportedChange::Down { buttons: 1 }));
223        assert_eq!(data.change, PointerChange::Down);
224        assert_eq!(data.buttons, 1);
225        assert_eq!([data.physical_x, data.physical_y], [10.0, 20.0]);
226        assert_eq!((data.view_id, data.device), (ViewId(3), 2));
227        assert_eq!(data.embedder_id, 0, "no host numbers its system events");
228        assert_eq!(data.pressure, 1.0, "a mouse detects no pressure");
229        assert_eq!(data.pointer_identifier, 0);
230        assert_eq!([data.physical_delta_x, data.physical_delta_y], [0.0, 0.0]);
231        assert!(!data.synthesized);
232        assert!(data.signal_kind.is_none());
233    }
234
235    #[test]
236    fn a_scroll_is_a_signal_on_a_hover() {
237        let data = PointerData::from(report(ReportedChange::Scroll { delta: [0.0, 40.0] }));
238        assert_eq!(data.change, PointerChange::Hover);
239        assert_eq!(data.signal_kind, Some(PointerSignalKind::Scroll));
240        assert_eq!([data.scroll_delta_x, data.scroll_delta_y], [0.0, 40.0]);
241    }
242
243    #[test]
244    fn a_pan_zoom_update_carries_its_totals() {
245        let data = PointerData::from(report(ReportedChange::PanZoomUpdate {
246            pan: [3.0, 4.0],
247            scale: 1.5,
248            rotation: 0.25,
249        }));
250        assert_eq!(data.change, PointerChange::PanZoomUpdate);
251        assert_eq!([data.pan_x, data.pan_y], [3.0, 4.0]);
252        assert_eq!((data.scale, data.rotation), (1.5, 0.25));
253        assert_eq!([data.pan_delta_x, data.pan_delta_y], [0.0, 0.0]);
254    }
255}