1use super::gesture_arena::{
6 self, DetailedReasonFloat, DetailedReasonUint, EndGestureEvent, ExamineEventResult,
7 ProcessBufferedEventsResult, ProcessNewEventResult, Reason, RecognizedGesture, TouchpadEvent,
8 VerifyEventResult,
9};
10use super::utils::{MovementDetail, movement_from_events};
11use crate::mouse_binding::{MouseButton, MouseEvent, MouseLocation, MousePhase, RelativeLocation};
12use crate::utils::{Position, euclidean_distance};
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 None,
624 ),
625 }
626}
627
628#[cfg(test)]
629mod test {
630 use super::*;
631 use crate::touch_binding;
632 use assert_matches::assert_matches;
633 use test_case::test_case;
634
635 fn make_touch_contact(id: u32, position: Position) -> touch_binding::TouchContact {
636 touch_binding::TouchContact { id, position, pressure: None, contact_size: None }
637 }
638
639 const SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM: f32 = 10.0;
640 const SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM: f32 = 20.0;
641 const BUTTON_CHANGE_STATE_TIMEOUT: zx::MonotonicDuration =
642 zx::MonotonicDuration::from_seconds(1);
643
644 #[test_case(TouchpadEvent{
645 timestamp: zx::MonotonicInstant::ZERO,
646 pressed_buttons: vec![],
647 contacts: vec![],
648 filtered_palm_contacts: vec![],
649 };"0 fingers")]
650 #[test_case(TouchpadEvent{
651 timestamp: zx::MonotonicInstant::ZERO,
652 pressed_buttons: vec![1],
653 contacts: vec![
654 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
655 ],
656 filtered_palm_contacts: vec![],
657 };"1 fingers button down")]
658 #[test_case(TouchpadEvent{
659 timestamp: zx::MonotonicInstant::ZERO,
660 pressed_buttons: vec![],
661 contacts: vec![
662 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
663 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
664 make_touch_contact(3, Position{x: 10.0, y: 10.0}),
665 ],
666 filtered_palm_contacts: vec![],
667 };"3 fingers")]
668 #[fuchsia::test]
669 fn initial_contender_examine_event_mismatch(event: TouchpadEvent) {
670 let contender: Box<dyn gesture_arena::Contender> = Box::new(InitialContender {
671 spurious_to_intentional_motion_threshold_mm:
672 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
673 spurious_to_intentional_motion_threshold_button_change_mm:
674 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
675 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
676 });
677
678 let got = contender.examine_event(&event);
679 assert_matches!(got, ExamineEventResult::Mismatch(_));
680 }
681
682 #[test_case(TouchpadEvent{
683 timestamp: zx::MonotonicInstant::ZERO,
684 pressed_buttons: vec![],
685 contacts: vec![
686 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
687 ],
688 filtered_palm_contacts: vec![],
689 }, "input_pipeline_lib_test::gestures::secondary_button::OneFingerContactContender";"1 fingers")]
690 #[test_case(TouchpadEvent{
691 timestamp: zx::MonotonicInstant::ZERO,
692 pressed_buttons: vec![],
693 contacts: vec![
694 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
695 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
696 ],
697 filtered_palm_contacts: vec![],
698 }, "input_pipeline_lib_test::gestures::secondary_button::TwoFingerContactContender";"2 fingers")]
699 #[fuchsia::test]
700 fn initial_contender_examine_event_contender(event: TouchpadEvent, contender_name: &str) {
701 let contender: Box<dyn gesture_arena::Contender> = Box::new(InitialContender {
702 spurious_to_intentional_motion_threshold_mm:
703 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
704 spurious_to_intentional_motion_threshold_button_change_mm:
705 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
706 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
707 });
708
709 let got = contender.examine_event(&event);
710 assert_matches!(got, ExamineEventResult::Contender(contender) => {
711 pretty_assertions::assert_eq!(contender.get_type_name(), contender_name);
712 });
713 }
714
715 #[fuchsia::test]
716 fn initial_contender_examine_event_matched_contender() {
717 let contender: Box<dyn gesture_arena::Contender> = Box::new(InitialContender {
718 spurious_to_intentional_motion_threshold_mm:
719 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
720 spurious_to_intentional_motion_threshold_button_change_mm:
721 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
722 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
723 });
724 let event = TouchpadEvent {
725 timestamp: zx::MonotonicInstant::ZERO,
726 pressed_buttons: vec![1],
727 contacts: vec![
728 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
729 make_touch_contact(2, Position { x: 1.0, y: 5.0 }),
730 ],
731 filtered_palm_contacts: vec![],
732 };
733
734 let got = contender.examine_event(&event);
735 assert_matches!(got, ExamineEventResult::MatchedContender(_));
736 }
737
738 #[test_case(TouchpadEvent{
739 timestamp: zx::MonotonicInstant::ZERO,
740 pressed_buttons: vec![],
741 contacts: vec![],
742 filtered_palm_contacts: vec![],
743 };"0 fingers")]
744 #[test_case(TouchpadEvent{
745 timestamp: zx::MonotonicInstant::ZERO,
746 pressed_buttons: vec![1],
747 contacts: vec![
748 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
749 ],
750 filtered_palm_contacts: vec![],
751 };"1 fingers button down")]
752 #[test_case(TouchpadEvent{
753 timestamp: zx::MonotonicInstant::ZERO,
754 pressed_buttons: vec![],
755 contacts: vec![
756 make_touch_contact(1, Position{x: 1.0, y: 12.0}),
757 ],
758 filtered_palm_contacts: vec![],
759 };"1 fingers move more than threshold")]
760 #[test_case(TouchpadEvent{
761 timestamp: zx::MonotonicInstant::ZERO,
762 pressed_buttons: vec![],
763 contacts: vec![
764 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
765 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
766 make_touch_contact(3, Position{x: 10.0, y: 10.0}),
767 ],
768 filtered_palm_contacts: vec![],
769 };"3 fingers")]
770 #[fuchsia::test]
771 fn one_finger_contact_contender_examine_event_mismatch(event: TouchpadEvent) {
772 let contender: Box<dyn gesture_arena::Contender> = Box::new(OneFingerContactContender {
773 one_finger_contact_event: TouchpadEvent {
774 timestamp: zx::MonotonicInstant::ZERO,
775 pressed_buttons: vec![],
776 contacts: vec![make_touch_contact(1, Position { x: 1.0, y: 1.0 })],
777 filtered_palm_contacts: vec![],
778 },
779 spurious_to_intentional_motion_threshold_mm:
780 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
781 spurious_to_intentional_motion_threshold_button_change_mm:
782 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
783 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
784 });
785
786 let got = contender.examine_event(&event);
787 assert_matches!(got, ExamineEventResult::Mismatch(_));
788 }
789
790 #[test_case(TouchpadEvent{
791 timestamp: zx::MonotonicInstant::ZERO,
792 pressed_buttons: vec![],
793 contacts: vec![
794 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
795 ],
796 filtered_palm_contacts: vec![],
797 };"1 fingers hold")]
798 #[test_case(TouchpadEvent{
799 timestamp: zx::MonotonicInstant::ZERO,
800 pressed_buttons: vec![],
801 contacts: vec![
802 make_touch_contact(1, Position{x: 1.0, y: 10.0}),
803 ],
804 filtered_palm_contacts: vec![],
805 };"1 fingers move less than threshold")]
806 #[fuchsia::test]
807 fn one_finger_contact_contender_examine_event_contender(event: TouchpadEvent) {
808 let contender: Box<dyn gesture_arena::Contender> = Box::new(OneFingerContactContender {
809 one_finger_contact_event: TouchpadEvent {
810 timestamp: zx::MonotonicInstant::ZERO,
811 pressed_buttons: vec![],
812 contacts: vec![make_touch_contact(1, Position { x: 1.0, y: 1.0 })],
813 filtered_palm_contacts: vec![],
814 },
815 spurious_to_intentional_motion_threshold_mm:
816 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
817 spurious_to_intentional_motion_threshold_button_change_mm:
818 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
819 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
820 });
821
822 let got = contender.examine_event(&event);
823 assert_matches!(got, ExamineEventResult::Contender(c) => {
824 pretty_assertions::assert_eq!(c.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::OneFingerContactContender");
825 });
826 }
827
828 #[fuchsia::test]
829 fn one_finger_contact_contender_examine_event_two_finger_contact_contender() {
830 let contender: Box<dyn gesture_arena::Contender> = Box::new(OneFingerContactContender {
831 one_finger_contact_event: TouchpadEvent {
832 timestamp: zx::MonotonicInstant::ZERO,
833 pressed_buttons: vec![],
834 contacts: vec![make_touch_contact(1, Position { x: 1.0, y: 1.0 })],
835 filtered_palm_contacts: vec![],
836 },
837 spurious_to_intentional_motion_threshold_mm:
838 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
839 spurious_to_intentional_motion_threshold_button_change_mm:
840 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
841 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
842 });
843
844 let event = TouchpadEvent {
845 timestamp: zx::MonotonicInstant::ZERO,
846 pressed_buttons: vec![],
847 contacts: vec![
848 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
849 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
850 ],
851 filtered_palm_contacts: vec![],
852 };
853 let got = contender.examine_event(&event);
854 assert_matches!(got, ExamineEventResult::Contender(c) => {
855 pretty_assertions::assert_eq!(c.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::TwoFingerContactContender");
856 });
857 }
858
859 #[test_case(TouchpadEvent{
860 timestamp: zx::MonotonicInstant::ZERO,
861 pressed_buttons: vec![],
862 contacts: vec![],
863 filtered_palm_contacts: vec![],
864 };"0 fingers")]
865 #[test_case(TouchpadEvent{
866 timestamp: zx::MonotonicInstant::ZERO,
867 pressed_buttons: vec![],
868 contacts: vec![
869 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
870 ],
871 filtered_palm_contacts: vec![],
872 };"1 fingers")]
873 #[test_case(TouchpadEvent{
874 timestamp: zx::MonotonicInstant::ZERO,
875 pressed_buttons: vec![],
876 contacts: vec![
877 make_touch_contact(1, Position{x: 1.0, y: 12.0}),
878 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
879 ],
880 filtered_palm_contacts: vec![],
881 };"2 fingers move more than threshold")]
882 #[test_case(TouchpadEvent{
883 timestamp: zx::MonotonicInstant::ZERO,
884 pressed_buttons: vec![],
885 contacts: vec![
886 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
887 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
888 make_touch_contact(3, Position{x: 10.0, y: 10.0}),
889 ],
890 filtered_palm_contacts: vec![],
891 };"3 fingers")]
892 #[fuchsia::test]
893 fn two_finger_contact_contender_examine_event_mismatch(event: TouchpadEvent) {
894 let contender: Box<dyn gesture_arena::Contender> = Box::new(TwoFingerContactContender {
895 two_finger_contact_event: TouchpadEvent {
896 timestamp: zx::MonotonicInstant::ZERO,
897 pressed_buttons: vec![],
898 contacts: vec![
899 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
900 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
901 ],
902 filtered_palm_contacts: vec![],
903 },
904 spurious_to_intentional_motion_threshold_mm:
905 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
906 spurious_to_intentional_motion_threshold_button_change_mm:
907 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
908 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
909 });
910
911 let got = contender.examine_event(&event);
912 assert_matches!(got, ExamineEventResult::Mismatch(_));
913 }
914
915 #[test_case(TouchpadEvent{
916 timestamp: zx::MonotonicInstant::ZERO,
917 pressed_buttons: vec![],
918 contacts: vec![
919 make_touch_contact(1, Position{x: 1.0, y: 9.0}),
920 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
921 ],
922 filtered_palm_contacts: vec![],
923 };"2 fingers move less than threshold")]
924 #[test_case(TouchpadEvent{
925 timestamp: zx::MonotonicInstant::ZERO,
926 pressed_buttons: vec![],
927 contacts: vec![
928 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
929 make_touch_contact(2, Position{x: 5.0, y: 5.0}),
930 ],
931 filtered_palm_contacts: vec![],
932 };"2 fingers hold")]
933 #[fuchsia::test]
934 fn two_finger_contact_contender_examine_event_contender(event: TouchpadEvent) {
935 let contender: Box<dyn gesture_arena::Contender> = Box::new(TwoFingerContactContender {
936 two_finger_contact_event: TouchpadEvent {
937 timestamp: zx::MonotonicInstant::ZERO,
938 pressed_buttons: vec![],
939 contacts: vec![
940 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
941 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
942 ],
943 filtered_palm_contacts: vec![],
944 },
945 spurious_to_intentional_motion_threshold_mm:
946 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
947 spurious_to_intentional_motion_threshold_button_change_mm:
948 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
949 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
950 });
951
952 let got = contender.examine_event(&event);
953 assert_matches!(got, ExamineEventResult::Contender(c) => {
954 pretty_assertions::assert_eq!(c.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::TwoFingerContactContender");
955 });
956 }
957
958 #[fuchsia::test]
959 fn two_finger_contact_contender_examine_event_matched_contender() {
960 let contender: Box<dyn gesture_arena::Contender> = Box::new(TwoFingerContactContender {
961 two_finger_contact_event: TouchpadEvent {
962 timestamp: zx::MonotonicInstant::ZERO,
963 pressed_buttons: vec![],
964 contacts: vec![
965 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
966 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
967 ],
968 filtered_palm_contacts: vec![],
969 },
970 spurious_to_intentional_motion_threshold_mm:
971 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
972 spurious_to_intentional_motion_threshold_button_change_mm:
973 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
974 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
975 });
976
977 let event = TouchpadEvent {
978 timestamp: zx::MonotonicInstant::ZERO,
979 pressed_buttons: vec![1],
980 contacts: vec![
981 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
982 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
983 ],
984 filtered_palm_contacts: vec![],
985 };
986 let got = contender.examine_event(&event);
987 assert_matches!(got, ExamineEventResult::MatchedContender(_));
988 }
989
990 #[fuchsia::test]
991 fn matched_contender_process_buffered_events() {
992 let contender: Box<dyn gesture_arena::MatchedContender> = Box::new(MatchedContender {
993 spurious_to_intentional_motion_threshold_mm:
994 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
995 spurious_to_intentional_motion_threshold_button_change_mm:
996 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
997 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
998 pressed_event: TouchpadEvent {
999 timestamp: zx::MonotonicInstant::from_nanos(41),
1000 pressed_buttons: vec![1],
1001 contacts: vec![
1002 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1003 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
1004 ],
1005 filtered_palm_contacts: vec![],
1006 },
1007 });
1008 let events = vec![
1009 TouchpadEvent {
1010 timestamp: zx::MonotonicInstant::ZERO,
1011 pressed_buttons: vec![],
1012 contacts: vec![make_touch_contact(1, Position { x: 1.0, y: 1.0 })],
1013 filtered_palm_contacts: vec![],
1014 },
1015 TouchpadEvent {
1017 timestamp: zx::MonotonicInstant::ZERO,
1018 pressed_buttons: vec![],
1019 contacts: vec![make_touch_contact(1, Position { x: 1.0, y: 9.0 })],
1020 filtered_palm_contacts: vec![],
1021 },
1022 TouchpadEvent {
1023 timestamp: zx::MonotonicInstant::from_nanos(21),
1024 pressed_buttons: vec![],
1025 contacts: vec![
1026 make_touch_contact(1, Position { x: 1.0, y: 9.0 }),
1027 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
1028 ],
1029 filtered_palm_contacts: vec![],
1030 },
1031 TouchpadEvent {
1033 timestamp: zx::MonotonicInstant::from_nanos(21),
1034 pressed_buttons: vec![],
1035 contacts: vec![
1036 make_touch_contact(1, Position { x: 1.0, y: 9.0 }),
1037 make_touch_contact(2, Position { x: 5.0, y: 14.0 }),
1038 ],
1039 filtered_palm_contacts: vec![],
1040 },
1041 TouchpadEvent {
1042 timestamp: zx::MonotonicInstant::from_nanos(41),
1043 pressed_buttons: vec![1],
1044 contacts: vec![
1045 make_touch_contact(1, Position { x: 1.0, y: 9.0 }),
1046 make_touch_contact(2, Position { x: 5.0, y: 5.0 }),
1047 ],
1048 filtered_palm_contacts: vec![],
1049 },
1050 ];
1051
1052 let got = contender.process_buffered_events(events);
1053
1054 assert_matches!(got, ProcessBufferedEventsResult{
1055 generated_events,
1056 winner: Some(winner),
1057 recognized_gesture: RecognizedGesture::SecondaryButtonDown,
1058 } => {
1059 pretty_assertions::assert_eq!(generated_events, vec![
1060 gesture_arena::MouseEvent {
1061 timestamp:zx::MonotonicInstant::from_nanos(41),
1062 mouse_data: MouseEvent::new(
1063 MouseLocation::Relative(RelativeLocation {
1064 millimeters: Position { x: 0.0, y: 0.0 },
1065 }),
1066 None,
1067 None,
1068 MousePhase::Down,
1069 hashset!{gesture_arena::SECONDARY_BUTTON},
1070 hashset!{gesture_arena::SECONDARY_BUTTON},
1071 None,
1072 None,
1073
1074 ),
1075 }
1076 ]);
1077 pretty_assertions::assert_eq!(winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonDownWinner");
1078 });
1079 }
1080
1081 #[test_case(TouchpadEvent{
1082 timestamp: zx::MonotonicInstant::from_nanos(41),
1083 pressed_buttons: vec![],
1084 contacts: vec![
1085 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1086 ],
1087 filtered_palm_contacts: vec![],
1088 };"1 finger button release")]
1089 #[test_case(TouchpadEvent{
1090 timestamp: zx::MonotonicInstant::from_nanos(41),
1091 pressed_buttons: vec![],
1092 contacts: vec![
1093 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1094 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1095 ],
1096 filtered_palm_contacts: vec![],
1097 };"2 finger button release")]
1098 #[test_case(TouchpadEvent{
1099 timestamp: zx::MonotonicInstant::from_nanos(41),
1100 pressed_buttons: vec![],
1101 contacts: vec![
1102 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1103 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1104 make_touch_contact(2, Position{x: 15.0, y: 15.0}),
1105 ],
1106 filtered_palm_contacts: vec![],
1107 };"3 finger button release")]
1108 #[test_case(TouchpadEvent{
1109 timestamp: zx::MonotonicInstant::from_nanos(41),
1110 pressed_buttons: vec![],
1111 contacts: vec![
1112 make_touch_contact(1, Position{x: 19.0, y: 1.0}),
1113 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1114 ],
1115 filtered_palm_contacts: vec![],
1116 };"move less than threshold in button change state")]
1117 #[test_case(TouchpadEvent{
1118 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1500),
1119 pressed_buttons: vec![],
1120 contacts: vec![
1121 make_touch_contact(1, Position{x: 9.0, y: 1.0}),
1122 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1123 ],
1124 filtered_palm_contacts: vec![],
1125 };"move less than threshold out of button change state")]
1126 #[test_case(TouchpadEvent{
1127 timestamp: zx::MonotonicInstant::from_nanos(41),
1128 pressed_buttons: vec![],
1129 contacts: vec![
1130 make_touch_contact(1, Position{x: 21.0, y: 1.0}),
1131 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1132 ],
1133 filtered_palm_contacts: vec![],
1134 };"move more than threshold in button change state")]
1135 #[test_case(TouchpadEvent{
1136 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1500),
1137 pressed_buttons: vec![],
1138 contacts: vec![
1139 make_touch_contact(1, Position{x: 11.0, y: 1.0}),
1140 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1141 ],
1142 filtered_palm_contacts: vec![],
1143 };"move more than threshold out of button change state")]
1144 #[fuchsia::test]
1145 fn button_down_winner_button_up(event: TouchpadEvent) {
1146 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonDownWinner {
1147 spurious_to_intentional_motion_threshold_mm:
1148 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
1149 spurious_to_intentional_motion_threshold_button_change_mm:
1150 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1151 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1152 pressed_event: TouchpadEvent {
1153 timestamp: zx::MonotonicInstant::ZERO,
1154 pressed_buttons: vec![1],
1155 contacts: vec![
1156 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1157 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1158 ],
1159 filtered_palm_contacts: vec![],
1160 },
1161 });
1162
1163 let got = winner.process_new_event(event);
1164 assert_matches!(got, ProcessNewEventResult::ContinueGesture(Some(gesture_arena::MouseEvent {mouse_data, ..}), got_winner) => {
1165 pretty_assertions::assert_eq!(mouse_data, MouseEvent::new(
1166 MouseLocation::Relative(RelativeLocation {
1167 millimeters: Position { x: 0.0, y: 0.0 },
1168 }),
1169 None,
1170 None,
1171 MousePhase::Up,
1172 hashset!{gesture_arena::SECONDARY_BUTTON},
1173 hashset!{},
1174 None,
1175 None,
1176
1177 ));
1178 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonUpWinner");
1179 });
1180 }
1181
1182 #[test_case(TouchpadEvent{
1183 timestamp: zx::MonotonicInstant::from_nanos(41),
1184 pressed_buttons: vec![1],
1185 contacts: vec![
1186 make_touch_contact(1, Position{x: 20.0, y: 1.0}),
1187 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1188 ],
1189 filtered_palm_contacts: vec![],
1190 };"move less than threshold in button change state")]
1191 #[test_case(TouchpadEvent{
1192 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1500),
1193 pressed_buttons: vec![1],
1194 contacts: vec![
1195 make_touch_contact(1, Position{x: 10.0, y: 1.0}),
1196 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1197 ],
1198 filtered_palm_contacts: vec![],
1199 };"move less than threshold out of button change state")]
1200 #[fuchsia::test]
1201 fn button_down_winner_continue(event: TouchpadEvent) {
1202 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonDownWinner {
1203 spurious_to_intentional_motion_threshold_mm:
1204 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
1205 spurious_to_intentional_motion_threshold_button_change_mm:
1206 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1207 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1208 pressed_event: TouchpadEvent {
1209 timestamp: zx::MonotonicInstant::ZERO,
1210 pressed_buttons: vec![1],
1211 contacts: vec![
1212 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1213 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1214 ],
1215 filtered_palm_contacts: vec![],
1216 },
1217 });
1218
1219 let got = winner.process_new_event(event);
1220 assert_matches!(got, ProcessNewEventResult::ContinueGesture(None, got_winner)=>{
1221 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonDownWinner");
1222 });
1223 }
1224
1225 #[test_case(TouchpadEvent{
1226 timestamp: zx::MonotonicInstant::from_nanos(41),
1227 pressed_buttons: vec![1],
1228 contacts: vec![
1229 make_touch_contact(1, Position{x: 21.0, y: 1.0}),
1230 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1231 ],
1232 filtered_palm_contacts: vec![],
1233 };"move more than threshold in button change state")]
1234 #[test_case(TouchpadEvent{
1235 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1500),
1236 pressed_buttons: vec![1],
1237 contacts: vec![
1238 make_touch_contact(1, Position{x: 11.0, y: 1.0}),
1239 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1240 ],
1241 filtered_palm_contacts: vec![],
1242 };"move more than threshold out of button change state")]
1243 #[fuchsia::test]
1244 fn button_down_winner_drag_winner_continue(event: TouchpadEvent) {
1245 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonDownWinner {
1246 spurious_to_intentional_motion_threshold_mm:
1247 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
1248 spurious_to_intentional_motion_threshold_button_change_mm:
1249 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1250 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1251 pressed_event: TouchpadEvent {
1252 timestamp: zx::MonotonicInstant::ZERO,
1253 pressed_buttons: vec![1],
1254 contacts: vec![
1255 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1256 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1257 ],
1258 filtered_palm_contacts: vec![],
1259 },
1260 });
1261
1262 let got = winner.process_new_event(event);
1263 assert_matches!(got, ProcessNewEventResult::ContinueGesture(Some(gesture_arena::MouseEvent {mouse_data, ..}), got_winner)=>{
1264 pretty_assertions::assert_eq!(mouse_data.phase, MousePhase::Move);
1265 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::DragWinner");
1266 });
1267 }
1268
1269 #[test_case(TouchpadEvent{
1270 timestamp: zx::MonotonicInstant::from_nanos(41),
1271 pressed_buttons: vec![],
1272 contacts: vec![
1273 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1274 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1275 ],
1276 filtered_palm_contacts: vec![],
1277 };"button release")]
1278 #[test_case(TouchpadEvent{
1279 timestamp: zx::MonotonicInstant::from_nanos(41),
1280 pressed_buttons: vec![],
1281 contacts: vec![
1282 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1283 ],
1284 filtered_palm_contacts: vec![],
1285 };"1 finger button release")]
1286 #[test_case(TouchpadEvent{
1287 timestamp: zx::MonotonicInstant::from_nanos(41),
1288 pressed_buttons: vec![],
1289 contacts: vec![
1290 make_touch_contact(1, Position{x: 21.0, y: 1.0}),
1291 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1292 ],
1293 filtered_palm_contacts: vec![],
1294 };"large move and button release")]
1295 #[fuchsia::test]
1296 fn drag_winner_button_up(event: TouchpadEvent) {
1297 let winner: Box<dyn gesture_arena::Winner> = Box::new(DragWinner {
1298 spurious_to_intentional_motion_threshold_button_change_mm:
1299 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1300 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1301 last_event: TouchpadEvent {
1302 timestamp: zx::MonotonicInstant::ZERO,
1303 pressed_buttons: vec![1],
1304 contacts: vec![
1305 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1306 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1307 ],
1308 filtered_palm_contacts: vec![],
1309 },
1310 });
1311
1312 let got = winner.process_new_event(event);
1313 assert_matches!(got, ProcessNewEventResult::ContinueGesture(Some(gesture_arena::MouseEvent {mouse_data, ..}), got_winner) => {
1314 pretty_assertions::assert_eq!(mouse_data, MouseEvent::new(
1315 MouseLocation::Relative(RelativeLocation {
1316 millimeters: Position { x: 0.0, y: 0.0 },
1317 }),
1318 None,
1319 None,
1320 MousePhase::Up,
1321 hashset!{gesture_arena::SECONDARY_BUTTON},
1322 hashset!{},
1323 None,
1324 None,
1325
1326 ));
1327 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonUpWinner");
1328 });
1329 }
1330
1331 #[test_case(TouchpadEvent{
1332 timestamp: zx::MonotonicInstant::from_nanos(41),
1333 pressed_buttons: vec![1],
1334 contacts: vec![
1335 make_touch_contact(1, Position{x: 19.0, y: 1.0}),
1336 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1337 ],
1338 filtered_palm_contacts: vec![],
1339 };"2 finger")]
1340 #[test_case(TouchpadEvent{
1341 timestamp: zx::MonotonicInstant::from_nanos(41),
1342 pressed_buttons: vec![1],
1343 contacts: vec![
1344 make_touch_contact(1, Position{x: 19.0, y: 1.0}),
1345 ],
1346 filtered_palm_contacts: vec![],
1347 };"1 finger")]
1348 #[fuchsia::test]
1349 fn drag_winner_continue(event: TouchpadEvent) {
1350 let winner: Box<dyn gesture_arena::Winner> = Box::new(DragWinner {
1351 spurious_to_intentional_motion_threshold_button_change_mm:
1352 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1353 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1354 last_event: TouchpadEvent {
1355 timestamp: zx::MonotonicInstant::ZERO,
1356 pressed_buttons: vec![1],
1357 contacts: vec![
1358 make_touch_contact(1, Position { x: 0.0, y: 0.0 }),
1359 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1360 ],
1361 filtered_palm_contacts: vec![],
1362 },
1363 });
1364
1365 let got = winner.process_new_event(event);
1366 assert_matches!(got, ProcessNewEventResult::ContinueGesture(Some(gesture_arena::MouseEvent {mouse_data, ..}), got_winner)=>{
1367 pretty_assertions::assert_eq!(mouse_data, MouseEvent::new(
1368 MouseLocation::Relative(RelativeLocation {
1369 millimeters: Position { x: 19.0, y: 1.0 },
1370 }),
1371 None,
1372 None,
1373 MousePhase::Move,
1374 hashset!{},
1375 hashset!{gesture_arena::SECONDARY_BUTTON},
1376 None,
1377 None,
1378
1379 ));
1380 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::DragWinner");
1381 });
1382 }
1383
1384 #[fuchsia::test]
1385 fn button_up_winner_continue() {
1386 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonUpWinner {
1387 spurious_to_intentional_motion_threshold_button_change_mm:
1388 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1389 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1390 button_up_event: TouchpadEvent {
1391 timestamp: zx::MonotonicInstant::ZERO,
1392 pressed_buttons: vec![],
1393 contacts: vec![
1394 make_touch_contact(1, Position { x: 0.0, y: 0.0 }),
1395 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1396 ],
1397 filtered_palm_contacts: vec![],
1398 },
1399 });
1400
1401 let event = TouchpadEvent {
1402 timestamp: zx::MonotonicInstant::from_nanos(41),
1403 pressed_buttons: vec![],
1404 contacts: vec![
1405 make_touch_contact(1, Position { x: 10.0, y: 1.0 }),
1406 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1407 ],
1408 filtered_palm_contacts: vec![],
1409 };
1410
1411 let got = winner.process_new_event(event);
1412 assert_matches!(got, ProcessNewEventResult::ContinueGesture(None, got_winner)=>{
1413 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonUpWinner");
1414 });
1415 }
1416
1417 #[test_case(TouchpadEvent{
1418 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1_001),
1419 pressed_buttons: vec![],
1420 contacts: vec![
1421 make_touch_contact(1, Position{x: 0.0, y: 0.0}),
1422 ],
1423 filtered_palm_contacts: vec![],
1424 };"timeout")]
1425 #[test_case(TouchpadEvent{
1426 timestamp: zx::MonotonicInstant::from_nanos(41),
1427 pressed_buttons: vec![1],
1428 contacts: vec![
1429 make_touch_contact(1, Position{x: 0.0, y: 0.0}),
1430 ],
1431 filtered_palm_contacts: vec![],
1432 };"button down")]
1433 #[test_case(TouchpadEvent{
1434 timestamp: zx::MonotonicInstant::from_nanos(41),
1435 pressed_buttons: vec![],
1436 contacts: vec![
1437 make_touch_contact(1, Position{x: 21.0, y: 0.0}),
1438 ],
1439 filtered_palm_contacts: vec![],
1440 };"move more than threshold")]
1441 #[test_case(TouchpadEvent{
1442 timestamp: zx::MonotonicInstant::from_nanos(41),
1443 pressed_buttons: vec![],
1444 contacts: vec![
1445 make_touch_contact(1, Position{x: 0.0, y: 0.0}),
1446 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1447 make_touch_contact(3, Position{x: 15.0, y: 15.0}),
1448 ],
1449 filtered_palm_contacts: vec![],
1450 };"more contacts")]
1451 #[test_case(TouchpadEvent{
1452 timestamp: zx::MonotonicInstant::from_nanos(41),
1453 pressed_buttons: vec![],
1454 contacts: vec![
1455 make_touch_contact(1, Position{x: 0.0, y: 0.0}),
1456 ],
1457 filtered_palm_contacts: vec![],
1458 };"less contacts")]
1459 #[test_case(TouchpadEvent{
1460 timestamp: zx::MonotonicInstant::from_nanos(41),
1461 pressed_buttons: vec![],
1462 contacts: vec![],
1463 filtered_palm_contacts: vec![],
1464 };"no contact")]
1465 #[fuchsia::test]
1466 fn button_up_winner_end(event: TouchpadEvent) {
1467 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonUpWinner {
1468 spurious_to_intentional_motion_threshold_button_change_mm:
1469 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1470 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1471 button_up_event: TouchpadEvent {
1472 timestamp: zx::MonotonicInstant::ZERO,
1473 pressed_buttons: vec![],
1474 contacts: vec![
1475 make_touch_contact(1, Position { x: 0.0, y: 0.0 }),
1476 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1477 ],
1478 filtered_palm_contacts: vec![],
1479 },
1480 });
1481
1482 let got = winner.process_new_event(event);
1483 assert_matches!(
1484 got,
1485 ProcessNewEventResult::EndGesture(EndGestureEvent::UnconsumedEvent(_), _)
1486 );
1487 }
1488}