1use super::gesture_arena::{
6 self, DetailedReasonFloat, DetailedReasonUint, EndGestureEvent, ExamineEventResult,
7 ProcessBufferedEventsResult, ProcessNewEventResult, Reason, RecognizedGesture, TouchpadEvent,
8 VerifyEventResult,
9};
10use super::utils::{movement_from_events, MovementDetail};
11use crate::mouse_binding::{MouseButton, MouseEvent, MouseLocation, MousePhase, RelativeLocation};
12use crate::utils::{euclidean_distance, Position};
13
14use maplit::hashset;
15use std::collections::HashSet;
16
17#[derive(Debug)]
20pub(super) struct InitialContender {
21 pub(super) spurious_to_intentional_motion_threshold_mm: f32,
24
25 pub(super) spurious_to_intentional_motion_threshold_button_change_mm: f32,
28
29 pub(super) button_change_state_timeout: zx::MonotonicDuration,
32}
33
34#[derive(Debug)]
36struct OneFingerContactContender {
37 one_finger_contact_event: TouchpadEvent,
39
40 spurious_to_intentional_motion_threshold_mm: f32,
43
44 spurious_to_intentional_motion_threshold_button_change_mm: f32,
47
48 button_change_state_timeout: zx::MonotonicDuration,
51}
52
53#[derive(Debug)]
55struct TwoFingerContactContender {
56 two_finger_contact_event: TouchpadEvent,
58
59 spurious_to_intentional_motion_threshold_mm: f32,
62
63 spurious_to_intentional_motion_threshold_button_change_mm: f32,
66
67 button_change_state_timeout: zx::MonotonicDuration,
70}
71
72#[derive(Debug)]
75struct MatchedContender {
76 pressed_event: TouchpadEvent,
78
79 spurious_to_intentional_motion_threshold_mm: f32,
82
83 spurious_to_intentional_motion_threshold_button_change_mm: f32,
86
87 button_change_state_timeout: zx::MonotonicDuration,
90}
91
92#[derive(Debug)]
94struct ButtonDownWinner {
95 pressed_event: TouchpadEvent,
97
98 spurious_to_intentional_motion_threshold_mm: f32,
100
101 spurious_to_intentional_motion_threshold_button_change_mm: f32,
104
105 button_change_state_timeout: zx::MonotonicDuration,
108}
109
110#[derive(Debug)]
113struct DragWinner {
114 last_event: TouchpadEvent,
116
117 spurious_to_intentional_motion_threshold_button_change_mm: f32,
120
121 button_change_state_timeout: zx::MonotonicDuration,
124}
125
126#[derive(Debug)]
129struct ButtonUpWinner {
130 button_up_event: TouchpadEvent,
132
133 spurious_to_intentional_motion_threshold_button_change_mm: f32,
136
137 button_change_state_timeout: zx::MonotonicDuration,
140}
141
142impl InitialContender {
143 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
144 fn into_one_finger_contact_contender(
145 self: Box<Self>,
146 one_finger_contact_event: TouchpadEvent,
147 ) -> Box<dyn gesture_arena::Contender> {
148 Box::new(OneFingerContactContender {
149 one_finger_contact_event,
150 spurious_to_intentional_motion_threshold_mm: self
151 .spurious_to_intentional_motion_threshold_mm,
152 spurious_to_intentional_motion_threshold_button_change_mm: self
153 .spurious_to_intentional_motion_threshold_button_change_mm,
154 button_change_state_timeout: self.button_change_state_timeout,
155 })
156 }
157
158 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
159 fn into_two_finger_contacts_contender(
160 self: Box<Self>,
161 two_finger_contact_event: TouchpadEvent,
162 ) -> Box<dyn gesture_arena::Contender> {
163 Box::new(TwoFingerContactContender {
164 two_finger_contact_event,
165 spurious_to_intentional_motion_threshold_mm: self
166 .spurious_to_intentional_motion_threshold_mm,
167 spurious_to_intentional_motion_threshold_button_change_mm: self
168 .spurious_to_intentional_motion_threshold_button_change_mm,
169 button_change_state_timeout: self.button_change_state_timeout,
170 })
171 }
172
173 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
174 fn into_matched_contender(
175 self: Box<Self>,
176 pressed_event: TouchpadEvent,
177 ) -> Box<dyn gesture_arena::MatchedContender> {
178 Box::new(MatchedContender {
179 pressed_event,
180 spurious_to_intentional_motion_threshold_mm: self
181 .spurious_to_intentional_motion_threshold_mm,
182 spurious_to_intentional_motion_threshold_button_change_mm: self
183 .spurious_to_intentional_motion_threshold_button_change_mm,
184 button_change_state_timeout: self.button_change_state_timeout,
185 })
186 }
187}
188
189impl gesture_arena::Contender for InitialContender {
190 fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
191 let num_pressed_buttons = event.pressed_buttons.len();
192
193 let num_contacts = event.contacts.len();
194 match num_contacts {
195 1 => {
196 if num_pressed_buttons != 0 {
197 return ExamineEventResult::Mismatch(Reason::DetailedUint(
198 DetailedReasonUint {
199 criterion: "num_pressed_buttons",
200 min: Some(0),
201 max: Some(0),
202 actual: num_pressed_buttons,
203 },
204 ));
205 }
206
207 ExamineEventResult::Contender(self.into_one_finger_contact_contender(event.clone()))
208 }
209 2 => {
210 match num_pressed_buttons {
211 0 => ExamineEventResult::Contender(
212 self.into_two_finger_contacts_contender(event.clone()),
213 ),
214 _ => ExamineEventResult::MatchedContender(
217 self.into_matched_contender(event.clone()),
218 ),
219 }
220 }
221 0 | _ => ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
222 criterion: "num_contacts",
223 min: Some(1),
224 max: Some(2),
225 actual: num_contacts,
226 })),
227 }
228 }
229}
230
231impl OneFingerContactContender {
232 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
233 fn into_two_finger_contacts_contender(
234 self: Box<Self>,
235 two_finger_contact_event: TouchpadEvent,
236 ) -> Box<dyn gesture_arena::Contender> {
237 Box::new(TwoFingerContactContender {
238 two_finger_contact_event,
239 spurious_to_intentional_motion_threshold_mm: self
240 .spurious_to_intentional_motion_threshold_mm,
241 spurious_to_intentional_motion_threshold_button_change_mm: self
242 .spurious_to_intentional_motion_threshold_button_change_mm,
243 button_change_state_timeout: self.button_change_state_timeout,
244 })
245 }
246}
247
248impl gesture_arena::Contender for OneFingerContactContender {
249 fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
250 let num_pressed_buttons = event.pressed_buttons.len();
251 if num_pressed_buttons > 0 {
252 return ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
253 criterion: "num_pressed_buttons",
254 min: None,
255 max: Some(0),
256 actual: num_pressed_buttons,
257 }));
258 }
259
260 let num_contacts = event.contacts.len();
261
262 match num_contacts {
263 1 => {
264 let displacement_mm = euclidean_distance(
265 position_from_event(event, 0),
266 position_from_event(&self.one_finger_contact_event, 0),
267 );
268 if displacement_mm >= self.spurious_to_intentional_motion_threshold_mm {
269 return ExamineEventResult::Mismatch(Reason::DetailedFloat(
270 DetailedReasonFloat {
271 criterion: "displacement_mm",
272 min: None,
273 max: Some(self.spurious_to_intentional_motion_threshold_mm),
274 actual: displacement_mm,
275 },
276 ));
277 }
278 ExamineEventResult::Contender(self)
279 }
280 2 => {
281 let displacement_mm = euclidean_distance(
282 position_from_event(event, 0),
283 position_from_event(&self.one_finger_contact_event, 0),
284 );
285 if displacement_mm >= self.spurious_to_intentional_motion_threshold_mm {
286 return ExamineEventResult::Mismatch(Reason::DetailedFloat(
287 DetailedReasonFloat {
288 criterion: "displacement_mm",
289 min: None,
290 max: Some(self.spurious_to_intentional_motion_threshold_mm),
291 actual: displacement_mm,
292 },
293 ));
294 }
295 ExamineEventResult::Contender(
296 self.into_two_finger_contacts_contender(event.clone()),
297 )
298 }
299 _ => ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
300 criterion: "num_contacts",
301 min: Some(1),
302 max: Some(2),
303 actual: num_contacts,
304 })),
305 }
306 }
307}
308
309impl TwoFingerContactContender {
310 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
311 fn into_matched_contender(
312 self: Box<Self>,
313 pressed_event: TouchpadEvent,
314 ) -> Box<dyn gesture_arena::MatchedContender> {
315 Box::new(MatchedContender {
316 pressed_event,
317 spurious_to_intentional_motion_threshold_mm: self
318 .spurious_to_intentional_motion_threshold_mm,
319 spurious_to_intentional_motion_threshold_button_change_mm: self
320 .spurious_to_intentional_motion_threshold_button_change_mm,
321 button_change_state_timeout: self.button_change_state_timeout,
322 })
323 }
324}
325
326impl gesture_arena::Contender for TwoFingerContactContender {
327 fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
328 let num_contacts = event.contacts.len();
329 if num_contacts != 2 {
330 return ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
331 criterion: "num_contacts",
332 min: Some(2),
333 max: Some(2),
334 actual: num_contacts,
335 }));
336 }
337
338 let MovementDetail { euclidean_distance, movement: _ } =
340 movement_from_events(&self.two_finger_contact_event, &event);
341 if euclidean_distance >= self.spurious_to_intentional_motion_threshold_mm {
342 return ExamineEventResult::Mismatch(Reason::DetailedFloat(DetailedReasonFloat {
343 criterion: "displacement_mm",
344 min: None,
345 max: Some(self.spurious_to_intentional_motion_threshold_mm),
346 actual: euclidean_distance,
347 }));
348 }
349
350 let num_pressed_buttons = event.pressed_buttons.len();
351 match num_pressed_buttons {
352 0 => ExamineEventResult::Contender(self),
354 _ => ExamineEventResult::MatchedContender(self.into_matched_contender(event.clone())),
358 }
359 }
360}
361
362impl MatchedContender {
363 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
364 fn into_button_down_winner(self: Box<Self>) -> Box<dyn gesture_arena::Winner> {
365 Box::new(ButtonDownWinner {
366 pressed_event: self.pressed_event,
367 spurious_to_intentional_motion_threshold_mm: self
368 .spurious_to_intentional_motion_threshold_mm,
369 spurious_to_intentional_motion_threshold_button_change_mm: self
370 .spurious_to_intentional_motion_threshold_button_change_mm,
371 button_change_state_timeout: self.button_change_state_timeout,
372 })
373 }
374}
375
376impl gesture_arena::MatchedContender for MatchedContender {
377 fn verify_event(self: Box<Self>, _event: &TouchpadEvent) -> VerifyEventResult {
378 log::error!("Unexpected MatchedContender::verify_event() called");
382
383 VerifyEventResult::MatchedContender(self)
384 }
385
386 fn process_buffered_events(
387 self: Box<Self>,
388 _events: Vec<TouchpadEvent>,
389 ) -> ProcessBufferedEventsResult {
390 ProcessBufferedEventsResult {
392 generated_events: vec![touchpad_event_to_mouse_down_event(&self.pressed_event)],
393 winner: Some(self.into_button_down_winner()),
394 recognized_gesture: RecognizedGesture::SecondaryButtonDown,
395 }
396 }
397}
398
399impl ButtonDownWinner {
400 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
401 fn into_drag_winner(self: Box<Self>) -> Box<dyn gesture_arena::Winner> {
402 Box::new(DragWinner {
403 last_event: self.pressed_event,
404 spurious_to_intentional_motion_threshold_button_change_mm: self
405 .spurious_to_intentional_motion_threshold_button_change_mm,
406 button_change_state_timeout: self.button_change_state_timeout,
407 })
408 }
409
410 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
411 fn into_button_up(
412 self: Box<Self>,
413 button_up_event: TouchpadEvent,
414 ) -> Box<dyn gesture_arena::Winner> {
415 Box::new(ButtonUpWinner {
416 button_up_event,
417 spurious_to_intentional_motion_threshold_button_change_mm: self
418 .spurious_to_intentional_motion_threshold_button_change_mm,
419 button_change_state_timeout: self.button_change_state_timeout,
420 })
421 }
422}
423
424impl gesture_arena::Winner for ButtonDownWinner {
425 fn process_new_event(self: Box<Self>, event: TouchpadEvent) -> ProcessNewEventResult {
426 let motion_threshold =
427 if event.timestamp - self.pressed_event.timestamp > self.button_change_state_timeout {
428 self.spurious_to_intentional_motion_threshold_mm
429 } else {
430 self.spurious_to_intentional_motion_threshold_button_change_mm
431 };
432
433 let MovementDetail { euclidean_distance, movement: _ } =
435 movement_from_events(&self.pressed_event, &event);
436 if euclidean_distance >= motion_threshold {
437 let drag_winner = self.into_drag_winner();
438 return drag_winner.process_new_event(event);
439 }
440
441 let num_pressed_buttons = event.pressed_buttons.len();
442 match num_pressed_buttons {
443 0 => ProcessNewEventResult::ContinueGesture(
446 Some(touchpad_event_to_mouse_up_event(&event)),
447 self.into_button_up(event),
448 ),
449 1 => ProcessNewEventResult::ContinueGesture(None, self),
450 _ => ProcessNewEventResult::ContinueGesture(None, self),
453 }
454 }
455}
456
457impl DragWinner {
458 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
459 fn into_drag_winner(
460 self: Box<Self>,
461 last_event: TouchpadEvent,
462 ) -> Box<dyn gesture_arena::Winner> {
463 Box::new(DragWinner {
464 spurious_to_intentional_motion_threshold_button_change_mm: self
465 .spurious_to_intentional_motion_threshold_button_change_mm,
466 button_change_state_timeout: self.button_change_state_timeout,
467 last_event,
468 })
469 }
470
471 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
472 fn into_button_up(
473 self: Box<Self>,
474 button_up_event: TouchpadEvent,
475 ) -> Box<dyn gesture_arena::Winner> {
476 Box::new(ButtonUpWinner {
477 spurious_to_intentional_motion_threshold_button_change_mm: self
478 .spurious_to_intentional_motion_threshold_button_change_mm,
479 button_change_state_timeout: self.button_change_state_timeout,
480 button_up_event,
481 })
482 }
483}
484
485impl gesture_arena::Winner for DragWinner {
486 fn process_new_event(self: Box<Self>, event: TouchpadEvent) -> ProcessNewEventResult {
487 let num_pressed_buttons = event.pressed_buttons.len();
488 match num_pressed_buttons {
489 0 => ProcessNewEventResult::ContinueGesture(
491 Some(touchpad_event_to_mouse_up_event(&event)),
492 self.into_button_up(event),
493 ),
494 1 | _ => {
495 ProcessNewEventResult::ContinueGesture(
498 Some(touchpad_event_to_mouse_drag_event(&self.last_event, &event)),
499 self.into_drag_winner(event),
500 )
501 }
502 }
503 }
504}
505
506impl gesture_arena::Winner for ButtonUpWinner {
507 fn process_new_event(self: Box<Self>, event: TouchpadEvent) -> ProcessNewEventResult {
508 let num_contacts = event.contacts.len();
510 let num_contacts_button_up = self.button_up_event.contacts.len();
511 if num_contacts != num_contacts_button_up {
512 return ProcessNewEventResult::EndGesture(
513 EndGestureEvent::UnconsumedEvent(event),
514 Reason::DetailedUint(DetailedReasonUint {
515 criterion: "num_contacts",
516 min: Some(num_contacts_button_up as u64),
517 max: Some(num_contacts_button_up as u64),
518 actual: num_contacts,
519 }),
520 );
521 }
522
523 let num_pressed_buttons = event.pressed_buttons.len();
525 if num_pressed_buttons != 0 {
526 return ProcessNewEventResult::EndGesture(
527 EndGestureEvent::UnconsumedEvent(event),
528 Reason::DetailedUint(DetailedReasonUint {
529 criterion: "num_buttons",
530 min: Some(0),
531 max: Some(0),
532 actual: num_pressed_buttons,
533 }),
534 );
535 }
536
537 if event.timestamp - self.button_up_event.timestamp > self.button_change_state_timeout {
539 return ProcessNewEventResult::EndGesture(
540 EndGestureEvent::UnconsumedEvent(event),
541 Reason::Basic("button_up_timeout"),
542 );
543 }
544
545 let MovementDetail { euclidean_distance, movement: _ } =
547 movement_from_events(&self.button_up_event, &event);
548 if euclidean_distance > self.spurious_to_intentional_motion_threshold_button_change_mm {
549 return ProcessNewEventResult::EndGesture(
550 EndGestureEvent::UnconsumedEvent(event),
551 Reason::DetailedFloat(DetailedReasonFloat {
552 criterion: "displacement_mm",
553 min: None,
554 max: Some(self.spurious_to_intentional_motion_threshold_button_change_mm),
555 actual: euclidean_distance,
556 }),
557 );
558 }
559
560 ProcessNewEventResult::ContinueGesture(None, self)
562 }
563}
564
565fn position_from_event(event: &TouchpadEvent, index: usize) -> Position {
568 event.contacts[index].position
569}
570
571fn touchpad_event_to_mouse_down_event(event: &TouchpadEvent) -> gesture_arena::MouseEvent {
572 make_mouse_event(
573 event.timestamp,
574 Position::zero(),
575 MousePhase::Down,
576 hashset! {gesture_arena::SECONDARY_BUTTON},
577 hashset! {gesture_arena::SECONDARY_BUTTON},
578 )
579}
580
581fn touchpad_event_to_mouse_up_event(event: &TouchpadEvent) -> gesture_arena::MouseEvent {
582 make_mouse_event(
583 event.timestamp,
584 Position::zero(),
585 MousePhase::Up,
586 hashset! {gesture_arena::SECONDARY_BUTTON},
587 hashset! {},
588 )
589}
590
591fn touchpad_event_to_mouse_drag_event(
592 last_event: &TouchpadEvent,
593 event: &TouchpadEvent,
594) -> gesture_arena::MouseEvent {
595 let MovementDetail { movement, euclidean_distance: _ } =
596 movement_from_events(last_event, event);
597 make_mouse_event(
598 event.timestamp,
599 movement,
600 MousePhase::Move,
601 hashset! {},
602 hashset! {gesture_arena::SECONDARY_BUTTON},
603 )
604}
605
606fn make_mouse_event(
607 timestamp: zx::MonotonicInstant,
608 movement_in_mm: Position,
609 phase: MousePhase,
610 affected_buttons: HashSet<MouseButton>,
611 pressed_buttons: HashSet<MouseButton>,
612) -> gesture_arena::MouseEvent {
613 gesture_arena::MouseEvent {
614 timestamp,
615 mouse_data: MouseEvent::new(
616 MouseLocation::Relative(RelativeLocation { millimeters: movement_in_mm }),
617 None,
618 None,
619 phase,
620 affected_buttons,
621 pressed_buttons,
622 None,
623 ),
624 }
625}
626
627#[cfg(test)]
628mod test {
629 use super::*;
630 use crate::touch_binding;
631 use assert_matches::assert_matches;
632 use test_case::test_case;
633
634 fn make_touch_contact(id: u32, position: Position) -> touch_binding::TouchContact {
635 touch_binding::TouchContact { id, position, pressure: None, contact_size: None }
636 }
637
638 const SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM: f32 = 10.0;
639 const SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM: f32 = 20.0;
640 const BUTTON_CHANGE_STATE_TIMEOUT: zx::MonotonicDuration =
641 zx::MonotonicDuration::from_seconds(1);
642
643 #[test_case(TouchpadEvent{
644 timestamp: zx::MonotonicInstant::ZERO,
645 pressed_buttons: vec![],
646 contacts: vec![],
647 filtered_palm_contacts: vec![],
648 };"0 fingers")]
649 #[test_case(TouchpadEvent{
650 timestamp: zx::MonotonicInstant::ZERO,
651 pressed_buttons: vec![1],
652 contacts: vec![
653 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
654 ],
655 filtered_palm_contacts: vec![],
656 };"1 fingers button down")]
657 #[test_case(TouchpadEvent{
658 timestamp: zx::MonotonicInstant::ZERO,
659 pressed_buttons: vec![],
660 contacts: vec![
661 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
662 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
663 make_touch_contact(3, Position{x: 10.0, y: 10.0}),
664 ],
665 filtered_palm_contacts: vec![],
666 };"3 fingers")]
667 #[fuchsia::test]
668 fn initial_contender_examine_event_mismatch(event: TouchpadEvent) {
669 let contender: Box<dyn gesture_arena::Contender> = Box::new(InitialContender {
670 spurious_to_intentional_motion_threshold_mm:
671 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
672 spurious_to_intentional_motion_threshold_button_change_mm:
673 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
674 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
675 });
676
677 let got = contender.examine_event(&event);
678 assert_matches!(got, ExamineEventResult::Mismatch(_));
679 }
680
681 #[test_case(TouchpadEvent{
682 timestamp: zx::MonotonicInstant::ZERO,
683 pressed_buttons: vec![],
684 contacts: vec![
685 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
686 ],
687 filtered_palm_contacts: vec![],
688 }, "input_pipeline_lib_test::gestures::secondary_button::OneFingerContactContender";"1 fingers")]
689 #[test_case(TouchpadEvent{
690 timestamp: zx::MonotonicInstant::ZERO,
691 pressed_buttons: vec![],
692 contacts: vec![
693 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
694 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
695 ],
696 filtered_palm_contacts: vec![],
697 }, "input_pipeline_lib_test::gestures::secondary_button::TwoFingerContactContender";"2 fingers")]
698 #[fuchsia::test]
699 fn initial_contender_examine_event_contender(event: TouchpadEvent, contender_name: &str) {
700 let contender: Box<dyn gesture_arena::Contender> = Box::new(InitialContender {
701 spurious_to_intentional_motion_threshold_mm:
702 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
703 spurious_to_intentional_motion_threshold_button_change_mm:
704 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
705 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
706 });
707
708 let got = contender.examine_event(&event);
709 assert_matches!(got, ExamineEventResult::Contender(contender) => {
710 pretty_assertions::assert_eq!(contender.get_type_name(), contender_name);
711 });
712 }
713
714 #[fuchsia::test]
715 fn initial_contender_examine_event_matched_contender() {
716 let contender: Box<dyn gesture_arena::Contender> = Box::new(InitialContender {
717 spurious_to_intentional_motion_threshold_mm:
718 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
719 spurious_to_intentional_motion_threshold_button_change_mm:
720 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
721 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
722 });
723 let event = TouchpadEvent {
724 timestamp: zx::MonotonicInstant::ZERO,
725 pressed_buttons: vec![1],
726 contacts: vec![
727 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
728 make_touch_contact(2, Position { x: 1.0, y: 5.0 }),
729 ],
730 filtered_palm_contacts: vec![],
731 };
732
733 let got = contender.examine_event(&event);
734 assert_matches!(got, ExamineEventResult::MatchedContender(_));
735 }
736
737 #[test_case(TouchpadEvent{
738 timestamp: zx::MonotonicInstant::ZERO,
739 pressed_buttons: vec![],
740 contacts: vec![],
741 filtered_palm_contacts: vec![],
742 };"0 fingers")]
743 #[test_case(TouchpadEvent{
744 timestamp: zx::MonotonicInstant::ZERO,
745 pressed_buttons: vec![1],
746 contacts: vec![
747 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
748 ],
749 filtered_palm_contacts: vec![],
750 };"1 fingers button down")]
751 #[test_case(TouchpadEvent{
752 timestamp: zx::MonotonicInstant::ZERO,
753 pressed_buttons: vec![],
754 contacts: vec![
755 make_touch_contact(1, Position{x: 1.0, y: 12.0}),
756 ],
757 filtered_palm_contacts: vec![],
758 };"1 fingers move more than threshold")]
759 #[test_case(TouchpadEvent{
760 timestamp: zx::MonotonicInstant::ZERO,
761 pressed_buttons: vec![],
762 contacts: vec![
763 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
764 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
765 make_touch_contact(3, Position{x: 10.0, y: 10.0}),
766 ],
767 filtered_palm_contacts: vec![],
768 };"3 fingers")]
769 #[fuchsia::test]
770 fn one_finger_contact_contender_examine_event_mismatch(event: TouchpadEvent) {
771 let contender: Box<dyn gesture_arena::Contender> = Box::new(OneFingerContactContender {
772 one_finger_contact_event: TouchpadEvent {
773 timestamp: zx::MonotonicInstant::ZERO,
774 pressed_buttons: vec![],
775 contacts: vec![make_touch_contact(1, Position { x: 1.0, y: 1.0 })],
776 filtered_palm_contacts: vec![],
777 },
778 spurious_to_intentional_motion_threshold_mm:
779 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
780 spurious_to_intentional_motion_threshold_button_change_mm:
781 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
782 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
783 });
784
785 let got = contender.examine_event(&event);
786 assert_matches!(got, ExamineEventResult::Mismatch(_));
787 }
788
789 #[test_case(TouchpadEvent{
790 timestamp: zx::MonotonicInstant::ZERO,
791 pressed_buttons: vec![],
792 contacts: vec![
793 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
794 ],
795 filtered_palm_contacts: vec![],
796 };"1 fingers hold")]
797 #[test_case(TouchpadEvent{
798 timestamp: zx::MonotonicInstant::ZERO,
799 pressed_buttons: vec![],
800 contacts: vec![
801 make_touch_contact(1, Position{x: 1.0, y: 10.0}),
802 ],
803 filtered_palm_contacts: vec![],
804 };"1 fingers move less than threshold")]
805 #[fuchsia::test]
806 fn one_finger_contact_contender_examine_event_contender(event: TouchpadEvent) {
807 let contender: Box<dyn gesture_arena::Contender> = Box::new(OneFingerContactContender {
808 one_finger_contact_event: TouchpadEvent {
809 timestamp: zx::MonotonicInstant::ZERO,
810 pressed_buttons: vec![],
811 contacts: vec![make_touch_contact(1, Position { x: 1.0, y: 1.0 })],
812 filtered_palm_contacts: vec![],
813 },
814 spurious_to_intentional_motion_threshold_mm:
815 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
816 spurious_to_intentional_motion_threshold_button_change_mm:
817 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
818 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
819 });
820
821 let got = contender.examine_event(&event);
822 assert_matches!(got, ExamineEventResult::Contender(c) => {
823 pretty_assertions::assert_eq!(c.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::OneFingerContactContender");
824 });
825 }
826
827 #[fuchsia::test]
828 fn one_finger_contact_contender_examine_event_two_finger_contact_contender() {
829 let contender: Box<dyn gesture_arena::Contender> = Box::new(OneFingerContactContender {
830 one_finger_contact_event: TouchpadEvent {
831 timestamp: zx::MonotonicInstant::ZERO,
832 pressed_buttons: vec![],
833 contacts: vec![make_touch_contact(1, Position { x: 1.0, y: 1.0 })],
834 filtered_palm_contacts: vec![],
835 },
836 spurious_to_intentional_motion_threshold_mm:
837 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
838 spurious_to_intentional_motion_threshold_button_change_mm:
839 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
840 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
841 });
842
843 let event = TouchpadEvent {
844 timestamp: zx::MonotonicInstant::ZERO,
845 pressed_buttons: vec![],
846 contacts: vec![
847 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
848 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
849 ],
850 filtered_palm_contacts: vec![],
851 };
852 let got = contender.examine_event(&event);
853 assert_matches!(got, ExamineEventResult::Contender(c) => {
854 pretty_assertions::assert_eq!(c.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::TwoFingerContactContender");
855 });
856 }
857
858 #[test_case(TouchpadEvent{
859 timestamp: zx::MonotonicInstant::ZERO,
860 pressed_buttons: vec![],
861 contacts: vec![],
862 filtered_palm_contacts: vec![],
863 };"0 fingers")]
864 #[test_case(TouchpadEvent{
865 timestamp: zx::MonotonicInstant::ZERO,
866 pressed_buttons: vec![],
867 contacts: vec![
868 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
869 ],
870 filtered_palm_contacts: vec![],
871 };"1 fingers")]
872 #[test_case(TouchpadEvent{
873 timestamp: zx::MonotonicInstant::ZERO,
874 pressed_buttons: vec![],
875 contacts: vec![
876 make_touch_contact(1, Position{x: 1.0, y: 12.0}),
877 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
878 ],
879 filtered_palm_contacts: vec![],
880 };"2 fingers move more than threshold")]
881 #[test_case(TouchpadEvent{
882 timestamp: zx::MonotonicInstant::ZERO,
883 pressed_buttons: vec![],
884 contacts: vec![
885 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
886 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
887 make_touch_contact(3, Position{x: 10.0, y: 10.0}),
888 ],
889 filtered_palm_contacts: vec![],
890 };"3 fingers")]
891 #[fuchsia::test]
892 fn two_finger_contact_contender_examine_event_mismatch(event: TouchpadEvent) {
893 let contender: Box<dyn gesture_arena::Contender> = Box::new(TwoFingerContactContender {
894 two_finger_contact_event: TouchpadEvent {
895 timestamp: zx::MonotonicInstant::ZERO,
896 pressed_buttons: vec![],
897 contacts: vec![
898 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
899 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
900 ],
901 filtered_palm_contacts: vec![],
902 },
903 spurious_to_intentional_motion_threshold_mm:
904 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
905 spurious_to_intentional_motion_threshold_button_change_mm:
906 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
907 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
908 });
909
910 let got = contender.examine_event(&event);
911 assert_matches!(got, ExamineEventResult::Mismatch(_));
912 }
913
914 #[test_case(TouchpadEvent{
915 timestamp: zx::MonotonicInstant::ZERO,
916 pressed_buttons: vec![],
917 contacts: vec![
918 make_touch_contact(1, Position{x: 1.0, y: 9.0}),
919 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
920 ],
921 filtered_palm_contacts: vec![],
922 };"2 fingers move less than threshold")]
923 #[test_case(TouchpadEvent{
924 timestamp: zx::MonotonicInstant::ZERO,
925 pressed_buttons: vec![],
926 contacts: vec![
927 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
928 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
929 ],
930 filtered_palm_contacts: vec![],
931 };"2 fingers hold")]
932 #[fuchsia::test]
933 fn two_finger_contact_contender_examine_event_contender(event: TouchpadEvent) {
934 let contender: Box<dyn gesture_arena::Contender> = Box::new(TwoFingerContactContender {
935 two_finger_contact_event: TouchpadEvent {
936 timestamp: zx::MonotonicInstant::ZERO,
937 pressed_buttons: vec![],
938 contacts: vec![
939 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
940 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
941 ],
942 filtered_palm_contacts: vec![],
943 },
944 spurious_to_intentional_motion_threshold_mm:
945 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
946 spurious_to_intentional_motion_threshold_button_change_mm:
947 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
948 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
949 });
950
951 let got = contender.examine_event(&event);
952 assert_matches!(got, ExamineEventResult::Contender(c) => {
953 pretty_assertions::assert_eq!(c.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::TwoFingerContactContender");
954 });
955 }
956
957 #[fuchsia::test]
958 fn two_finger_contact_contender_examine_event_matched_contender() {
959 let contender: Box<dyn gesture_arena::Contender> = Box::new(TwoFingerContactContender {
960 two_finger_contact_event: TouchpadEvent {
961 timestamp: zx::MonotonicInstant::ZERO,
962 pressed_buttons: vec![],
963 contacts: vec![
964 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
965 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
966 ],
967 filtered_palm_contacts: vec![],
968 },
969 spurious_to_intentional_motion_threshold_mm:
970 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
971 spurious_to_intentional_motion_threshold_button_change_mm:
972 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
973 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
974 });
975
976 let event = TouchpadEvent {
977 timestamp: zx::MonotonicInstant::ZERO,
978 pressed_buttons: vec![1],
979 contacts: vec![
980 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
981 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
982 ],
983 filtered_palm_contacts: vec![],
984 };
985 let got = contender.examine_event(&event);
986 assert_matches!(got, ExamineEventResult::MatchedContender(_));
987 }
988
989 #[fuchsia::test]
990 fn matched_contender_process_buffered_events() {
991 let contender: Box<dyn gesture_arena::MatchedContender> = Box::new(MatchedContender {
992 spurious_to_intentional_motion_threshold_mm:
993 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
994 spurious_to_intentional_motion_threshold_button_change_mm:
995 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
996 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
997 pressed_event: TouchpadEvent {
998 timestamp: zx::MonotonicInstant::from_nanos(41),
999 pressed_buttons: vec![1],
1000 contacts: vec![
1001 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1002 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
1003 ],
1004 filtered_palm_contacts: vec![],
1005 },
1006 });
1007 let events = vec![
1008 TouchpadEvent {
1009 timestamp: zx::MonotonicInstant::ZERO,
1010 pressed_buttons: vec![],
1011 contacts: vec![make_touch_contact(1, Position { x: 1.0, y: 1.0 })],
1012 filtered_palm_contacts: vec![],
1013 },
1014 TouchpadEvent {
1016 timestamp: zx::MonotonicInstant::ZERO,
1017 pressed_buttons: vec![],
1018 contacts: vec![make_touch_contact(1, Position { x: 1.0, y: 9.0 })],
1019 filtered_palm_contacts: vec![],
1020 },
1021 TouchpadEvent {
1022 timestamp: zx::MonotonicInstant::from_nanos(21),
1023 pressed_buttons: vec![],
1024 contacts: vec![
1025 make_touch_contact(1, Position { x: 1.0, y: 9.0 }),
1026 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
1027 ],
1028 filtered_palm_contacts: vec![],
1029 },
1030 TouchpadEvent {
1032 timestamp: zx::MonotonicInstant::from_nanos(21),
1033 pressed_buttons: vec![],
1034 contacts: vec![
1035 make_touch_contact(1, Position { x: 1.0, y: 9.0 }),
1036 make_touch_contact(2, Position { x: 5.0, y: 14.0 }),
1037 ],
1038 filtered_palm_contacts: vec![],
1039 },
1040 TouchpadEvent {
1041 timestamp: zx::MonotonicInstant::from_nanos(41),
1042 pressed_buttons: vec![1],
1043 contacts: vec![
1044 make_touch_contact(1, Position { x: 1.0, y: 9.0 }),
1045 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
1046 ],
1047 filtered_palm_contacts: vec![],
1048 },
1049 ];
1050
1051 let got = contender.process_buffered_events(events);
1052
1053 assert_matches!(got, ProcessBufferedEventsResult{
1054 generated_events,
1055 winner: Some(winner),
1056 recognized_gesture: RecognizedGesture::SecondaryButtonDown,
1057 } => {
1058 pretty_assertions::assert_eq!(generated_events, vec![
1059 gesture_arena::MouseEvent {
1060 timestamp:zx::MonotonicInstant::from_nanos(41),
1061 mouse_data: MouseEvent::new(
1062 MouseLocation::Relative(RelativeLocation {
1063 millimeters: Position { x: 0.0, y: 0.0 },
1064 }),
1065 None,
1066 None,
1067 MousePhase::Down,
1068 hashset!{gesture_arena::SECONDARY_BUTTON},
1069 hashset!{gesture_arena::SECONDARY_BUTTON},
1070 None,
1071 ),
1072 }
1073 ]);
1074 pretty_assertions::assert_eq!(winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonDownWinner");
1075 });
1076 }
1077
1078 #[test_case(TouchpadEvent{
1079 timestamp: zx::MonotonicInstant::from_nanos(41),
1080 pressed_buttons: vec![],
1081 contacts: vec![
1082 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1083 ],
1084 filtered_palm_contacts: vec![],
1085 };"1 finger button release")]
1086 #[test_case(TouchpadEvent{
1087 timestamp: zx::MonotonicInstant::from_nanos(41),
1088 pressed_buttons: vec![],
1089 contacts: vec![
1090 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1091 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1092 ],
1093 filtered_palm_contacts: vec![],
1094 };"2 finger button release")]
1095 #[test_case(TouchpadEvent{
1096 timestamp: zx::MonotonicInstant::from_nanos(41),
1097 pressed_buttons: vec![],
1098 contacts: vec![
1099 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1100 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1101 make_touch_contact(2, Position{x: 15.0, y: 15.0}),
1102 ],
1103 filtered_palm_contacts: vec![],
1104 };"3 finger button release")]
1105 #[test_case(TouchpadEvent{
1106 timestamp: zx::MonotonicInstant::from_nanos(41),
1107 pressed_buttons: vec![],
1108 contacts: vec![
1109 make_touch_contact(1, Position{x: 19.0, y: 1.0}),
1110 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1111 ],
1112 filtered_palm_contacts: vec![],
1113 };"move less than threshold in button change state")]
1114 #[test_case(TouchpadEvent{
1115 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1500),
1116 pressed_buttons: vec![],
1117 contacts: vec![
1118 make_touch_contact(1, Position{x: 9.0, y: 1.0}),
1119 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1120 ],
1121 filtered_palm_contacts: vec![],
1122 };"move less than threshold out of button change state")]
1123 #[test_case(TouchpadEvent{
1124 timestamp: zx::MonotonicInstant::from_nanos(41),
1125 pressed_buttons: vec![],
1126 contacts: vec![
1127 make_touch_contact(1, Position{x: 21.0, y: 1.0}),
1128 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1129 ],
1130 filtered_palm_contacts: vec![],
1131 };"move more than threshold in button change state")]
1132 #[test_case(TouchpadEvent{
1133 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1500),
1134 pressed_buttons: vec![],
1135 contacts: vec![
1136 make_touch_contact(1, Position{x: 11.0, y: 1.0}),
1137 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1138 ],
1139 filtered_palm_contacts: vec![],
1140 };"move more than threshold out of button change state")]
1141 #[fuchsia::test]
1142 fn button_down_winner_button_up(event: TouchpadEvent) {
1143 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonDownWinner {
1144 spurious_to_intentional_motion_threshold_mm:
1145 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
1146 spurious_to_intentional_motion_threshold_button_change_mm:
1147 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1148 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1149 pressed_event: TouchpadEvent {
1150 timestamp: zx::MonotonicInstant::ZERO,
1151 pressed_buttons: vec![1],
1152 contacts: vec![
1153 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1154 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1155 ],
1156 filtered_palm_contacts: vec![],
1157 },
1158 });
1159
1160 let got = winner.process_new_event(event);
1161 assert_matches!(got, ProcessNewEventResult::ContinueGesture(Some(gesture_arena::MouseEvent {mouse_data, ..}), got_winner) => {
1162 pretty_assertions::assert_eq!(mouse_data, MouseEvent::new(
1163 MouseLocation::Relative(RelativeLocation {
1164 millimeters: Position { x: 0.0, y: 0.0 },
1165 }),
1166 None,
1167 None,
1168 MousePhase::Up,
1169 hashset!{gesture_arena::SECONDARY_BUTTON},
1170 hashset!{},
1171 None,
1172 ));
1173 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonUpWinner");
1174 });
1175 }
1176
1177 #[test_case(TouchpadEvent{
1178 timestamp: zx::MonotonicInstant::from_nanos(41),
1179 pressed_buttons: vec![1],
1180 contacts: vec![
1181 make_touch_contact(1, Position{x: 20.0, y: 1.0}),
1182 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1183 ],
1184 filtered_palm_contacts: vec![],
1185 };"move less than threshold in button change state")]
1186 #[test_case(TouchpadEvent{
1187 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1500),
1188 pressed_buttons: vec![1],
1189 contacts: vec![
1190 make_touch_contact(1, Position{x: 10.0, y: 1.0}),
1191 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1192 ],
1193 filtered_palm_contacts: vec![],
1194 };"move less than threshold out of button change state")]
1195 #[fuchsia::test]
1196 fn button_down_winner_continue(event: TouchpadEvent) {
1197 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonDownWinner {
1198 spurious_to_intentional_motion_threshold_mm:
1199 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
1200 spurious_to_intentional_motion_threshold_button_change_mm:
1201 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1202 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1203 pressed_event: TouchpadEvent {
1204 timestamp: zx::MonotonicInstant::ZERO,
1205 pressed_buttons: vec![1],
1206 contacts: vec![
1207 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1208 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1209 ],
1210 filtered_palm_contacts: vec![],
1211 },
1212 });
1213
1214 let got = winner.process_new_event(event);
1215 assert_matches!(got, ProcessNewEventResult::ContinueGesture(None, got_winner)=>{
1216 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonDownWinner");
1217 });
1218 }
1219
1220 #[test_case(TouchpadEvent{
1221 timestamp: zx::MonotonicInstant::from_nanos(41),
1222 pressed_buttons: vec![1],
1223 contacts: vec![
1224 make_touch_contact(1, Position{x: 21.0, y: 1.0}),
1225 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1226 ],
1227 filtered_palm_contacts: vec![],
1228 };"move more than threshold in button change state")]
1229 #[test_case(TouchpadEvent{
1230 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1500),
1231 pressed_buttons: vec![1],
1232 contacts: vec![
1233 make_touch_contact(1, Position{x: 11.0, y: 1.0}),
1234 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1235 ],
1236 filtered_palm_contacts: vec![],
1237 };"move more than threshold out of button change state")]
1238 #[fuchsia::test]
1239 fn button_down_winner_drag_winner_continue(event: TouchpadEvent) {
1240 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonDownWinner {
1241 spurious_to_intentional_motion_threshold_mm:
1242 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
1243 spurious_to_intentional_motion_threshold_button_change_mm:
1244 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1245 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1246 pressed_event: TouchpadEvent {
1247 timestamp: zx::MonotonicInstant::ZERO,
1248 pressed_buttons: vec![1],
1249 contacts: vec![
1250 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1251 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1252 ],
1253 filtered_palm_contacts: vec![],
1254 },
1255 });
1256
1257 let got = winner.process_new_event(event);
1258 assert_matches!(got, ProcessNewEventResult::ContinueGesture(Some(gesture_arena::MouseEvent {mouse_data, ..}), got_winner)=>{
1259 pretty_assertions::assert_eq!(mouse_data.phase, MousePhase::Move);
1260 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::DragWinner");
1261 });
1262 }
1263
1264 #[test_case(TouchpadEvent{
1265 timestamp: zx::MonotonicInstant::from_nanos(41),
1266 pressed_buttons: vec![],
1267 contacts: vec![
1268 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1269 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1270 ],
1271 filtered_palm_contacts: vec![],
1272 };"button release")]
1273 #[test_case(TouchpadEvent{
1274 timestamp: zx::MonotonicInstant::from_nanos(41),
1275 pressed_buttons: vec![],
1276 contacts: vec![
1277 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1278 ],
1279 filtered_palm_contacts: vec![],
1280 };"1 finger button release")]
1281 #[test_case(TouchpadEvent{
1282 timestamp: zx::MonotonicInstant::from_nanos(41),
1283 pressed_buttons: vec![],
1284 contacts: vec![
1285 make_touch_contact(1, Position{x: 21.0, y: 1.0}),
1286 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1287 ],
1288 filtered_palm_contacts: vec![],
1289 };"large move and button release")]
1290 #[fuchsia::test]
1291 fn drag_winner_button_up(event: TouchpadEvent) {
1292 let winner: Box<dyn gesture_arena::Winner> = Box::new(DragWinner {
1293 spurious_to_intentional_motion_threshold_button_change_mm:
1294 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1295 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1296 last_event: TouchpadEvent {
1297 timestamp: zx::MonotonicInstant::ZERO,
1298 pressed_buttons: vec![1],
1299 contacts: vec![
1300 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1301 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1302 ],
1303 filtered_palm_contacts: vec![],
1304 },
1305 });
1306
1307 let got = winner.process_new_event(event);
1308 assert_matches!(got, ProcessNewEventResult::ContinueGesture(Some(gesture_arena::MouseEvent {mouse_data, ..}), got_winner) => {
1309 pretty_assertions::assert_eq!(mouse_data, MouseEvent::new(
1310 MouseLocation::Relative(RelativeLocation {
1311 millimeters: Position { x: 0.0, y: 0.0 },
1312 }),
1313 None,
1314 None,
1315 MousePhase::Up,
1316 hashset!{gesture_arena::SECONDARY_BUTTON},
1317 hashset!{},
1318 None,
1319 ));
1320 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonUpWinner");
1321 });
1322 }
1323
1324 #[test_case(TouchpadEvent{
1325 timestamp: zx::MonotonicInstant::from_nanos(41),
1326 pressed_buttons: vec![1],
1327 contacts: vec![
1328 make_touch_contact(1, Position{x: 19.0, y: 1.0}),
1329 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1330 ],
1331 filtered_palm_contacts: vec![],
1332 };"2 finger")]
1333 #[test_case(TouchpadEvent{
1334 timestamp: zx::MonotonicInstant::from_nanos(41),
1335 pressed_buttons: vec![1],
1336 contacts: vec![
1337 make_touch_contact(1, Position{x: 19.0, y: 1.0}),
1338 ],
1339 filtered_palm_contacts: vec![],
1340 };"1 finger")]
1341 #[fuchsia::test]
1342 fn drag_winner_continue(event: TouchpadEvent) {
1343 let winner: Box<dyn gesture_arena::Winner> = Box::new(DragWinner {
1344 spurious_to_intentional_motion_threshold_button_change_mm:
1345 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1346 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1347 last_event: TouchpadEvent {
1348 timestamp: zx::MonotonicInstant::ZERO,
1349 pressed_buttons: vec![1],
1350 contacts: vec![
1351 make_touch_contact(1, Position { x: 0.0, y: 0.0 }),
1352 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1353 ],
1354 filtered_palm_contacts: vec![],
1355 },
1356 });
1357
1358 let got = winner.process_new_event(event);
1359 assert_matches!(got, ProcessNewEventResult::ContinueGesture(Some(gesture_arena::MouseEvent {mouse_data, ..}), got_winner)=>{
1360 pretty_assertions::assert_eq!(mouse_data, MouseEvent::new(
1361 MouseLocation::Relative(RelativeLocation {
1362 millimeters: Position { x: 19.0, y: 1.0 },
1363 }),
1364 None,
1365 None,
1366 MousePhase::Move,
1367 hashset!{},
1368 hashset!{gesture_arena::SECONDARY_BUTTON},
1369 None,
1370 ));
1371 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::DragWinner");
1372 });
1373 }
1374
1375 #[fuchsia::test]
1376 fn button_up_winner_continue() {
1377 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonUpWinner {
1378 spurious_to_intentional_motion_threshold_button_change_mm:
1379 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1380 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1381 button_up_event: TouchpadEvent {
1382 timestamp: zx::MonotonicInstant::ZERO,
1383 pressed_buttons: vec![],
1384 contacts: vec![
1385 make_touch_contact(1, Position { x: 0.0, y: 0.0 }),
1386 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1387 ],
1388 filtered_palm_contacts: vec![],
1389 },
1390 });
1391
1392 let event = TouchpadEvent {
1393 timestamp: zx::MonotonicInstant::from_nanos(41),
1394 pressed_buttons: vec![],
1395 contacts: vec![
1396 make_touch_contact(1, Position { x: 10.0, y: 1.0 }),
1397 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1398 ],
1399 filtered_palm_contacts: vec![],
1400 };
1401
1402 let got = winner.process_new_event(event);
1403 assert_matches!(got, ProcessNewEventResult::ContinueGesture(None, got_winner)=>{
1404 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonUpWinner");
1405 });
1406 }
1407
1408 #[test_case(TouchpadEvent{
1409 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1_001),
1410 pressed_buttons: vec![],
1411 contacts: vec![
1412 make_touch_contact(1, Position{x: 0.0, y: 0.0}),
1413 ],
1414 filtered_palm_contacts: vec![],
1415 };"timeout")]
1416 #[test_case(TouchpadEvent{
1417 timestamp: zx::MonotonicInstant::from_nanos(41),
1418 pressed_buttons: vec![1],
1419 contacts: vec![
1420 make_touch_contact(1, Position{x: 0.0, y: 0.0}),
1421 ],
1422 filtered_palm_contacts: vec![],
1423 };"button down")]
1424 #[test_case(TouchpadEvent{
1425 timestamp: zx::MonotonicInstant::from_nanos(41),
1426 pressed_buttons: vec![],
1427 contacts: vec![
1428 make_touch_contact(1, Position{x: 21.0, y: 0.0}),
1429 ],
1430 filtered_palm_contacts: vec![],
1431 };"move more than threshold")]
1432 #[test_case(TouchpadEvent{
1433 timestamp: zx::MonotonicInstant::from_nanos(41),
1434 pressed_buttons: vec![],
1435 contacts: vec![
1436 make_touch_contact(1, Position{x: 0.0, y: 0.0}),
1437 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1438 make_touch_contact(3, Position{x: 15.0, y: 15.0}),
1439 ],
1440 filtered_palm_contacts: vec![],
1441 };"more contacts")]
1442 #[test_case(TouchpadEvent{
1443 timestamp: zx::MonotonicInstant::from_nanos(41),
1444 pressed_buttons: vec![],
1445 contacts: vec![
1446 make_touch_contact(1, Position{x: 0.0, y: 0.0}),
1447 ],
1448 filtered_palm_contacts: vec![],
1449 };"less contacts")]
1450 #[test_case(TouchpadEvent{
1451 timestamp: zx::MonotonicInstant::from_nanos(41),
1452 pressed_buttons: vec![],
1453 contacts: vec![],
1454 filtered_palm_contacts: vec![],
1455 };"no contact")]
1456 #[fuchsia::test]
1457 fn button_up_winner_end(event: TouchpadEvent) {
1458 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonUpWinner {
1459 spurious_to_intentional_motion_threshold_button_change_mm:
1460 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1461 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1462 button_up_event: TouchpadEvent {
1463 timestamp: zx::MonotonicInstant::ZERO,
1464 pressed_buttons: vec![],
1465 contacts: vec![
1466 make_touch_contact(1, Position { x: 0.0, y: 0.0 }),
1467 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1468 ],
1469 filtered_palm_contacts: vec![],
1470 },
1471 });
1472
1473 let got = winner.process_new_event(event);
1474 assert_matches!(
1475 got,
1476 ProcessNewEventResult::EndGesture(EndGestureEvent::UnconsumedEvent(_), _)
1477 );
1478 }
1479}