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 sorted_vec_map::SortedVecSet;
15
16#[derive(Debug)]
19pub(super) struct InitialContender {
20 pub(super) spurious_to_intentional_motion_threshold_mm: f32,
23
24 pub(super) spurious_to_intentional_motion_threshold_button_change_mm: f32,
27
28 pub(super) button_change_state_timeout: zx::MonotonicDuration,
31}
32
33#[derive(Debug)]
35struct OneFingerContactContender {
36 one_finger_contact_event: TouchpadEvent,
38
39 spurious_to_intentional_motion_threshold_mm: f32,
42
43 spurious_to_intentional_motion_threshold_button_change_mm: f32,
46
47 button_change_state_timeout: zx::MonotonicDuration,
50}
51
52#[derive(Debug)]
54struct TwoFingerContactContender {
55 two_finger_contact_event: TouchpadEvent,
57
58 spurious_to_intentional_motion_threshold_mm: f32,
61
62 spurious_to_intentional_motion_threshold_button_change_mm: f32,
65
66 button_change_state_timeout: zx::MonotonicDuration,
69}
70
71#[derive(Debug)]
74struct MatchedContender {
75 pressed_event: TouchpadEvent,
77
78 spurious_to_intentional_motion_threshold_mm: f32,
81
82 spurious_to_intentional_motion_threshold_button_change_mm: f32,
85
86 button_change_state_timeout: zx::MonotonicDuration,
89}
90
91#[derive(Debug)]
93struct ButtonDownWinner {
94 pressed_event: TouchpadEvent,
96
97 spurious_to_intentional_motion_threshold_mm: f32,
99
100 spurious_to_intentional_motion_threshold_button_change_mm: f32,
103
104 button_change_state_timeout: zx::MonotonicDuration,
107}
108
109#[derive(Debug)]
112struct DragWinner {
113 last_event: TouchpadEvent,
115
116 spurious_to_intentional_motion_threshold_button_change_mm: f32,
119
120 button_change_state_timeout: zx::MonotonicDuration,
123}
124
125#[derive(Debug)]
128struct ButtonUpWinner {
129 button_up_event: TouchpadEvent,
131
132 spurious_to_intentional_motion_threshold_button_change_mm: f32,
135
136 button_change_state_timeout: zx::MonotonicDuration,
139}
140
141impl InitialContender {
142 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
143 fn into_one_finger_contact_contender(
144 self: Box<Self>,
145 one_finger_contact_event: TouchpadEvent,
146 ) -> Box<dyn gesture_arena::Contender> {
147 Box::new(OneFingerContactContender {
148 one_finger_contact_event,
149 spurious_to_intentional_motion_threshold_mm: self
150 .spurious_to_intentional_motion_threshold_mm,
151 spurious_to_intentional_motion_threshold_button_change_mm: self
152 .spurious_to_intentional_motion_threshold_button_change_mm,
153 button_change_state_timeout: self.button_change_state_timeout,
154 })
155 }
156
157 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
158 fn into_two_finger_contacts_contender(
159 self: Box<Self>,
160 two_finger_contact_event: TouchpadEvent,
161 ) -> Box<dyn gesture_arena::Contender> {
162 Box::new(TwoFingerContactContender {
163 two_finger_contact_event,
164 spurious_to_intentional_motion_threshold_mm: self
165 .spurious_to_intentional_motion_threshold_mm,
166 spurious_to_intentional_motion_threshold_button_change_mm: self
167 .spurious_to_intentional_motion_threshold_button_change_mm,
168 button_change_state_timeout: self.button_change_state_timeout,
169 })
170 }
171
172 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
173 fn into_matched_contender(
174 self: Box<Self>,
175 pressed_event: TouchpadEvent,
176 ) -> Box<dyn gesture_arena::MatchedContender> {
177 Box::new(MatchedContender {
178 pressed_event,
179 spurious_to_intentional_motion_threshold_mm: self
180 .spurious_to_intentional_motion_threshold_mm,
181 spurious_to_intentional_motion_threshold_button_change_mm: self
182 .spurious_to_intentional_motion_threshold_button_change_mm,
183 button_change_state_timeout: self.button_change_state_timeout,
184 })
185 }
186}
187
188impl gesture_arena::Contender for InitialContender {
189 fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
190 let num_pressed_buttons = event.pressed_buttons.len();
191
192 let num_contacts = event.contacts.len();
193 match num_contacts {
194 1 => {
195 if num_pressed_buttons != 0 {
196 return ExamineEventResult::Mismatch(Reason::DetailedUint(
197 DetailedReasonUint {
198 criterion: "num_pressed_buttons",
199 min: Some(0),
200 max: Some(0),
201 actual: num_pressed_buttons,
202 },
203 ));
204 }
205
206 ExamineEventResult::Contender(self.into_one_finger_contact_contender(event.clone()))
207 }
208 2 => {
209 match num_pressed_buttons {
210 0 => ExamineEventResult::Contender(
211 self.into_two_finger_contacts_contender(event.clone()),
212 ),
213 _ => ExamineEventResult::MatchedContender(
216 self.into_matched_contender(event.clone()),
217 ),
218 }
219 }
220 0 | _ => ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
221 criterion: "num_contacts",
222 min: Some(1),
223 max: Some(2),
224 actual: num_contacts,
225 })),
226 }
227 }
228}
229
230impl OneFingerContactContender {
231 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
232 fn into_two_finger_contacts_contender(
233 self: Box<Self>,
234 two_finger_contact_event: TouchpadEvent,
235 ) -> Box<dyn gesture_arena::Contender> {
236 Box::new(TwoFingerContactContender {
237 two_finger_contact_event,
238 spurious_to_intentional_motion_threshold_mm: self
239 .spurious_to_intentional_motion_threshold_mm,
240 spurious_to_intentional_motion_threshold_button_change_mm: self
241 .spurious_to_intentional_motion_threshold_button_change_mm,
242 button_change_state_timeout: self.button_change_state_timeout,
243 })
244 }
245}
246
247impl gesture_arena::Contender for OneFingerContactContender {
248 fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
249 let num_pressed_buttons = event.pressed_buttons.len();
250 if num_pressed_buttons > 0 {
251 return ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
252 criterion: "num_pressed_buttons",
253 min: None,
254 max: Some(0),
255 actual: num_pressed_buttons,
256 }));
257 }
258
259 let num_contacts = event.contacts.len();
260
261 match num_contacts {
262 1 => {
263 let displacement_mm = euclidean_distance(
264 position_from_event(event, 0),
265 position_from_event(&self.one_finger_contact_event, 0),
266 );
267 if displacement_mm >= self.spurious_to_intentional_motion_threshold_mm {
268 return ExamineEventResult::Mismatch(Reason::DetailedFloat(
269 DetailedReasonFloat {
270 criterion: "displacement_mm",
271 min: None,
272 max: Some(self.spurious_to_intentional_motion_threshold_mm),
273 actual: displacement_mm,
274 },
275 ));
276 }
277 ExamineEventResult::Contender(self)
278 }
279 2 => {
280 let displacement_mm = euclidean_distance(
281 position_from_event(event, 0),
282 position_from_event(&self.one_finger_contact_event, 0),
283 );
284 if displacement_mm >= self.spurious_to_intentional_motion_threshold_mm {
285 return ExamineEventResult::Mismatch(Reason::DetailedFloat(
286 DetailedReasonFloat {
287 criterion: "displacement_mm",
288 min: None,
289 max: Some(self.spurious_to_intentional_motion_threshold_mm),
290 actual: displacement_mm,
291 },
292 ));
293 }
294 ExamineEventResult::Contender(
295 self.into_two_finger_contacts_contender(event.clone()),
296 )
297 }
298 _ => ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
299 criterion: "num_contacts",
300 min: Some(1),
301 max: Some(2),
302 actual: num_contacts,
303 })),
304 }
305 }
306}
307
308impl TwoFingerContactContender {
309 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
310 fn into_matched_contender(
311 self: Box<Self>,
312 pressed_event: TouchpadEvent,
313 ) -> Box<dyn gesture_arena::MatchedContender> {
314 Box::new(MatchedContender {
315 pressed_event,
316 spurious_to_intentional_motion_threshold_mm: self
317 .spurious_to_intentional_motion_threshold_mm,
318 spurious_to_intentional_motion_threshold_button_change_mm: self
319 .spurious_to_intentional_motion_threshold_button_change_mm,
320 button_change_state_timeout: self.button_change_state_timeout,
321 })
322 }
323}
324
325impl gesture_arena::Contender for TwoFingerContactContender {
326 fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
327 let num_contacts = event.contacts.len();
328 if num_contacts != 2 {
329 return ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
330 criterion: "num_contacts",
331 min: Some(2),
332 max: Some(2),
333 actual: num_contacts,
334 }));
335 }
336
337 let MovementDetail { euclidean_distance, movement: _ } =
339 movement_from_events(&self.two_finger_contact_event, &event);
340 if euclidean_distance >= self.spurious_to_intentional_motion_threshold_mm {
341 return ExamineEventResult::Mismatch(Reason::DetailedFloat(DetailedReasonFloat {
342 criterion: "displacement_mm",
343 min: None,
344 max: Some(self.spurious_to_intentional_motion_threshold_mm),
345 actual: euclidean_distance,
346 }));
347 }
348
349 let num_pressed_buttons = event.pressed_buttons.len();
350 match num_pressed_buttons {
351 0 => ExamineEventResult::Contender(self),
353 _ => ExamineEventResult::MatchedContender(self.into_matched_contender(event.clone())),
357 }
358 }
359}
360
361impl MatchedContender {
362 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
363 fn into_button_down_winner(self: Box<Self>) -> Box<dyn gesture_arena::Winner> {
364 Box::new(ButtonDownWinner {
365 pressed_event: self.pressed_event,
366 spurious_to_intentional_motion_threshold_mm: self
367 .spurious_to_intentional_motion_threshold_mm,
368 spurious_to_intentional_motion_threshold_button_change_mm: self
369 .spurious_to_intentional_motion_threshold_button_change_mm,
370 button_change_state_timeout: self.button_change_state_timeout,
371 })
372 }
373}
374
375impl gesture_arena::MatchedContender for MatchedContender {
376 fn verify_event(self: Box<Self>, _event: &TouchpadEvent) -> VerifyEventResult {
377 log::error!("Unexpected MatchedContender::verify_event() called");
381
382 VerifyEventResult::MatchedContender(self)
383 }
384
385 fn process_buffered_events(
386 self: Box<Self>,
387 _events: Vec<TouchpadEvent>,
388 ) -> ProcessBufferedEventsResult {
389 ProcessBufferedEventsResult {
391 generated_events: vec![touchpad_event_to_mouse_down_event(&self.pressed_event)],
392 winner: Some(self.into_button_down_winner()),
393 recognized_gesture: RecognizedGesture::SecondaryButtonDown,
394 }
395 }
396}
397
398impl ButtonDownWinner {
399 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
400 fn into_drag_winner(self: Box<Self>) -> Box<dyn gesture_arena::Winner> {
401 Box::new(DragWinner {
402 last_event: self.pressed_event,
403 spurious_to_intentional_motion_threshold_button_change_mm: self
404 .spurious_to_intentional_motion_threshold_button_change_mm,
405 button_change_state_timeout: self.button_change_state_timeout,
406 })
407 }
408
409 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
410 fn into_button_up(
411 self: Box<Self>,
412 button_up_event: TouchpadEvent,
413 ) -> Box<dyn gesture_arena::Winner> {
414 Box::new(ButtonUpWinner {
415 button_up_event,
416 spurious_to_intentional_motion_threshold_button_change_mm: self
417 .spurious_to_intentional_motion_threshold_button_change_mm,
418 button_change_state_timeout: self.button_change_state_timeout,
419 })
420 }
421}
422
423impl gesture_arena::Winner for ButtonDownWinner {
424 fn process_new_event(self: Box<Self>, event: TouchpadEvent) -> ProcessNewEventResult {
425 let motion_threshold =
426 if event.timestamp - self.pressed_event.timestamp > self.button_change_state_timeout {
427 self.spurious_to_intentional_motion_threshold_mm
428 } else {
429 self.spurious_to_intentional_motion_threshold_button_change_mm
430 };
431
432 let MovementDetail { euclidean_distance, movement: _ } =
434 movement_from_events(&self.pressed_event, &event);
435 if euclidean_distance >= motion_threshold {
436 let drag_winner = self.into_drag_winner();
437 return drag_winner.process_new_event(event);
438 }
439
440 let num_pressed_buttons = event.pressed_buttons.len();
441 match num_pressed_buttons {
442 0 => ProcessNewEventResult::ContinueGesture(
445 Some(touchpad_event_to_mouse_up_event(&event)),
446 self.into_button_up(event),
447 ),
448 1 => ProcessNewEventResult::ContinueGesture(None, self),
449 _ => ProcessNewEventResult::ContinueGesture(None, self),
452 }
453 }
454}
455
456impl DragWinner {
457 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
458 fn into_drag_winner(
459 self: Box<Self>,
460 last_event: TouchpadEvent,
461 ) -> Box<dyn gesture_arena::Winner> {
462 Box::new(DragWinner {
463 spurious_to_intentional_motion_threshold_button_change_mm: self
464 .spurious_to_intentional_motion_threshold_button_change_mm,
465 button_change_state_timeout: self.button_change_state_timeout,
466 last_event,
467 })
468 }
469
470 #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
471 fn into_button_up(
472 self: Box<Self>,
473 button_up_event: TouchpadEvent,
474 ) -> Box<dyn gesture_arena::Winner> {
475 Box::new(ButtonUpWinner {
476 spurious_to_intentional_motion_threshold_button_change_mm: self
477 .spurious_to_intentional_motion_threshold_button_change_mm,
478 button_change_state_timeout: self.button_change_state_timeout,
479 button_up_event,
480 })
481 }
482}
483
484impl gesture_arena::Winner for DragWinner {
485 fn process_new_event(self: Box<Self>, event: TouchpadEvent) -> ProcessNewEventResult {
486 let num_pressed_buttons = event.pressed_buttons.len();
487 match num_pressed_buttons {
488 0 => ProcessNewEventResult::ContinueGesture(
490 Some(touchpad_event_to_mouse_up_event(&event)),
491 self.into_button_up(event),
492 ),
493 1 | _ => {
494 ProcessNewEventResult::ContinueGesture(
497 Some(touchpad_event_to_mouse_drag_event(&self.last_event, &event)),
498 self.into_drag_winner(event),
499 )
500 }
501 }
502 }
503}
504
505impl gesture_arena::Winner for ButtonUpWinner {
506 fn process_new_event(self: Box<Self>, event: TouchpadEvent) -> ProcessNewEventResult {
507 let num_contacts = event.contacts.len();
509 let num_contacts_button_up = self.button_up_event.contacts.len();
510 if num_contacts != num_contacts_button_up {
511 return ProcessNewEventResult::EndGesture(
512 EndGestureEvent::UnconsumedEvent(event),
513 Reason::DetailedUint(DetailedReasonUint {
514 criterion: "num_contacts",
515 min: Some(num_contacts_button_up as u64),
516 max: Some(num_contacts_button_up as u64),
517 actual: num_contacts,
518 }),
519 );
520 }
521
522 let num_pressed_buttons = event.pressed_buttons.len();
524 if num_pressed_buttons != 0 {
525 return ProcessNewEventResult::EndGesture(
526 EndGestureEvent::UnconsumedEvent(event),
527 Reason::DetailedUint(DetailedReasonUint {
528 criterion: "num_buttons",
529 min: Some(0),
530 max: Some(0),
531 actual: num_pressed_buttons,
532 }),
533 );
534 }
535
536 if event.timestamp - self.button_up_event.timestamp > self.button_change_state_timeout {
538 return ProcessNewEventResult::EndGesture(
539 EndGestureEvent::UnconsumedEvent(event),
540 Reason::Basic("button_up_timeout"),
541 );
542 }
543
544 let MovementDetail { euclidean_distance, movement: _ } =
546 movement_from_events(&self.button_up_event, &event);
547 if euclidean_distance > self.spurious_to_intentional_motion_threshold_button_change_mm {
548 return ProcessNewEventResult::EndGesture(
549 EndGestureEvent::UnconsumedEvent(event),
550 Reason::DetailedFloat(DetailedReasonFloat {
551 criterion: "displacement_mm",
552 min: None,
553 max: Some(self.spurious_to_intentional_motion_threshold_button_change_mm),
554 actual: euclidean_distance,
555 }),
556 );
557 }
558
559 ProcessNewEventResult::ContinueGesture(None, self)
561 }
562}
563
564fn position_from_event(event: &TouchpadEvent, index: usize) -> Position {
567 event.contacts[index].position
568}
569
570fn touchpad_event_to_mouse_down_event(event: &TouchpadEvent) -> gesture_arena::MouseEvent {
571 make_mouse_event(
572 event.timestamp,
573 Position::zero(),
574 MousePhase::Down,
575 SortedVecSet::from(vec![gesture_arena::SECONDARY_BUTTON]),
576 SortedVecSet::from(vec![gesture_arena::SECONDARY_BUTTON]),
577 )
578}
579
580fn touchpad_event_to_mouse_up_event(event: &TouchpadEvent) -> gesture_arena::MouseEvent {
581 make_mouse_event(
582 event.timestamp,
583 Position::zero(),
584 MousePhase::Up,
585 SortedVecSet::from(vec![gesture_arena::SECONDARY_BUTTON]),
586 SortedVecSet::new(),
587 )
588}
589
590fn touchpad_event_to_mouse_drag_event(
591 last_event: &TouchpadEvent,
592 event: &TouchpadEvent,
593) -> gesture_arena::MouseEvent {
594 let MovementDetail { movement, euclidean_distance: _ } =
595 movement_from_events(last_event, event);
596 make_mouse_event(
597 event.timestamp,
598 movement,
599 MousePhase::Move,
600 SortedVecSet::new(),
601 SortedVecSet::from(vec![gesture_arena::SECONDARY_BUTTON]),
602 )
603}
604
605fn make_mouse_event(
606 timestamp: zx::MonotonicInstant,
607 movement_in_mm: Position,
608 phase: MousePhase,
609 affected_buttons: SortedVecSet<MouseButton>,
610 pressed_buttons: SortedVecSet<MouseButton>,
611) -> gesture_arena::MouseEvent {
612 gesture_arena::MouseEvent {
613 timestamp,
614 mouse_data: MouseEvent::new(
615 MouseLocation::Relative(RelativeLocation { millimeters: movement_in_mm }),
616 None,
617 None,
618 phase,
619 affected_buttons,
620 pressed_buttons,
621 None,
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 SortedVecSet::from(vec![gesture_arena::SECONDARY_BUTTON]),
1069 SortedVecSet::from(vec![gesture_arena::SECONDARY_BUTTON]),
1070 None,
1071 None,
1072
1073 ),
1074 }
1075 ]);
1076 pretty_assertions::assert_eq!(winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonDownWinner");
1077 });
1078 }
1079
1080 #[test_case(TouchpadEvent{
1081 timestamp: zx::MonotonicInstant::from_nanos(41),
1082 pressed_buttons: vec![],
1083 contacts: vec![
1084 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1085 ],
1086 filtered_palm_contacts: vec![],
1087 };"1 finger button release")]
1088 #[test_case(TouchpadEvent{
1089 timestamp: zx::MonotonicInstant::from_nanos(41),
1090 pressed_buttons: vec![],
1091 contacts: vec![
1092 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1093 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1094 ],
1095 filtered_palm_contacts: vec![],
1096 };"2 finger button release")]
1097 #[test_case(TouchpadEvent{
1098 timestamp: zx::MonotonicInstant::from_nanos(41),
1099 pressed_buttons: vec![],
1100 contacts: vec![
1101 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1102 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1103 make_touch_contact(2, Position{x: 15.0, y: 15.0}),
1104 ],
1105 filtered_palm_contacts: vec![],
1106 };"3 finger button release")]
1107 #[test_case(TouchpadEvent{
1108 timestamp: zx::MonotonicInstant::from_nanos(41),
1109 pressed_buttons: vec![],
1110 contacts: vec![
1111 make_touch_contact(1, Position{x: 19.0, y: 1.0}),
1112 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1113 ],
1114 filtered_palm_contacts: vec![],
1115 };"move less than threshold in button change state")]
1116 #[test_case(TouchpadEvent{
1117 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1500),
1118 pressed_buttons: vec![],
1119 contacts: vec![
1120 make_touch_contact(1, Position{x: 9.0, y: 1.0}),
1121 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1122 ],
1123 filtered_palm_contacts: vec![],
1124 };"move less than threshold out of button change state")]
1125 #[test_case(TouchpadEvent{
1126 timestamp: zx::MonotonicInstant::from_nanos(41),
1127 pressed_buttons: vec![],
1128 contacts: vec![
1129 make_touch_contact(1, Position{x: 21.0, y: 1.0}),
1130 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1131 ],
1132 filtered_palm_contacts: vec![],
1133 };"move more than threshold in button change state")]
1134 #[test_case(TouchpadEvent{
1135 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1500),
1136 pressed_buttons: vec![],
1137 contacts: vec![
1138 make_touch_contact(1, Position{x: 11.0, y: 1.0}),
1139 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1140 ],
1141 filtered_palm_contacts: vec![],
1142 };"move more than threshold out of button change state")]
1143 #[fuchsia::test]
1144 fn button_down_winner_button_up(event: TouchpadEvent) {
1145 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonDownWinner {
1146 spurious_to_intentional_motion_threshold_mm:
1147 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
1148 spurious_to_intentional_motion_threshold_button_change_mm:
1149 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1150 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1151 pressed_event: TouchpadEvent {
1152 timestamp: zx::MonotonicInstant::ZERO,
1153 pressed_buttons: vec![1],
1154 contacts: vec![
1155 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1156 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1157 ],
1158 filtered_palm_contacts: vec![],
1159 },
1160 });
1161
1162 let got = winner.process_new_event(event);
1163 assert_matches!(got, ProcessNewEventResult::ContinueGesture(Some(gesture_arena::MouseEvent {mouse_data, ..}), got_winner) => {
1164 pretty_assertions::assert_eq!(mouse_data, MouseEvent::new(
1165 MouseLocation::Relative(RelativeLocation {
1166 millimeters: Position { x: 0.0, y: 0.0 },
1167 }),
1168 None,
1169 None,
1170 MousePhase::Up,
1171 SortedVecSet::from(vec![gesture_arena::SECONDARY_BUTTON]),
1172 SortedVecSet::new(),
1173 None,
1174 None,
1175
1176 ));
1177 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonUpWinner");
1178 });
1179 }
1180
1181 #[test_case(TouchpadEvent{
1182 timestamp: zx::MonotonicInstant::from_nanos(41),
1183 pressed_buttons: vec![1],
1184 contacts: vec![
1185 make_touch_contact(1, Position{x: 20.0, y: 1.0}),
1186 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1187 ],
1188 filtered_palm_contacts: vec![],
1189 };"move less than threshold in button change state")]
1190 #[test_case(TouchpadEvent{
1191 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1500),
1192 pressed_buttons: vec![1],
1193 contacts: vec![
1194 make_touch_contact(1, Position{x: 10.0, y: 1.0}),
1195 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1196 ],
1197 filtered_palm_contacts: vec![],
1198 };"move less than threshold out of button change state")]
1199 #[fuchsia::test]
1200 fn button_down_winner_continue(event: TouchpadEvent) {
1201 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonDownWinner {
1202 spurious_to_intentional_motion_threshold_mm:
1203 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
1204 spurious_to_intentional_motion_threshold_button_change_mm:
1205 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1206 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1207 pressed_event: TouchpadEvent {
1208 timestamp: zx::MonotonicInstant::ZERO,
1209 pressed_buttons: vec![1],
1210 contacts: vec![
1211 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1212 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1213 ],
1214 filtered_palm_contacts: vec![],
1215 },
1216 });
1217
1218 let got = winner.process_new_event(event);
1219 assert_matches!(got, ProcessNewEventResult::ContinueGesture(None, got_winner)=>{
1220 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonDownWinner");
1221 });
1222 }
1223
1224 #[test_case(TouchpadEvent{
1225 timestamp: zx::MonotonicInstant::from_nanos(41),
1226 pressed_buttons: vec![1],
1227 contacts: vec![
1228 make_touch_contact(1, Position{x: 21.0, y: 1.0}),
1229 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1230 ],
1231 filtered_palm_contacts: vec![],
1232 };"move more than threshold in button change state")]
1233 #[test_case(TouchpadEvent{
1234 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1500),
1235 pressed_buttons: vec![1],
1236 contacts: vec![
1237 make_touch_contact(1, Position{x: 11.0, y: 1.0}),
1238 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1239 ],
1240 filtered_palm_contacts: vec![],
1241 };"move more than threshold out of button change state")]
1242 #[fuchsia::test]
1243 fn button_down_winner_drag_winner_continue(event: TouchpadEvent) {
1244 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonDownWinner {
1245 spurious_to_intentional_motion_threshold_mm:
1246 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_MM,
1247 spurious_to_intentional_motion_threshold_button_change_mm:
1248 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1249 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1250 pressed_event: TouchpadEvent {
1251 timestamp: zx::MonotonicInstant::ZERO,
1252 pressed_buttons: vec![1],
1253 contacts: vec![
1254 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1255 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1256 ],
1257 filtered_palm_contacts: vec![],
1258 },
1259 });
1260
1261 let got = winner.process_new_event(event);
1262 assert_matches!(got, ProcessNewEventResult::ContinueGesture(Some(gesture_arena::MouseEvent {mouse_data, ..}), got_winner)=>{
1263 pretty_assertions::assert_eq!(mouse_data.phase, MousePhase::Move);
1264 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::DragWinner");
1265 });
1266 }
1267
1268 #[test_case(TouchpadEvent{
1269 timestamp: zx::MonotonicInstant::from_nanos(41),
1270 pressed_buttons: vec![],
1271 contacts: vec![
1272 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1273 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1274 ],
1275 filtered_palm_contacts: vec![],
1276 };"button release")]
1277 #[test_case(TouchpadEvent{
1278 timestamp: zx::MonotonicInstant::from_nanos(41),
1279 pressed_buttons: vec![],
1280 contacts: vec![
1281 make_touch_contact(1, Position{x: 1.0, y: 1.0}),
1282 ],
1283 filtered_palm_contacts: vec![],
1284 };"1 finger button release")]
1285 #[test_case(TouchpadEvent{
1286 timestamp: zx::MonotonicInstant::from_nanos(41),
1287 pressed_buttons: vec![],
1288 contacts: vec![
1289 make_touch_contact(1, Position{x: 21.0, y: 1.0}),
1290 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1291 ],
1292 filtered_palm_contacts: vec![],
1293 };"large move and button release")]
1294 #[fuchsia::test]
1295 fn drag_winner_button_up(event: TouchpadEvent) {
1296 let winner: Box<dyn gesture_arena::Winner> = Box::new(DragWinner {
1297 spurious_to_intentional_motion_threshold_button_change_mm:
1298 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1299 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1300 last_event: TouchpadEvent {
1301 timestamp: zx::MonotonicInstant::ZERO,
1302 pressed_buttons: vec![1],
1303 contacts: vec![
1304 make_touch_contact(1, Position { x: 1.0, y: 1.0 }),
1305 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1306 ],
1307 filtered_palm_contacts: vec![],
1308 },
1309 });
1310
1311 let got = winner.process_new_event(event);
1312 assert_matches!(got, ProcessNewEventResult::ContinueGesture(Some(gesture_arena::MouseEvent {mouse_data, ..}), got_winner) => {
1313 pretty_assertions::assert_eq!(mouse_data, MouseEvent::new(
1314 MouseLocation::Relative(RelativeLocation {
1315 millimeters: Position { x: 0.0, y: 0.0 },
1316 }),
1317 None,
1318 None,
1319 MousePhase::Up,
1320 SortedVecSet::from(vec![gesture_arena::SECONDARY_BUTTON]),
1321 SortedVecSet::new(),
1322 None,
1323 None,
1324
1325 ));
1326 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonUpWinner");
1327 });
1328 }
1329
1330 #[test_case(TouchpadEvent{
1331 timestamp: zx::MonotonicInstant::from_nanos(41),
1332 pressed_buttons: vec![1],
1333 contacts: vec![
1334 make_touch_contact(1, Position{x: 19.0, y: 1.0}),
1335 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1336 ],
1337 filtered_palm_contacts: vec![],
1338 };"2 finger")]
1339 #[test_case(TouchpadEvent{
1340 timestamp: zx::MonotonicInstant::from_nanos(41),
1341 pressed_buttons: vec![1],
1342 contacts: vec![
1343 make_touch_contact(1, Position{x: 19.0, y: 1.0}),
1344 ],
1345 filtered_palm_contacts: vec![],
1346 };"1 finger")]
1347 #[fuchsia::test]
1348 fn drag_winner_continue(event: TouchpadEvent) {
1349 let winner: Box<dyn gesture_arena::Winner> = Box::new(DragWinner {
1350 spurious_to_intentional_motion_threshold_button_change_mm:
1351 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1352 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1353 last_event: TouchpadEvent {
1354 timestamp: zx::MonotonicInstant::ZERO,
1355 pressed_buttons: vec![1],
1356 contacts: vec![
1357 make_touch_contact(1, Position { x: 0.0, y: 0.0 }),
1358 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1359 ],
1360 filtered_palm_contacts: vec![],
1361 },
1362 });
1363
1364 let got = winner.process_new_event(event);
1365 assert_matches!(got, ProcessNewEventResult::ContinueGesture(Some(gesture_arena::MouseEvent {mouse_data, ..}), got_winner)=>{
1366 pretty_assertions::assert_eq!(mouse_data, MouseEvent::new(
1367 MouseLocation::Relative(RelativeLocation {
1368 millimeters: Position { x: 19.0, y: 1.0 },
1369 }),
1370 None,
1371 None,
1372 MousePhase::Move,
1373 SortedVecSet::new(),
1374 SortedVecSet::from(vec![gesture_arena::SECONDARY_BUTTON]),
1375 None,
1376 None,
1377
1378 ));
1379 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::DragWinner");
1380 });
1381 }
1382
1383 #[fuchsia::test]
1384 fn button_up_winner_continue() {
1385 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonUpWinner {
1386 spurious_to_intentional_motion_threshold_button_change_mm:
1387 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1388 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1389 button_up_event: TouchpadEvent {
1390 timestamp: zx::MonotonicInstant::ZERO,
1391 pressed_buttons: vec![],
1392 contacts: vec![
1393 make_touch_contact(1, Position { x: 0.0, y: 0.0 }),
1394 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1395 ],
1396 filtered_palm_contacts: vec![],
1397 },
1398 });
1399
1400 let event = TouchpadEvent {
1401 timestamp: zx::MonotonicInstant::from_nanos(41),
1402 pressed_buttons: vec![],
1403 contacts: vec![
1404 make_touch_contact(1, Position { x: 10.0, y: 1.0 }),
1405 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1406 ],
1407 filtered_palm_contacts: vec![],
1408 };
1409
1410 let got = winner.process_new_event(event);
1411 assert_matches!(got, ProcessNewEventResult::ContinueGesture(None, got_winner)=>{
1412 pretty_assertions::assert_eq!(got_winner.get_type_name(), "input_pipeline_lib_test::gestures::secondary_button::ButtonUpWinner");
1413 });
1414 }
1415
1416 #[test_case(TouchpadEvent{
1417 timestamp: zx::MonotonicInstant::ZERO + zx::MonotonicDuration::from_millis(1_001),
1418 pressed_buttons: vec![],
1419 contacts: vec![
1420 make_touch_contact(1, Position{x: 0.0, y: 0.0}),
1421 ],
1422 filtered_palm_contacts: vec![],
1423 };"timeout")]
1424 #[test_case(TouchpadEvent{
1425 timestamp: zx::MonotonicInstant::from_nanos(41),
1426 pressed_buttons: vec![1],
1427 contacts: vec![
1428 make_touch_contact(1, Position{x: 0.0, y: 0.0}),
1429 ],
1430 filtered_palm_contacts: vec![],
1431 };"button down")]
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: 21.0, y: 0.0}),
1437 ],
1438 filtered_palm_contacts: vec![],
1439 };"move more than threshold")]
1440 #[test_case(TouchpadEvent{
1441 timestamp: zx::MonotonicInstant::from_nanos(41),
1442 pressed_buttons: vec![],
1443 contacts: vec![
1444 make_touch_contact(1, Position{x: 0.0, y: 0.0}),
1445 make_touch_contact(2, Position{x: 10.0, y: 10.0}),
1446 make_touch_contact(3, Position{x: 15.0, y: 15.0}),
1447 ],
1448 filtered_palm_contacts: vec![],
1449 };"more contacts")]
1450 #[test_case(TouchpadEvent{
1451 timestamp: zx::MonotonicInstant::from_nanos(41),
1452 pressed_buttons: vec![],
1453 contacts: vec![
1454 make_touch_contact(1, Position{x: 0.0, y: 0.0}),
1455 ],
1456 filtered_palm_contacts: vec![],
1457 };"less contacts")]
1458 #[test_case(TouchpadEvent{
1459 timestamp: zx::MonotonicInstant::from_nanos(41),
1460 pressed_buttons: vec![],
1461 contacts: vec![],
1462 filtered_palm_contacts: vec![],
1463 };"no contact")]
1464 #[fuchsia::test]
1465 fn button_up_winner_end(event: TouchpadEvent) {
1466 let winner: Box<dyn gesture_arena::Winner> = Box::new(ButtonUpWinner {
1467 spurious_to_intentional_motion_threshold_button_change_mm:
1468 SPURIOUS_TO_INTENTIONAL_MOTION_THRESHOLD_BUTTON_CHANGE_MM,
1469 button_change_state_timeout: BUTTON_CHANGE_STATE_TIMEOUT,
1470 button_up_event: TouchpadEvent {
1471 timestamp: zx::MonotonicInstant::ZERO,
1472 pressed_buttons: vec![],
1473 contacts: vec![
1474 make_touch_contact(1, Position { x: 0.0, y: 0.0 }),
1475 make_touch_contact(2, Position { x: 10.0, y: 10.0 }),
1476 ],
1477 filtered_palm_contacts: vec![],
1478 },
1479 });
1480
1481 let got = winner.process_new_event(event);
1482 assert_matches!(
1483 got,
1484 ProcessNewEventResult::EndGesture(EndGestureEvent::UnconsumedEvent(_), _)
1485 );
1486 }
1487}