1use super::gesture_arena::TouchpadEvent;
6use crate::utils::{euclidean_distance, Position};
7use std::collections::HashMap;
8
9#[derive(Debug, PartialEq)]
11pub(super) struct MovementDetail {
12 pub(super) euclidean_distance: f32,
13 pub(super) movement: Position,
14}
15
16pub(super) fn movement_from_events(
19 previous_event: &TouchpadEvent,
20 new_event: &TouchpadEvent,
21) -> MovementDetail {
22 let mut previous_contacts: HashMap<u32, Position> = HashMap::new();
23 for c in &previous_event.contacts {
24 previous_contacts.insert(c.id, c.position.clone());
25 }
26
27 let mut movement = Position { x: 0.0, y: 0.0 };
28 let mut max_distance = 0.0;
29 for new_contact in &new_event.contacts {
30 let previous = previous_contacts.get(&new_contact.id);
31 match previous {
32 None => {}
33 Some(&previous) => {
34 let dis = euclidean_distance(new_contact.position, previous.clone());
35 if dis > max_distance {
36 max_distance = dis;
37 movement = new_contact.position - previous;
38 }
39 }
40 }
41 }
42
43 MovementDetail { euclidean_distance: max_distance, movement }
44}
45
46#[cfg(test)]
47mod tests {
48
49 use super::*;
50 use crate::gestures::gesture_arena::TouchpadEvent;
51 use crate::touch_binding;
52 use crate::utils::Position;
53
54 use test_case::test_case;
55
56 fn make_touch_contact(id: u32, position: Position) -> touch_binding::TouchContact {
57 touch_binding::TouchContact { id, position, pressure: None, contact_size: None }
58 }
59
60 #[test_case(
61 TouchpadEvent {
62 timestamp: zx::Instant::ZERO,
63 pressed_buttons: vec![],
64 contacts: vec![
65 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
66 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
67 ],
68 filtered_palm_contacts: vec![],
69 }; "previous contact stay, place new finger")]
70 #[test_case(
71 TouchpadEvent {
72 timestamp: zx::Instant::ZERO,
73 pressed_buttons: vec![],
74 contacts: vec![
75 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
76 ],
77 filtered_palm_contacts: vec![],
78 }; "previous contact lift, place new finger")]
79 #[test_case(
80 TouchpadEvent {
81 timestamp: zx::Instant::ZERO,
82 pressed_buttons: vec![],
83 contacts: vec![],
84 filtered_palm_contacts: vec![],
85 }; "previous contact lift")]
86 #[fuchsia::test]
87 fn movement_from_events_no_movement(new_event: TouchpadEvent) {
88 let previous_event = TouchpadEvent {
89 timestamp: zx::Instant::ZERO,
90 pressed_buttons: vec![],
91 contacts: vec![make_touch_contact(1, Position { x: 1.0, y: 1.0 })],
92 filtered_palm_contacts: vec![],
93 };
94
95 let got = movement_from_events(&previous_event, &new_event);
96 let want = MovementDetail { euclidean_distance: 0.0, movement: Position::zero() };
97 pretty_assertions::assert_eq!(got, want);
98 }
99
100 #[test_case(
101 TouchpadEvent {
102 timestamp: zx::Instant::ZERO,
103 pressed_buttons: vec![],
104 contacts: vec![
105 make_touch_contact(1, Position{x: 1.0, y: 6.0}),
106 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
107 ],
108 filtered_palm_contacts: vec![],
109 }; "contact 1 move, contact 2 stay")]
110 #[test_case(
111 TouchpadEvent {
112 timestamp: zx::Instant::ZERO,
113 pressed_buttons: vec![],
114 contacts: vec![
115 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
116 make_touch_contact(2, Position{x: 5.0, y: 10.0}),
117 ],
118 filtered_palm_contacts: vec![],
119 }; "contact 2 move, contact 1 stay")]
120 #[test_case(
121 TouchpadEvent {
122 timestamp: zx::Instant::ZERO,
123 pressed_buttons: vec![],
124 contacts: vec![
125 make_touch_contact(1, Position{x: 1.0, y: 6.0}),
126 make_touch_contact(2, Position{x: 3.0, y: 5.0}),
127 ],
128 filtered_palm_contacts: vec![],
129 }; "contact 1 movement larger")]
130 #[test_case(
131 TouchpadEvent {
132 timestamp: zx::Instant::ZERO,
133 pressed_buttons: vec![],
134 contacts: vec![
135 make_touch_contact(1, Position{x: 1.0, y: 6.0}),
136 ],
137 filtered_palm_contacts: vec![],
138 }; "1 contact lift")]
139 #[fuchsia::test]
140 fn movement_from_events_furthest_movement(new_event: TouchpadEvent) {
141 let previous_event = TouchpadEvent {
142 timestamp: zx::Instant::ZERO,
143 pressed_buttons: vec![],
144 contacts: vec![
145 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
146 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
147 ],
148 filtered_palm_contacts: vec![],
149 };
150
151 let got = movement_from_events(&previous_event, &new_event);
152 let want =
153 MovementDetail { euclidean_distance: 5.0, movement: Position { x: 0.0, y: 5.0 } };
154 pretty_assertions::assert_eq!(got, want);
155 }
156}