Skip to main content

inset_embedder/
pointer_data_packet_converter.rs

1//! Flutter counterpart: `engine/src/flutter/lib/ui/window/pointer_data_packet_converter.cc`.
2
3use std::collections::HashMap;
4
5use crate::{PointerChange, PointerData, PointerDataPacket, PointerSignalKind, ViewId};
6
7#[derive(Clone, Copy, Debug)]
8struct PointerState {
9    pointer_identifier: i64,
10    is_down: bool,
11    is_pan_zoom_active: bool,
12    physical_x: f64,
13    physical_y: f64,
14    pan_x: f64,
15    pan_y: f64,
16    scale: f64,
17    rotation: f64,
18    buttons: i64,
19    view_id: ViewId,
20}
21
22/// Converts the pointer data a host reports into the form the framework takes, keeping for each
23/// device what the framework was last told of it.
24#[derive(Debug, Default)]
25pub struct PointerDataPacketConverter {
26    /// A map from pointer device ID to the state of the pointer.
27    states: HashMap<i64, PointerState>,
28
29    pointer: i64,
30}
31
32impl PointerDataPacketConverter {
33    pub fn new() -> PointerDataPacketConverter {
34        PointerDataPacketConverter::default()
35    }
36
37    /// Converts pointer data packet into a form that framework understands. The raw pointer data
38    /// packet from embedding does not have sufficient information and may contain illegal pointer
39    /// transitions. This method will fill out that information and attempt to correct pointer
40    /// transitions.
41    ///
42    /// Pointer data with view IDs `view_exists` does not know will be ignored.
43    ///
44    /// Returns a full converted packet with all the required information filled. It may contain
45    /// synthetic pointer data as the result of converter's attempt to correct illegal pointer
46    /// transitions.
47    pub fn convert(
48        &mut self,
49        packet: &PointerDataPacket,
50        view_exists: impl Fn(ViewId) -> bool,
51    ) -> PointerDataPacket {
52        let mut converted_pointers = Vec::new();
53        // Converts each pointer data in the buffer and stores it in the converted_pointers.
54        for pointer_data in &packet.data {
55            self.convert_pointer_data(*pointer_data, &view_exists, &mut converted_pointers);
56        }
57        PointerDataPacket::new(converted_pointers)
58    }
59
60    fn convert_pointer_data(
61        &mut self,
62        mut pointer_data: PointerData,
63        view_exists: &impl Fn(ViewId) -> bool,
64        converted_pointers: &mut Vec<PointerData>,
65    ) {
66        // Ignores pointer events with an invalid view ID.
67        if !view_exists(pointer_data.view_id) {
68            return;
69        }
70        match pointer_data.signal_kind.unwrap_or(PointerSignalKind::None) {
71            PointerSignalKind::None => match pointer_data.change {
72                PointerChange::Cancel => {
73                    // Android's three finger gesture will send a cancel event
74                    // to a non-existing pointer. Drops the cancel if pointer
75                    // is not previously added.
76                    // https://github.com/flutter/flutter/issues/20517
77                    if let Some(mut state) = self.states.get(&pointer_data.device).copied() {
78                        self.update_pointer_identifier(&mut pointer_data, &mut state, false);
79
80                        if Self::location_needs_update(&pointer_data, &state) {
81                            // Synthesizes a move event if the location does not match.
82                            let mut synthesized_move_event = pointer_data;
83                            synthesized_move_event.change = PointerChange::Move;
84                            synthesized_move_event.synthesized = true;
85
86                            self.update_delta_and_state(&mut synthesized_move_event, &mut state);
87                            converted_pointers.push(synthesized_move_event);
88                        }
89
90                        state.is_down = false;
91                        self.states.insert(pointer_data.device, state);
92                        converted_pointers.push(pointer_data);
93                    }
94                }
95                PointerChange::Add => {
96                    if let Some(mut state) = self.states.get(&pointer_data.device).copied() {
97                        // Synthesizes a remove event if the pointer was not previously
98                        // removed.
99                        let mut synthesized_data = pointer_data;
100                        synthesized_data.physical_x = state.physical_x;
101                        synthesized_data.physical_y = state.physical_y;
102                        synthesized_data.pan_x = state.pan_x;
103                        synthesized_data.pan_y = state.pan_y;
104                        synthesized_data.scale = state.scale;
105                        synthesized_data.rotation = state.rotation;
106                        synthesized_data.buttons = state.buttons;
107                        synthesized_data.synthesized = true;
108
109                        // The framework expects an add event to always follow a remove event,
110                        // and remove events with invalid views are ignored.
111                        // To meet the framework's expectations, the view ID of the add event
112                        // is used for the remove event if the old view has been destroyed.
113                        if view_exists(state.view_id) {
114                            synthesized_data.view_id = state.view_id;
115
116                            if state.is_down {
117                                // Synthesizes cancel event if the pointer is down.
118                                let mut synthesized_cancel_event = synthesized_data;
119                                synthesized_cancel_event.change = PointerChange::Cancel;
120                                self.update_pointer_identifier(
121                                    &mut synthesized_cancel_event,
122                                    &mut state,
123                                    false,
124                                );
125
126                                converted_pointers.push(synthesized_cancel_event);
127                            }
128                        }
129
130                        let mut synthesized_remove_event = synthesized_data;
131                        synthesized_remove_event.change = PointerChange::Remove;
132
133                        converted_pointers.push(synthesized_remove_event);
134                    }
135
136                    self.ensure_pointer_state(&pointer_data);
137                    converted_pointers.push(pointer_data);
138                }
139                PointerChange::Remove => {
140                    // Makes sure we have an existing pointer
141                    let Some(mut state) = self.states.get(&pointer_data.device).copied() else {
142                        return;
143                    };
144                    if state.view_id != pointer_data.view_id {
145                        // Ignores remove event if the pointer was previously added to a
146                        // different view.
147                        return;
148                    }
149
150                    if state.is_down {
151                        // Synthesizes cancel event if the pointer is down.
152                        let mut synthesized_cancel_event = pointer_data;
153                        synthesized_cancel_event.change = PointerChange::Cancel;
154                        synthesized_cancel_event.synthesized = true;
155                        self.update_pointer_identifier(
156                            &mut synthesized_cancel_event,
157                            &mut state,
158                            false,
159                        );
160
161                        state.is_down = false;
162                        self.states.insert(synthesized_cancel_event.device, state);
163                        converted_pointers.push(synthesized_cancel_event);
164                    }
165
166                    if Self::location_needs_update(&pointer_data, &state) {
167                        // Synthesizes a hover event if the location does not match.
168                        let mut synthesized_hover_event = pointer_data;
169                        synthesized_hover_event.change = PointerChange::Hover;
170                        synthesized_hover_event.synthesized = true;
171
172                        self.update_delta_and_state(&mut synthesized_hover_event, &mut state);
173                        converted_pointers.push(synthesized_hover_event);
174                    }
175
176                    self.states.remove(&pointer_data.device);
177                    converted_pointers.push(pointer_data);
178                }
179                PointerChange::Hover => {
180                    let mut state = match self.states.get(&pointer_data.device).copied() {
181                        Some(state) => state,
182                        None => {
183                            // Synthesizes add event if the pointer is not previously added.
184                            let mut synthesized_add_event = pointer_data;
185                            synthesized_add_event.change = PointerChange::Add;
186                            synthesized_add_event.synthesized = true;
187                            synthesized_add_event.buttons = 0;
188                            let state = self.ensure_pointer_state(&synthesized_add_event);
189                            converted_pointers.push(synthesized_add_event);
190                            state
191                        }
192                    };
193
194                    state.buttons = pointer_data.buttons;
195                    if Self::location_needs_update(&pointer_data, &state) {
196                        self.update_delta_and_state(&mut pointer_data, &mut state);
197                        converted_pointers.push(pointer_data);
198                    }
199                }
200                PointerChange::Down => {
201                    let mut state = match self.states.get(&pointer_data.device).copied() {
202                        Some(state) => state,
203                        None => {
204                            // Synthesizes a add event if the pointer is not previously added.
205                            let mut synthesized_add_event = pointer_data;
206                            synthesized_add_event.change = PointerChange::Add;
207                            synthesized_add_event.synthesized = true;
208                            synthesized_add_event.buttons = 0;
209                            let state = self.ensure_pointer_state(&synthesized_add_event);
210                            converted_pointers.push(synthesized_add_event);
211                            state
212                        }
213                    };
214
215                    if Self::location_needs_update(&pointer_data, &state) {
216                        // Synthesizes a hover event if the location does not match.
217                        let mut synthesized_hover_event = pointer_data;
218                        synthesized_hover_event.change = PointerChange::Hover;
219                        synthesized_hover_event.synthesized = true;
220                        synthesized_hover_event.buttons = 0;
221
222                        self.update_delta_and_state(&mut synthesized_hover_event, &mut state);
223                        converted_pointers.push(synthesized_hover_event);
224                    }
225
226                    self.update_pointer_identifier(&mut pointer_data, &mut state, true);
227                    state.is_down = true;
228                    state.buttons = pointer_data.buttons;
229                    self.states.insert(pointer_data.device, state);
230                    converted_pointers.push(pointer_data);
231                }
232                PointerChange::Move => {
233                    // Makes sure we have an existing pointer in down state
234                    let Some(mut state) = self.states.get(&pointer_data.device).copied() else {
235                        return;
236                    };
237
238                    self.update_pointer_identifier(&mut pointer_data, &mut state, false);
239                    self.update_delta_and_state(&mut pointer_data, &mut state);
240                    converted_pointers.push(pointer_data);
241                }
242                PointerChange::Up => {
243                    // Makes sure we have an existing pointer in down state
244                    let Some(mut state) = self.states.get(&pointer_data.device).copied() else {
245                        return;
246                    };
247
248                    self.update_pointer_identifier(&mut pointer_data, &mut state, false);
249
250                    if Self::location_needs_update(&pointer_data, &state) {
251                        // Synthesizes a move event if the location does not match.
252                        let mut synthesized_move_event = pointer_data;
253                        synthesized_move_event.change = PointerChange::Move;
254                        synthesized_move_event.buttons = state.buttons;
255                        synthesized_move_event.synthesized = true;
256
257                        self.update_delta_and_state(&mut synthesized_move_event, &mut state);
258                        converted_pointers.push(synthesized_move_event);
259                    }
260
261                    state.is_down = false;
262                    state.buttons = pointer_data.buttons;
263                    self.states.insert(pointer_data.device, state);
264                    converted_pointers.push(pointer_data);
265                }
266                PointerChange::PanZoomStart => {
267                    // Makes sure we have an existing pointer
268                    let mut state = match self.states.get(&pointer_data.device).copied() {
269                        Some(state) => state,
270                        None => {
271                            // Synthesizes add event if the pointer is not previously added.
272                            let mut synthesized_add_event = pointer_data;
273                            synthesized_add_event.change = PointerChange::Add;
274                            synthesized_add_event.synthesized = true;
275                            synthesized_add_event.buttons = 0;
276                            let state = self.ensure_pointer_state(&synthesized_add_event);
277                            converted_pointers.push(synthesized_add_event);
278                            state
279                        }
280                    };
281                    if Self::location_needs_update(&pointer_data, &state) {
282                        // Synthesizes a hover event if the location does not match.
283                        let mut synthesized_hover_event = pointer_data;
284                        synthesized_hover_event.change = PointerChange::Hover;
285                        synthesized_hover_event.synthesized = true;
286                        synthesized_hover_event.buttons = 0;
287
288                        self.update_delta_and_state(&mut synthesized_hover_event, &mut state);
289                        converted_pointers.push(synthesized_hover_event);
290                    }
291
292                    self.update_pointer_identifier(&mut pointer_data, &mut state, true);
293                    state.is_pan_zoom_active = true;
294                    state.pan_x = 0.0;
295                    state.pan_y = 0.0;
296                    state.scale = 1.0;
297                    state.rotation = 0.0;
298                    self.states.insert(pointer_data.device, state);
299                    converted_pointers.push(pointer_data);
300                }
301                PointerChange::PanZoomUpdate => {
302                    // Makes sure we have an existing pointer in pan_zoom_active state
303                    let Some(mut state) = self.states.get(&pointer_data.device).copied() else {
304                        return;
305                    };
306
307                    self.update_pointer_identifier(&mut pointer_data, &mut state, false);
308                    self.update_delta_and_state(&mut pointer_data, &mut state);
309
310                    converted_pointers.push(pointer_data);
311                }
312                PointerChange::PanZoomEnd => {
313                    // Makes sure we have an existing pointer in pan_zoom_active state
314                    let Some(mut state) = self.states.get(&pointer_data.device).copied() else {
315                        return;
316                    };
317
318                    self.update_pointer_identifier(&mut pointer_data, &mut state, false);
319
320                    if Self::location_needs_update(&pointer_data, &state) {
321                        // Synthesizes an update event if the location does not match.
322                        let mut synthesized_move_event = pointer_data;
323                        synthesized_move_event.change = PointerChange::PanZoomUpdate;
324                        synthesized_move_event.pan_x = state.pan_x;
325                        synthesized_move_event.pan_y = state.pan_y;
326                        synthesized_move_event.pan_delta_x = 0.0;
327                        synthesized_move_event.pan_delta_y = 0.0;
328                        synthesized_move_event.scale = state.scale;
329                        synthesized_move_event.rotation = state.rotation;
330                        synthesized_move_event.synthesized = true;
331
332                        self.update_delta_and_state(&mut synthesized_move_event, &mut state);
333                        converted_pointers.push(synthesized_move_event);
334                    }
335
336                    state.is_pan_zoom_active = false;
337                    self.states.insert(pointer_data.device, state);
338                    converted_pointers.push(pointer_data);
339                }
340            },
341            PointerSignalKind::Scroll
342            | PointerSignalKind::ScrollInertiaCancel
343            | PointerSignalKind::Scale => {
344                // Makes sure we have an existing pointer
345                let mut state = match self.states.get(&pointer_data.device).copied() {
346                    Some(state) => state,
347                    None => {
348                        // Synthesizes a add event if the pointer is not previously added.
349                        let mut synthesized_add_event = pointer_data;
350                        synthesized_add_event.signal_kind = None;
351                        synthesized_add_event.change = PointerChange::Add;
352                        synthesized_add_event.synthesized = true;
353                        synthesized_add_event.buttons = 0;
354                        let state = self.ensure_pointer_state(&synthesized_add_event);
355                        converted_pointers.push(synthesized_add_event);
356                        state
357                    }
358                };
359
360                if Self::location_needs_update(&pointer_data, &state) {
361                    if state.is_down {
362                        // Synthesizes a move event if the pointer is down.
363                        let mut synthesized_move_event = pointer_data;
364                        synthesized_move_event.signal_kind = None;
365                        synthesized_move_event.change = PointerChange::Move;
366                        synthesized_move_event.buttons = state.buttons;
367                        synthesized_move_event.synthesized = true;
368
369                        self.update_delta_and_state(&mut synthesized_move_event, &mut state);
370                        converted_pointers.push(synthesized_move_event);
371                    } else {
372                        // Synthesizes a hover event if the pointer is up.
373                        let mut synthesized_hover_event = pointer_data;
374                        synthesized_hover_event.signal_kind = None;
375                        synthesized_hover_event.change = PointerChange::Hover;
376                        synthesized_hover_event.buttons = 0;
377                        synthesized_hover_event.synthesized = true;
378
379                        self.update_delta_and_state(&mut synthesized_hover_event, &mut state);
380                        converted_pointers.push(synthesized_hover_event);
381                    }
382                }
383
384                converted_pointers.push(pointer_data);
385            }
386            // Ignores unknown signal kind.
387            PointerSignalKind::Unknown => {}
388        }
389    }
390
391    fn ensure_pointer_state(&mut self, pointer_data: &PointerData) -> PointerState {
392        let state = PointerState {
393            pointer_identifier: 0,
394            is_down: false,
395            is_pan_zoom_active: false,
396            physical_x: pointer_data.physical_x,
397            physical_y: pointer_data.physical_y,
398            pan_x: 0.0,
399            pan_y: 0.0,
400            scale: 0.0,
401            rotation: 0.0,
402            buttons: 0,
403            view_id: pointer_data.view_id,
404        };
405        self.states.insert(pointer_data.device, state);
406        state
407    }
408
409    fn update_delta_and_state(&mut self, pointer_data: &mut PointerData, state: &mut PointerState) {
410        pointer_data.physical_delta_x = pointer_data.physical_x - state.physical_x;
411        pointer_data.physical_delta_y = pointer_data.physical_y - state.physical_y;
412        pointer_data.pan_delta_x = pointer_data.pan_x - state.pan_x;
413        pointer_data.pan_delta_y = pointer_data.pan_y - state.pan_y;
414        state.physical_x = pointer_data.physical_x;
415        state.physical_y = pointer_data.physical_y;
416        state.pan_x = pointer_data.pan_x;
417        state.pan_y = pointer_data.pan_y;
418        state.scale = pointer_data.scale;
419        state.rotation = pointer_data.rotation;
420        self.states.insert(pointer_data.device, *state);
421    }
422
423    fn update_pointer_identifier(
424        &mut self,
425        pointer_data: &mut PointerData,
426        state: &mut PointerState,
427        start_new_pointer: bool,
428    ) {
429        if start_new_pointer {
430            self.pointer += 1;
431            state.pointer_identifier = self.pointer;
432            self.states.insert(pointer_data.device, *state);
433        }
434        pointer_data.pointer_identifier = state.pointer_identifier;
435    }
436
437    fn location_needs_update(pointer_data: &PointerData, state: &PointerState) -> bool {
438        state.physical_x != pointer_data.physical_x || state.physical_y != pointer_data.physical_y
439    }
440}
441
442#[cfg(test)]
443mod tests {
444    use std::collections::HashSet;
445
446    use super::*;
447    use crate::PointerDeviceKind;
448
449    const IMPLICIT_VIEW_ID: ViewId = ViewId(0);
450
451    fn pointer_data(
452        change: PointerChange,
453        device: i64,
454        dx: f64,
455        dy: f64,
456        buttons: i64,
457    ) -> PointerData {
458        PointerData {
459            change,
460            kind: PointerDeviceKind::Touch,
461            device,
462            physical_x: dx,
463            physical_y: dy,
464            buttons,
465            view_id: IMPLICIT_VIEW_ID,
466            ..PointerData::default()
467        }
468    }
469
470    #[allow(clippy::too_many_arguments)]
471    fn mouse_pointer_data(
472        change: PointerChange,
473        signal_kind: PointerSignalKind,
474        device: i64,
475        dx: f64,
476        dy: f64,
477        scroll_delta_x: f64,
478        scroll_delta_y: f64,
479        buttons: i64,
480    ) -> PointerData {
481        PointerData {
482            change,
483            kind: PointerDeviceKind::Mouse,
484            signal_kind: Some(signal_kind),
485            device,
486            physical_x: dx,
487            physical_y: dy,
488            buttons,
489            scroll_delta_x,
490            scroll_delta_y,
491            view_id: IMPLICIT_VIEW_ID,
492            ..PointerData::default()
493        }
494    }
495
496    #[allow(clippy::too_many_arguments)]
497    fn trackpad_gesture_data(
498        change: PointerChange,
499        device: i64,
500        dx: f64,
501        dy: f64,
502        pan_x: f64,
503        pan_y: f64,
504        scale: f64,
505        rotation: f64,
506    ) -> PointerData {
507        PointerData {
508            change,
509            kind: PointerDeviceKind::Mouse,
510            device,
511            physical_x: dx,
512            physical_y: dy,
513            pan_x,
514            pan_y,
515            scale,
516            rotation,
517            view_id: IMPLICIT_VIEW_ID,
518            ..PointerData::default()
519        }
520    }
521
522    fn convert(
523        converter: &mut PointerDataPacketConverter,
524        views: &HashSet<ViewId>,
525        data: Vec<PointerData>,
526    ) -> Vec<PointerData> {
527        converter
528            .convert(&PointerDataPacket::new(data), |view_id| {
529                views.contains(&view_id)
530            })
531            .data
532    }
533
534    fn implicit_view() -> HashSet<ViewId> {
535        HashSet::from([IMPLICIT_VIEW_ID])
536    }
537
538    fn changes(result: &[PointerData]) -> Vec<PointerChange> {
539        result.iter().map(|datum| datum.change).collect()
540    }
541
542    fn synthesized(result: &[PointerData]) -> Vec<bool> {
543        result.iter().map(|datum| datum.synthesized).collect()
544    }
545
546    #[test]
547    fn can_convert_pointer_data_packet() {
548        let mut converter = PointerDataPacketConverter::new();
549        let result = convert(
550            &mut converter,
551            &implicit_view(),
552            vec![
553                pointer_data(PointerChange::Add, 0, 0.0, 0.0, 0),
554                pointer_data(PointerChange::Hover, 0, 3.0, 0.0, 0),
555                pointer_data(PointerChange::Down, 0, 3.0, 0.0, 1),
556                pointer_data(PointerChange::Move, 0, 3.0, 4.0, 1),
557                pointer_data(PointerChange::Up, 0, 3.0, 4.0, 0),
558                pointer_data(PointerChange::Remove, 0, 3.0, 4.0, 0),
559            ],
560        );
561
562        use PointerChange::*;
563        assert_eq!(changes(&result), [Add, Hover, Down, Move, Up, Remove]);
564        assert_eq!(synthesized(&result), [false; 6]);
565        assert_eq!(
566            [result[1].physical_delta_x, result[1].physical_delta_y],
567            [3.0, 0.0]
568        );
569        assert_eq!(result[2].pointer_identifier, 1);
570        assert_eq!(result[3].pointer_identifier, 1);
571        assert_eq!(
572            [result[3].physical_delta_x, result[3].physical_delta_y],
573            [0.0, 4.0]
574        );
575        assert_eq!(result[4].pointer_identifier, 1);
576    }
577
578    #[test]
579    fn can_synthesize_down_and_up() {
580        let mut converter = PointerDataPacketConverter::new();
581        let result = convert(
582            &mut converter,
583            &implicit_view(),
584            vec![
585                pointer_data(PointerChange::Add, 0, 0.0, 0.0, 0),
586                pointer_data(PointerChange::Down, 0, 3.0, 0.0, 1),
587                pointer_data(PointerChange::Up, 0, 3.0, 4.0, 0),
588                pointer_data(PointerChange::Remove, 0, 3.0, 4.0, 0),
589            ],
590        );
591
592        use PointerChange::*;
593        assert_eq!(changes(&result), [Add, Hover, Down, Move, Up, Remove]);
594        assert_eq!(
595            synthesized(&result),
596            [false, true, false, true, false, false]
597        );
598        // A hover should be synthesized.
599        assert_eq!(
600            [result[1].physical_delta_x, result[1].physical_delta_y],
601            [3.0, 0.0]
602        );
603        assert_eq!(result[1].buttons, 0);
604        assert_eq!((result[2].pointer_identifier, result[2].buttons), (1, 1));
605        // A move should be synthesized.
606        assert_eq!((result[3].pointer_identifier, result[3].buttons), (1, 1));
607        assert_eq!(
608            [result[3].physical_delta_x, result[3].physical_delta_y],
609            [0.0, 4.0]
610        );
611        assert_eq!((result[4].pointer_identifier, result[4].buttons), (1, 0));
612    }
613
614    #[test]
615    fn can_update_pointer_identifier() {
616        let mut converter = PointerDataPacketConverter::new();
617        let result = convert(
618            &mut converter,
619            &implicit_view(),
620            vec![
621                pointer_data(PointerChange::Add, 0, 0.0, 0.0, 0),
622                pointer_data(PointerChange::Down, 0, 0.0, 0.0, 1),
623                pointer_data(PointerChange::Up, 0, 0.0, 0.0, 0),
624                pointer_data(PointerChange::Down, 0, 0.0, 0.0, 1),
625                pointer_data(PointerChange::Move, 0, 3.0, 0.0, 1),
626                pointer_data(PointerChange::Up, 0, 3.0, 0.0, 0),
627                pointer_data(PointerChange::Remove, 0, 3.0, 0.0, 0),
628            ],
629        );
630
631        use PointerChange::*;
632        assert_eq!(changes(&result), [Add, Down, Up, Down, Move, Up, Remove]);
633        assert_eq!(synthesized(&result), [false; 7]);
634        let identifiers: Vec<i64> = result.iter().map(|d| d.pointer_identifier).collect();
635        // Pointer count increase to 2.
636        assert_eq!(identifiers[1..6], [1, 1, 2, 2, 2]);
637        assert_eq!(
638            [result[4].physical_delta_x, result[4].physical_delta_y],
639            [3.0, 0.0]
640        );
641    }
642
643    #[test]
644    fn always_forward_move_event() {
645        let mut converter = PointerDataPacketConverter::new();
646        let result = convert(
647            &mut converter,
648            &implicit_view(),
649            vec![
650                pointer_data(PointerChange::Add, 0, 0.0, 0.0, 0),
651                pointer_data(PointerChange::Down, 0, 0.0, 0.0, 1),
652                // Creates a move event without a location change.
653                pointer_data(PointerChange::Move, 0, 0.0, 0.0, 1),
654                pointer_data(PointerChange::Up, 0, 0.0, 0.0, 0),
655            ],
656        );
657
658        use PointerChange::*;
659        // Does not filter out the move event.
660        assert_eq!(changes(&result), [Add, Down, Move, Up]);
661        assert_eq!(synthesized(&result), [false; 4]);
662        assert_eq!(result[2].pointer_identifier, 1);
663    }
664
665    #[test]
666    fn can_work_with_different_devices() {
667        let mut converter = PointerDataPacketConverter::new();
668        let result = convert(
669            &mut converter,
670            &implicit_view(),
671            vec![
672                pointer_data(PointerChange::Add, 0, 0.0, 0.0, 0),
673                pointer_data(PointerChange::Down, 0, 0.0, 0.0, 1),
674                pointer_data(PointerChange::Add, 1, 0.0, 0.0, 0),
675                pointer_data(PointerChange::Down, 1, 0.0, 0.0, 1),
676                pointer_data(PointerChange::Up, 0, 0.0, 0.0, 0),
677                pointer_data(PointerChange::Down, 0, 0.0, 0.0, 1),
678                pointer_data(PointerChange::Move, 1, 0.0, 4.0, 1),
679                pointer_data(PointerChange::Move, 0, 3.0, 0.0, 1),
680                pointer_data(PointerChange::Up, 1, 0.0, 4.0, 0),
681                pointer_data(PointerChange::Up, 0, 3.0, 0.0, 0),
682                pointer_data(PointerChange::Remove, 0, 3.0, 0.0, 0),
683                pointer_data(PointerChange::Remove, 1, 0.0, 4.0, 0),
684            ],
685        );
686
687        use PointerChange::*;
688        assert_eq!(
689            changes(&result),
690            [
691                Add, Down, Add, Down, Up, Down, Move, Move, Up, Up, Remove, Remove
692            ]
693        );
694        assert_eq!(synthesized(&result), [false; 12]);
695        let devices: Vec<i64> = result.iter().map(|d| d.device).collect();
696        assert_eq!(devices, [0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1]);
697        let identifiers: Vec<i64> = result.iter().map(|d| d.pointer_identifier).collect();
698        assert_eq!(
699            [
700                identifiers[1],
701                identifiers[3],
702                identifiers[4],
703                identifiers[5]
704            ],
705            [1, 2, 1, 3]
706        );
707        assert_eq!(identifiers[6..10], [2, 3, 2, 3]);
708        assert_eq!(
709            [result[6].physical_delta_x, result[6].physical_delta_y],
710            [0.0, 4.0]
711        );
712        assert_eq!(
713            [result[7].physical_delta_x, result[7].physical_delta_y],
714            [3.0, 0.0]
715        );
716    }
717
718    #[test]
719    fn can_synthesize_add() {
720        let mut converter = PointerDataPacketConverter::new();
721        let result = convert(
722            &mut converter,
723            &implicit_view(),
724            vec![
725                pointer_data(PointerChange::Down, 0, 330.0, 450.0, 1),
726                pointer_data(PointerChange::Up, 0, 0.0, 0.0, 0),
727            ],
728        );
729
730        use PointerChange::*;
731        assert_eq!(changes(&result), [Add, Down, Move, Up]);
732        assert_eq!(synthesized(&result), [true, false, true, false]);
733        // A add should be synthesized.
734        assert_eq!([result[0].physical_x, result[0].physical_y], [330.0, 450.0]);
735        assert_eq!(result[0].buttons, 0);
736        assert_eq!(result[1].buttons, 1);
737        // A move should be synthesized.
738        assert_eq!(
739            [result[2].physical_delta_x, result[2].physical_delta_y],
740            [-330.0, -450.0]
741        );
742        assert_eq!([result[2].physical_x, result[2].physical_y], [0.0, 0.0]);
743        assert_eq!(result[2].buttons, 1);
744        assert_eq!(result[3].buttons, 0);
745    }
746
747    #[test]
748    fn can_synthesize_remove() {
749        let views = HashSet::from([ViewId(100), ViewId(200)]);
750        let mut converter = PointerDataPacketConverter::new();
751        let result = convert(
752            &mut converter,
753            &views,
754            vec![
755                PointerData {
756                    view_id: ViewId(100),
757                    ..pointer_data(PointerChange::Add, 0, 0.0, 0.0, 0)
758                },
759                PointerData {
760                    view_id: ViewId(100),
761                    ..pointer_data(PointerChange::Down, 0, 3.0, 4.0, 1)
762                },
763                PointerData {
764                    view_id: ViewId(200),
765                    ..pointer_data(PointerChange::Add, 0, 0.0, 0.0, 0)
766                },
767            ],
768        );
769
770        use PointerChange::*;
771        assert_eq!(changes(&result), [Add, Hover, Down, Cancel, Remove, Add]);
772        assert_eq!(
773            synthesized(&result),
774            [false, true, false, true, true, false]
775        );
776        assert_eq!(result[0].view_id, ViewId(100));
777        // A hover should be synthesized.
778        assert_eq!(
779            [result[1].physical_delta_x, result[1].physical_delta_y],
780            [3.0, 4.0]
781        );
782        assert_eq!(result[1].buttons, 0);
783        assert_eq!((result[2].pointer_identifier, result[2].buttons), (1, 1));
784        // A cancel should be synthesized.
785        assert_eq!((result[3].pointer_identifier, result[3].buttons), (1, 1));
786        assert_eq!([result[3].physical_x, result[3].physical_y], [3.0, 4.0]);
787        // A remove should be synthesized.
788        assert_eq!([result[4].physical_x, result[4].physical_y], [3.0, 4.0]);
789        assert_eq!(result[4].view_id, ViewId(100));
790        assert_eq!(result[5].view_id, ViewId(200));
791    }
792
793    #[test]
794    fn can_avoid_double_remove_after_synthesized_remove() {
795        let views = HashSet::from([ViewId(100), ViewId(200)]);
796        let mut converter = PointerDataPacketConverter::new();
797        let result = convert(
798            &mut converter,
799            &views,
800            vec![
801                PointerData {
802                    view_id: ViewId(100),
803                    ..pointer_data(PointerChange::Add, 0, 0.0, 0.0, 0)
804                },
805                PointerData {
806                    view_id: ViewId(200),
807                    ..pointer_data(PointerChange::Add, 0, 0.0, 0.0, 0)
808                },
809            ],
810        );
811
812        assert_eq!(synthesized(&result), [false, true, false]);
813        // A remove should be synthesized.
814        let views_of: Vec<ViewId> = result.iter().map(|d| d.view_id).collect();
815        assert_eq!(views_of, [ViewId(100), ViewId(100), ViewId(200)]);
816
817        // Simulate a double remove.
818        let result = convert(
819            &mut converter,
820            &views,
821            vec![PointerData {
822                view_id: ViewId(100),
823                ..pointer_data(PointerChange::Remove, 0, 0.0, 0.0, 0)
824            }],
825        );
826        // The double remove should be ignored.
827        assert!(result.is_empty());
828    }
829
830    #[test]
831    fn can_handle_three_finger_gesture() {
832        // Regression test https://github.com/flutter/flutter/issues/20517.
833        let views = implicit_view();
834        let mut converter = PointerDataPacketConverter::new();
835        let mut result = Vec::new();
836        // First finger down.
837        result.extend(convert(
838            &mut converter,
839            &views,
840            vec![pointer_data(PointerChange::Down, 0, 0.0, 0.0, 1)],
841        ));
842        // Second finger down.
843        result.extend(convert(
844            &mut converter,
845            &views,
846            vec![pointer_data(PointerChange::Down, 1, 33.0, 44.0, 1)],
847        ));
848        // Triggers three cancels.
849        result.extend(convert(
850            &mut converter,
851            &views,
852            vec![
853                pointer_data(PointerChange::Cancel, 1, 33.0, 44.0, 0),
854                pointer_data(PointerChange::Cancel, 0, 0.0, 0.0, 0),
855                pointer_data(PointerChange::Cancel, 2, 40.0, 50.0, 0),
856            ],
857        ));
858
859        use PointerChange::*;
860        // Third cancel should be dropped
861        assert_eq!(changes(&result), [Add, Down, Add, Down, Cancel, Cancel]);
862        assert_eq!(
863            synthesized(&result),
864            [true, false, true, false, false, false]
865        );
866        let devices: Vec<i64> = result.iter().map(|d| d.device).collect();
867        assert_eq!(devices, [0, 0, 1, 1, 1, 0]);
868        assert_eq!((result[0].buttons, result[1].buttons), (0, 1));
869        assert_eq!([result[2].physical_x, result[2].physical_y], [33.0, 44.0]);
870        assert_eq!((result[2].buttons, result[3].buttons), (0, 1));
871        assert_eq!([result[4].physical_x, result[4].physical_y], [33.0, 44.0]);
872    }
873
874    #[test]
875    fn can_convert_pointer_signals() {
876        for kind in [
877            PointerSignalKind::Scroll,
878            PointerSignalKind::ScrollInertiaCancel,
879            PointerSignalKind::Scale,
880        ] {
881            let mut converter = PointerDataPacketConverter::new();
882            let none = PointerSignalKind::None;
883            let result = convert(
884                &mut converter,
885                &implicit_view(),
886                vec![
887                    mouse_pointer_data(PointerChange::Add, none, 0, 0.0, 0.0, 0.0, 0.0, 0),
888                    mouse_pointer_data(PointerChange::Add, none, 1, 0.0, 0.0, 0.0, 0.0, 0),
889                    mouse_pointer_data(PointerChange::Down, none, 1, 0.0, 0.0, 0.0, 0.0, 1),
890                    mouse_pointer_data(PointerChange::Hover, kind, 0, 34.0, 34.0, 30.0, 0.0, 0),
891                    mouse_pointer_data(PointerChange::Hover, kind, 1, 49.0, 49.0, 50.0, 0.0, 0),
892                    mouse_pointer_data(PointerChange::Hover, kind, 2, 10.0, 20.0, 30.0, 40.0, 0),
893                ],
894            );
895
896            use PointerChange::*;
897            assert_eq!(
898                changes(&result),
899                [Add, Add, Down, Hover, Hover, Move, Hover, Add, Hover]
900            );
901            let signals: Vec<PointerSignalKind> = result
902                .iter()
903                .map(|d| d.signal_kind.unwrap_or(PointerSignalKind::None))
904                .collect();
905            assert_eq!(
906                signals,
907                [none, none, none, none, kind, none, kind, none, kind]
908            );
909            let devices: Vec<i64> = result.iter().map(|d| d.device).collect();
910            assert_eq!(devices, [0, 1, 1, 0, 0, 1, 1, 2, 2]);
911            assert_eq!(
912                synthesized(&result),
913                [false, false, false, true, false, true, false, true, false]
914            );
915
916            // Converter will synthesize a hover to position for device 0.
917            assert_eq!([result[3].physical_x, result[3].physical_y], [34.0, 34.0]);
918            assert_eq!(
919                [result[3].physical_delta_x, result[3].physical_delta_y],
920                [34.0, 34.0]
921            );
922            assert_eq!(result[3].buttons, 0);
923            assert_eq!([result[4].physical_x, result[4].physical_y], [34.0, 34.0]);
924            assert_eq!(
925                [result[4].scroll_delta_x, result[4].scroll_delta_y],
926                [30.0, 0.0]
927            );
928
929            // Converter will synthesize a move to position for device 1.
930            assert_eq!([result[5].physical_x, result[5].physical_y], [49.0, 49.0]);
931            assert_eq!(
932                [result[5].physical_delta_x, result[5].physical_delta_y],
933                [49.0, 49.0]
934            );
935            assert_eq!(result[5].buttons, 1);
936            assert_eq!([result[6].physical_x, result[6].physical_y], [49.0, 49.0]);
937            assert_eq!(
938                [result[6].scroll_delta_x, result[6].scroll_delta_y],
939                [50.0, 0.0]
940            );
941
942            // Converter will synthesize an add for device 2.
943            assert_eq!([result[7].physical_x, result[7].physical_y], [10.0, 20.0]);
944            assert_eq!([result[8].physical_x, result[8].physical_y], [10.0, 20.0]);
945            assert_eq!(
946                [result[8].scroll_delta_x, result[8].scroll_delta_y],
947                [30.0, 40.0]
948            );
949        }
950    }
951
952    #[test]
953    fn can_convert_trackpad_gesture() {
954        let mut converter = PointerDataPacketConverter::new();
955        let result = convert(
956            &mut converter,
957            &implicit_view(),
958            vec![
959                trackpad_gesture_data(PointerChange::PanZoomStart, 0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0),
960                trackpad_gesture_data(
961                    PointerChange::PanZoomUpdate,
962                    0,
963                    0.0,
964                    0.0,
965                    3.0,
966                    4.0,
967                    1.0,
968                    0.0,
969                ),
970                trackpad_gesture_data(PointerChange::PanZoomEnd, 0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0),
971            ],
972        );
973
974        use PointerChange::*;
975        assert_eq!(
976            changes(&result),
977            [Add, PanZoomStart, PanZoomUpdate, PanZoomEnd]
978        );
979        assert_eq!(synthesized(&result), [true, false, false, false]);
980        assert_eq!([result[2].pan_x, result[2].pan_y], [3.0, 4.0]);
981        assert_eq!([result[2].pan_delta_x, result[2].pan_delta_y], [3.0, 4.0]);
982        assert_eq!((result[2].scale, result[2].rotation), (1.0, 0.0));
983    }
984
985    #[test]
986    fn a_pan_zoom_away_from_where_its_device_was_starts_with_a_hover_and_ends_with_an_update() {
987        let mut converter = PointerDataPacketConverter::new();
988        let views = implicit_view();
989        let first = convert(
990            &mut converter,
991            &views,
992            vec![
993                trackpad_gesture_data(PointerChange::PanZoomStart, 1, 5.0, 5.0, 0.0, 0.0, 1.0, 0.0),
994                trackpad_gesture_data(
995                    PointerChange::PanZoomUpdate,
996                    1,
997                    5.0,
998                    5.0,
999                    0.0,
1000                    6.0,
1001                    1.5,
1002                    0.0,
1003                ),
1004                trackpad_gesture_data(PointerChange::PanZoomEnd, 1, 9.0, 5.0, 0.0, 0.0, 0.0, 0.0),
1005            ],
1006        );
1007        let second = convert(
1008            &mut converter,
1009            &views,
1010            vec![trackpad_gesture_data(
1011                PointerChange::PanZoomStart,
1012                1,
1013                20.0,
1014                5.0,
1015                0.0,
1016                0.0,
1017                1.0,
1018                0.0,
1019            )],
1020        );
1021
1022        use PointerChange::*;
1023        assert_eq!(
1024            changes(&first),
1025            [Add, PanZoomStart, PanZoomUpdate, PanZoomUpdate, PanZoomEnd]
1026        );
1027        let ending = first[3];
1028        assert!(ending.synthesized);
1029        assert_eq!([ending.physical_delta_x, ending.pan_delta_y], [4.0, 0.0]);
1030        assert_eq!((ending.pan_y, ending.scale), (6.0, 1.5));
1031        assert_eq!(changes(&second), [Hover, PanZoomStart]);
1032        assert!(second[0].synthesized);
1033        assert_eq!(second[0].physical_delta_x, 11.0);
1034        assert_eq!(
1035            [first[1].pointer_identifier, second[1].pointer_identifier],
1036            [1, 2]
1037        );
1038    }
1039
1040    #[test]
1041    fn a_move_up_or_remove_of_a_device_never_added_is_dropped() {
1042        let mut converter = PointerDataPacketConverter::new();
1043        let result = convert(
1044            &mut converter,
1045            &implicit_view(),
1046            vec![
1047                pointer_data(PointerChange::Move, 0, 1.0, 0.0, 1),
1048                pointer_data(PointerChange::Up, 0, 1.0, 0.0, 0),
1049                pointer_data(PointerChange::Remove, 0, 1.0, 0.0, 0),
1050                trackpad_gesture_data(
1051                    PointerChange::PanZoomUpdate,
1052                    1,
1053                    0.0,
1054                    0.0,
1055                    1.0,
1056                    0.0,
1057                    1.0,
1058                    0.0,
1059                ),
1060                trackpad_gesture_data(PointerChange::PanZoomEnd, 1, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0),
1061            ],
1062        );
1063        assert!(result.is_empty());
1064    }
1065
1066    #[test]
1067    fn can_convert_view_id() {
1068        let views = HashSet::from([ViewId(100), ViewId(200)]);
1069        let mut converter = PointerDataPacketConverter::new();
1070        let result = convert(
1071            &mut converter,
1072            &views,
1073            vec![
1074                PointerData {
1075                    view_id: ViewId(100),
1076                    ..pointer_data(PointerChange::Add, 0, 0.0, 0.0, 0)
1077                },
1078                PointerData {
1079                    view_id: ViewId(200),
1080                    ..pointer_data(PointerChange::Hover, 0, 1.0, 0.0, 0)
1081                },
1082            ],
1083        );
1084
1085        let views_of: Vec<ViewId> = result.iter().map(|d| d.view_id).collect();
1086        assert_eq!(views_of, [ViewId(100), ViewId(200)]);
1087    }
1088}