1use crate::input_device::{self, Handled, InputDeviceBinding, InputDeviceStatus, InputEvent};
6use crate::utils::{self, Position};
7use crate::{Transport, metrics};
8use anyhow::{Error, format_err};
9use async_trait::async_trait;
10use fidl_fuchsia_input_report as fidl_input_report;
11use fuchsia_inspect::ArrayProperty;
12use fuchsia_inspect::health::Reporter;
13use fuchsia_sync::Mutex;
14use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
15use metrics_registry::*;
16use sorted_vec_map::SortedVecSet;
17use zx;
18
19pub type MouseButton = u8;
20
21#[derive(Copy, Clone, Debug, PartialEq)]
23pub enum PrecisionScroll {
24 Yes,
26 No,
28}
29
30#[derive(Copy, Clone, Debug, PartialEq)]
32pub enum MouseLocation {
33 Relative(RelativeLocation),
35
36 Absolute(Position),
38}
39
40#[derive(Copy, Clone, Debug, PartialEq)]
41pub enum MousePhase {
42 Down, Move, Up, Wheel, }
47
48#[derive(Copy, Clone, Debug, PartialEq)]
50pub struct RelativeLocation {
51 pub counts: Position,
53}
54
55impl Default for RelativeLocation {
56 fn default() -> Self {
57 RelativeLocation { counts: Position::zero() }
58 }
59}
60
61#[derive(Clone, Debug, PartialEq)]
64pub struct WheelDelta {
65 pub ticks: i64,
66 pub physical_pixel: Option<f32>,
67}
68
69#[derive(Debug)]
91pub struct MouseEvent {
92 pub location: MouseLocation,
94
95 pub wheel_delta_v: Option<WheelDelta>,
97
98 pub wheel_delta_h: Option<WheelDelta>,
100
101 pub is_precision_scroll: Option<PrecisionScroll>,
103
104 pub phase: MousePhase,
106
107 pub affected_buttons: SortedVecSet<MouseButton>,
109
110 pub pressed_buttons: SortedVecSet<MouseButton>,
112
113 pub wake_lease: Mutex<Option<zx::EventPair>>,
115}
116
117impl Clone for MouseEvent {
118 fn clone(&self) -> Self {
119 log::debug!("MouseEvent cloned without wake lease.");
120 Self {
121 location: self.location,
122 wheel_delta_v: self.wheel_delta_v.clone(),
123 wheel_delta_h: self.wheel_delta_h.clone(),
124 is_precision_scroll: self.is_precision_scroll,
125 phase: self.phase,
126 affected_buttons: self.affected_buttons.clone(),
127 pressed_buttons: self.pressed_buttons.clone(),
128 wake_lease: None.into(),
129 }
130 }
131}
132
133impl PartialEq for MouseEvent {
134 fn eq(&self, other: &Self) -> bool {
135 self.location == other.location
136 && self.wheel_delta_v == other.wheel_delta_v
137 && self.wheel_delta_h == other.wheel_delta_h
138 && self.is_precision_scroll == other.is_precision_scroll
139 && self.phase == other.phase
140 && self.affected_buttons == other.affected_buttons
141 && self.pressed_buttons == other.pressed_buttons
142 }
143}
144
145impl MouseEvent {
146 pub fn new(
154 location: MouseLocation,
155 wheel_delta_v: Option<WheelDelta>,
156 wheel_delta_h: Option<WheelDelta>,
157 phase: MousePhase,
158 affected_buttons: SortedVecSet<MouseButton>,
159 pressed_buttons: SortedVecSet<MouseButton>,
160 is_precision_scroll: Option<PrecisionScroll>,
161 wake_lease: Option<zx::EventPair>,
162 ) -> MouseEvent {
163 MouseEvent {
164 location,
165 wheel_delta_v,
166 wheel_delta_h,
167 phase,
168 affected_buttons,
169 pressed_buttons,
170 is_precision_scroll,
171 wake_lease: Mutex::new(wake_lease),
172 }
173 }
174
175 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
176 match self.location {
177 MouseLocation::Relative(pos) => {
178 node.record_child("location_relative", move |location_node| {
179 location_node.record_double("x", f64::from(pos.counts.x));
180 location_node.record_double("y", f64::from(pos.counts.y));
181 })
182 }
183 MouseLocation::Absolute(pos) => {
184 node.record_child("location_absolute", move |location_node| {
185 location_node.record_double("x", f64::from(pos.x));
186 location_node.record_double("y", f64::from(pos.y));
187 })
188 }
189 };
190
191 if let Some(wheel_delta_v) = &self.wheel_delta_v {
192 node.record_child("wheel_delta_v", move |wheel_delta_v_node| {
193 wheel_delta_v_node.record_int("ticks", wheel_delta_v.ticks);
194 if let Some(physical_pixel) = wheel_delta_v.physical_pixel {
195 wheel_delta_v_node.record_double("physical_pixel", f64::from(physical_pixel));
196 }
197 });
198 }
199
200 if let Some(wheel_delta_h) = &self.wheel_delta_h {
201 node.record_child("wheel_delta_h", move |wheel_delta_h_node| {
202 wheel_delta_h_node.record_int("ticks", wheel_delta_h.ticks);
203 if let Some(physical_pixel) = wheel_delta_h.physical_pixel {
204 wheel_delta_h_node.record_double("physical_pixel", f64::from(physical_pixel));
205 }
206 });
207 }
208
209 if let Some(is_precision_scroll) = self.is_precision_scroll {
210 match is_precision_scroll {
211 PrecisionScroll::Yes => node.record_string("is_precision_scroll", "yes"),
212 PrecisionScroll::No => node.record_string("is_precision_scroll", "no"),
213 }
214 }
215
216 match self.phase {
217 MousePhase::Down => node.record_string("phase", "down"),
218 MousePhase::Move => node.record_string("phase", "move"),
219 MousePhase::Up => node.record_string("phase", "up"),
220 MousePhase::Wheel => node.record_string("phase", "wheel"),
221 }
222
223 let affected_buttons_node =
224 node.create_uint_array("affected_buttons", self.affected_buttons.len());
225 self.affected_buttons.iter().enumerate().for_each(|(i, button)| {
226 affected_buttons_node.set(i, *button);
227 });
228 node.record(affected_buttons_node);
229
230 let pressed_buttons_node =
231 node.create_uint_array("pressed_buttons", self.pressed_buttons.len());
232 self.pressed_buttons.iter().enumerate().for_each(|(i, button)| {
233 pressed_buttons_node.set(i, *button);
234 });
235 node.record(pressed_buttons_node);
236 }
237}
238
239pub struct MouseBinding {
245 event_sender: UnboundedSender<Vec<InputEvent>>,
247
248 device_descriptor: MouseDeviceDescriptor,
250}
251
252#[derive(Clone, Debug, Eq, PartialEq)]
253pub struct MouseDeviceDescriptor {
254 pub device_id: u32,
256
257 pub absolute_x_range: Option<fidl_input_report::Range>,
259
260 pub absolute_y_range: Option<fidl_input_report::Range>,
262
263 pub wheel_v_range: Option<fidl_input_report::Axis>,
265
266 pub wheel_h_range: Option<fidl_input_report::Axis>,
268
269 pub buttons: Option<Vec<MouseButton>>,
271}
272
273#[async_trait]
274impl input_device::InputDeviceBinding for MouseBinding {
275 fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>> {
276 self.event_sender.clone()
277 }
278
279 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
280 input_device::InputDeviceDescriptor::Mouse(self.device_descriptor.clone())
281 }
282}
283
284impl MouseBinding {
285 pub async fn new(
300 device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
301 device_id: u32,
302 input_event_sender: UnboundedSender<Vec<InputEvent>>,
303 device_node: fuchsia_inspect::Node,
304 _feature_flags: input_device::InputPipelineFeatureFlags,
305 metrics_logger: metrics::MetricsLogger,
306 ) -> Result<Self, Error> {
307 let (device_binding, mut inspect_status) =
308 Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
309 inspect_status.health_node.set_ok();
310 input_device::initialize_report_stream(
311 device_proxy,
312 device_binding.get_device_descriptor(),
313 device_binding.input_event_sender(),
314 inspect_status,
315 metrics_logger,
316 _feature_flags,
317 Self::process_reports,
318 );
319
320 Ok(device_binding)
321 }
322
323 async fn bind_device(
335 device: &fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
336 device_id: u32,
337 input_event_sender: UnboundedSender<Vec<InputEvent>>,
338 device_node: fuchsia_inspect::Node,
339 ) -> Result<(Self, InputDeviceStatus), Error> {
340 let mut input_device_status = InputDeviceStatus::new(device_node);
341 let device_descriptor: fidl_next_fuchsia_input_report::DeviceDescriptor = match device
342 .get_descriptor()
343 .await
344 {
345 Ok(res) => res.descriptor,
346 Err(_) => {
347 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
348 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
349 }
350 };
351
352 let mouse_descriptor = device_descriptor.mouse.ok_or_else(|| {
353 input_device_status
354 .health_node
355 .set_unhealthy("DeviceDescriptor does not have a MouseDescriptor.");
356 format_err!("DeviceDescriptor does not have a MouseDescriptor")
357 })?;
358
359 let mouse_input_descriptor = mouse_descriptor.input.ok_or_else(|| {
360 input_device_status
361 .health_node
362 .set_unhealthy("MouseDescriptor does not have a MouseInputDescriptor.");
363 format_err!("MouseDescriptor does not have a MouseInputDescriptor")
364 })?;
365
366 let device_descriptor: MouseDeviceDescriptor = MouseDeviceDescriptor {
367 device_id,
368 absolute_x_range: mouse_input_descriptor
369 .position_x
370 .as_ref()
371 .map(|axis| utils::range_to_old(&axis.range)),
372 absolute_y_range: mouse_input_descriptor
373 .position_y
374 .as_ref()
375 .map(|axis| utils::range_to_old(&axis.range)),
376 wheel_v_range: utils::axis_to_old(mouse_input_descriptor.scroll_v.as_ref()),
377 wheel_h_range: utils::axis_to_old(mouse_input_descriptor.scroll_h.as_ref()),
378 buttons: mouse_input_descriptor.buttons,
379 };
380
381 Ok((Self { event_sender: input_event_sender, device_descriptor }, input_device_status))
382 }
383
384 fn process_reports(
406 reports: &[fidl_next_fuchsia_input_report::wire::InputReport<'_>],
407 mut previous_state: Option<input_device::PreviousDeviceState>,
408 device_descriptor: &input_device::InputDeviceDescriptor,
409 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
410 inspect_status: &InputDeviceStatus,
411 metrics_logger: &metrics::MetricsLogger,
412 _feature_flags: &input_device::InputPipelineFeatureFlags,
413 ) -> (Option<input_device::PreviousDeviceState>, Option<UnboundedReceiver<InputEvent>>) {
414 fuchsia_trace::duration!("input", "mouse-binding-process-reports", "num_reports" => reports.len());
415 for report in reports {
416 previous_state = Self::process_report(
417 report,
418 previous_state,
419 device_descriptor,
420 input_event_sender,
421 inspect_status,
422 metrics_logger,
423 );
424 }
425 (previous_state, None)
426 }
427
428 fn process_report(
429 report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
430 previous_state: Option<input_device::PreviousDeviceState>,
431 device_descriptor: &input_device::InputDeviceDescriptor,
432 input_event_sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
433 inspect_status: &InputDeviceStatus,
434 metrics_logger: &metrics::MetricsLogger,
435 ) -> Option<input_device::PreviousDeviceState> {
436 if let Some(trace_id) = report.trace_id() {
437 fuchsia_trace::flow_end!("input", "input_report", trace_id.0.into());
438 }
439
440 let wake_lease = utils::duplicate_wake_lease(report.wake_lease());
444
445 inspect_status.count_received_report_wire(report);
446 let mouse_report = match report.mouse() {
448 Some(mouse) => mouse,
449 None => {
450 inspect_status.count_filtered_report();
451 return previous_state;
452 }
453 };
454
455 let previous_buttons: SortedVecSet<MouseButton> = match previous_state {
456 Some(input_device::PreviousDeviceState::Mouse { pressed_buttons }) => pressed_buttons,
457 _ => SortedVecSet::new(),
458 };
459 let current_buttons: SortedVecSet<MouseButton> =
460 buttons_from_mouse_report_wire(mouse_report);
461
462 send_mouse_event(
468 MouseLocation::Relative(Default::default()),
469 None, None, MousePhase::Down,
472 current_buttons.difference(&previous_buttons).cloned().collect(),
473 current_buttons.clone(),
474 device_descriptor,
475 input_event_sender,
476 inspect_status,
477 metrics_logger,
478 wake_lease.as_ref().map(|lease| {
479 lease
480 .duplicate_handle(zx::Rights::SAME_RIGHTS)
481 .expect("failed to duplicate event pair")
482 }),
483 );
484
485 let location = if let (Some(position_x), Some(position_y)) =
487 (mouse_report.position_x(), mouse_report.position_y())
488 {
489 MouseLocation::Absolute(Position { x: position_x.0 as f32, y: position_y.0 as f32 })
490 } else {
491 let movement_x = mouse_report.movement_x().map(|x| x.0).unwrap_or_default() as f32;
492 let movement_y = mouse_report.movement_y().map(|y| y.0).unwrap_or_default() as f32;
493 MouseLocation::Relative(RelativeLocation {
494 counts: Position { x: movement_x, y: movement_y },
495 })
496 };
497
498 send_mouse_event(
502 location,
503 None, None, MousePhase::Move,
506 current_buttons.union(&previous_buttons).cloned().collect(),
507 current_buttons.union(&previous_buttons).cloned().collect(),
508 device_descriptor,
509 input_event_sender,
510 inspect_status,
511 metrics_logger,
512 wake_lease.as_ref().map(|lease| {
513 lease
514 .duplicate_handle(zx::Rights::SAME_RIGHTS)
515 .expect("failed to duplicate event pair")
516 }),
517 );
518
519 let wheel_delta_v = mouse_report
520 .scroll_v()
521 .map(|ticks| WheelDelta { ticks: ticks.0, physical_pixel: None });
522
523 let wheel_delta_h = mouse_report
524 .scroll_h()
525 .map(|ticks| WheelDelta { ticks: ticks.0, physical_pixel: None });
526
527 send_mouse_event(
529 MouseLocation::Relative(Default::default()),
530 wheel_delta_v,
531 wheel_delta_h,
532 MousePhase::Wheel,
533 current_buttons.union(&previous_buttons).cloned().collect(),
534 current_buttons.union(&previous_buttons).cloned().collect(),
535 device_descriptor,
536 input_event_sender,
537 inspect_status,
538 metrics_logger,
539 wake_lease.as_ref().map(|lease| {
540 lease
541 .duplicate_handle(zx::Rights::SAME_RIGHTS)
542 .expect("failed to duplicate event pair")
543 }),
544 );
545
546 send_mouse_event(
552 MouseLocation::Relative(Default::default()),
553 None, None, MousePhase::Up,
556 previous_buttons.difference(¤t_buttons).cloned().collect(),
557 current_buttons.clone(),
558 device_descriptor,
559 input_event_sender,
560 inspect_status,
561 metrics_logger,
562 wake_lease,
563 );
564
565 Some(input_device::PreviousDeviceState::Mouse { pressed_buttons: current_buttons })
566 }
567}
568
569fn send_mouse_event(
584 location: MouseLocation,
585 wheel_delta_v: Option<WheelDelta>,
586 wheel_delta_h: Option<WheelDelta>,
587 phase: MousePhase,
588 affected_buttons: SortedVecSet<MouseButton>,
589 pressed_buttons: SortedVecSet<MouseButton>,
590 device_descriptor: &input_device::InputDeviceDescriptor,
591 sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
592 inspect_status: &InputDeviceStatus,
593 metrics_logger: &metrics::MetricsLogger,
594 wake_lease: Option<zx::EventPair>,
595) {
596 if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
598 return;
599 }
600
601 if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
604 return;
605 }
606
607 if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
609 return;
610 }
611
612 let trace_id = fuchsia_trace::Id::new();
613 fuchsia_trace::duration!("input", "mouse-binding-send-event");
614 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
615
616 let event = input_device::InputEvent {
617 device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
618 location,
619 wheel_delta_v,
620 wheel_delta_h,
621 phase,
622 affected_buttons,
623 pressed_buttons,
624 match phase {
625 MousePhase::Wheel => Some(PrecisionScroll::No),
626 _ => None,
627 },
628 wake_lease,
629 )),
630 device_descriptor: device_descriptor.clone(),
631 event_time: zx::MonotonicInstant::get(),
632 handled: Handled::No,
633 trace_id: Some(trace_id),
634 };
635 let events = vec![event];
636 inspect_status.count_generated_events(&events);
637
638 if let Err(e) = sender.unbounded_send(events) {
639 metrics_logger.log_error(
640 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
641 std::format!("Failed to send MouseEvent with error: {:?}", e),
642 );
643 }
644}
645
646fn buttons_from_mouse_report_wire(
647 mouse_report: &fidl_next_fuchsia_input_report::wire::MouseInputReport<'_>,
648) -> SortedVecSet<MouseButton> {
649 mouse_report
650 .pressed_buttons()
651 .map(|buttons| SortedVecSet::from_iter(buttons.iter().copied()))
652 .unwrap_or_default()
653}
654
655#[cfg(test)]
656mod tests {
657 use super::*;
658 use crate::testing_utilities;
659 use fuchsia_async as fasync;
660 use futures::StreamExt;
661 use sorted_vec_map::SortedVecSet;
662
663 const DEVICE_ID: u32 = 1;
664
665 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
666 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
667 device_id,
668 absolute_x_range: None,
669 absolute_y_range: None,
670 wheel_v_range: Some(fidl_fuchsia_input_report::Axis {
671 range: fidl_input_report::Range { min: -1, max: 1 },
672 unit: fidl_input_report::Unit {
673 type_: fidl_input_report::UnitType::Other,
674 exponent: 1,
675 },
676 }),
677 wheel_h_range: Some(fidl_fuchsia_input_report::Axis {
678 range: fidl_input_report::Range { min: -1, max: 1 },
679 unit: fidl_input_report::Unit {
680 type_: fidl_input_report::UnitType::Other,
681 exponent: 1,
682 },
683 }),
684 buttons: None,
685 })
686 }
687
688 fn wheel_delta_ticks(ticks: i64) -> Option<WheelDelta> {
689 Some(WheelDelta { ticks, physical_pixel: None })
690 }
691
692 #[fasync::run_singlethreaded(test)]
694 async fn movement_without_button() {
695 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
696 let first_report = testing_utilities::create_mouse_input_report_relative(
697 Position { x: 10.0, y: 16.0 },
698 None, None, vec![],
701 event_time_i64,
702 );
703 let descriptor = mouse_device_descriptor(DEVICE_ID);
704
705 let input_reports = vec![first_report];
706 let expected_events = vec![testing_utilities::create_mouse_event(
707 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
708 None, None, None, MousePhase::Move,
712 SortedVecSet::new(),
713 SortedVecSet::new(),
714 event_time_u64,
715 &descriptor,
716 )];
717
718 assert_input_report_sequence_generates_events!(
719 input_reports: input_reports,
720 expected_events: expected_events,
721 device_descriptor: descriptor,
722 device_type: MouseBinding,
723 );
724 }
725
726 #[fasync::run_singlethreaded(test)]
728 async fn down_without_movement() {
729 let mouse_button: MouseButton = 3;
730 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
731 let first_report = testing_utilities::create_mouse_input_report_relative(
732 Position::zero(),
733 None, None, vec![mouse_button],
736 event_time_i64,
737 );
738 let descriptor = mouse_device_descriptor(DEVICE_ID);
739
740 let input_reports = vec![first_report];
741 let expected_events = vec![testing_utilities::create_mouse_event(
742 MouseLocation::Relative(Default::default()),
743 None, None, None, MousePhase::Down,
747 SortedVecSet::from(vec![mouse_button]),
748 SortedVecSet::from(vec![mouse_button]),
749 event_time_u64,
750 &descriptor,
751 )];
752
753 assert_input_report_sequence_generates_events!(
754 input_reports: input_reports,
755 expected_events: expected_events,
756 device_descriptor: descriptor,
757 device_type: MouseBinding,
758 );
759 }
760
761 #[fasync::run_singlethreaded(test)]
764 async fn down_with_movement() {
765 let mouse_button: MouseButton = 3;
766 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
767 let first_report = testing_utilities::create_mouse_input_report_relative(
768 Position { x: 10.0, y: 16.0 },
769 None, None, vec![mouse_button],
772 event_time_i64,
773 );
774 let descriptor = mouse_device_descriptor(DEVICE_ID);
775
776 let input_reports = vec![first_report];
777 let expected_events = vec![
778 testing_utilities::create_mouse_event(
779 MouseLocation::Relative(Default::default()),
780 None, None, None, MousePhase::Down,
784 SortedVecSet::from(vec![mouse_button]),
785 SortedVecSet::from(vec![mouse_button]),
786 event_time_u64,
787 &descriptor,
788 ),
789 testing_utilities::create_mouse_event(
790 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
791 None, None, None, MousePhase::Move,
795 SortedVecSet::from(vec![mouse_button]),
796 SortedVecSet::from(vec![mouse_button]),
797 event_time_u64,
798 &descriptor,
799 ),
800 ];
801
802 assert_input_report_sequence_generates_events!(
803 input_reports: input_reports,
804 expected_events: expected_events,
805 device_descriptor: descriptor,
806 device_type: MouseBinding,
807 );
808 }
809
810 #[fasync::run_singlethreaded(test)]
812 async fn down_up() {
813 let button = 1;
814 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
815 let first_report = testing_utilities::create_mouse_input_report_relative(
816 Position::zero(),
817 None, None, vec![button],
820 event_time_i64,
821 );
822 let second_report = testing_utilities::create_mouse_input_report_relative(
823 Position::zero(),
824 None, None, vec![],
827 event_time_i64,
828 );
829 let descriptor = mouse_device_descriptor(DEVICE_ID);
830
831 let input_reports = vec![first_report, second_report];
832 let expected_events = vec![
833 testing_utilities::create_mouse_event(
834 MouseLocation::Relative(Default::default()),
835 None, None, None, MousePhase::Down,
839 SortedVecSet::from(vec![button]),
840 SortedVecSet::from(vec![button]),
841 event_time_u64,
842 &descriptor,
843 ),
844 testing_utilities::create_mouse_event(
845 MouseLocation::Relative(Default::default()),
846 None, None, None, MousePhase::Up,
850 SortedVecSet::from(vec![button]),
851 SortedVecSet::new(),
852 event_time_u64,
853 &descriptor,
854 ),
855 ];
856
857 assert_input_report_sequence_generates_events!(
858 input_reports: input_reports,
859 expected_events: expected_events,
860 device_descriptor: descriptor,
861 device_type: MouseBinding,
862 );
863 }
864
865 #[fasync::run_singlethreaded(test)]
867 async fn down_up_with_movement() {
868 let button = 1;
869
870 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
871 let first_report = testing_utilities::create_mouse_input_report_relative(
872 Position::zero(),
873 None, None, vec![button],
876 event_time_i64,
877 );
878 let second_report = testing_utilities::create_mouse_input_report_relative(
879 Position { x: 10.0, y: 16.0 },
880 None, None, vec![],
883 event_time_i64,
884 );
885 let descriptor = mouse_device_descriptor(DEVICE_ID);
886
887 let input_reports = vec![first_report, second_report];
888 let expected_events = vec![
889 testing_utilities::create_mouse_event(
890 MouseLocation::Relative(Default::default()),
891 None, None, None, MousePhase::Down,
895 SortedVecSet::from(vec![button]),
896 SortedVecSet::from(vec![button]),
897 event_time_u64,
898 &descriptor,
899 ),
900 testing_utilities::create_mouse_event(
901 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
902 None, None, None, MousePhase::Move,
906 SortedVecSet::from(vec![button]),
907 SortedVecSet::from(vec![button]),
908 event_time_u64,
909 &descriptor,
910 ),
911 testing_utilities::create_mouse_event(
912 MouseLocation::Relative(Default::default()),
913 None, None, None, MousePhase::Up,
917 SortedVecSet::from(vec![button]),
918 SortedVecSet::new(),
919 event_time_u64,
920 &descriptor,
921 ),
922 ];
923
924 assert_input_report_sequence_generates_events!(
925 input_reports: input_reports,
926 expected_events: expected_events,
927 device_descriptor: descriptor,
928 device_type: MouseBinding,
929 );
930 }
931
932 #[fasync::run_singlethreaded(test)]
936 async fn down_move_up() {
937 let button = 1;
938
939 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
940 let first_report = testing_utilities::create_mouse_input_report_relative(
941 Position::zero(),
942 None, None, vec![button],
945 event_time_i64,
946 );
947 let second_report = testing_utilities::create_mouse_input_report_relative(
948 Position { x: 10.0, y: 16.0 },
949 None, None, vec![button],
952 event_time_i64,
953 );
954 let third_report = testing_utilities::create_mouse_input_report_relative(
955 Position::zero(),
956 None, None, vec![],
959 event_time_i64,
960 );
961 let descriptor = mouse_device_descriptor(DEVICE_ID);
962
963 let input_reports = vec![first_report, second_report, third_report];
964 let expected_events = vec![
965 testing_utilities::create_mouse_event(
966 MouseLocation::Relative(Default::default()),
967 None, None, None, MousePhase::Down,
971 SortedVecSet::from(vec![button]),
972 SortedVecSet::from(vec![button]),
973 event_time_u64,
974 &descriptor,
975 ),
976 testing_utilities::create_mouse_event(
977 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
978 None, None, None, MousePhase::Move,
982 SortedVecSet::from(vec![button]),
983 SortedVecSet::from(vec![button]),
984 event_time_u64,
985 &descriptor,
986 ),
987 testing_utilities::create_mouse_event(
988 MouseLocation::Relative(Default::default()),
989 None, None, None, MousePhase::Up,
993 SortedVecSet::from(vec![button]),
994 SortedVecSet::new(),
995 event_time_u64,
996 &descriptor,
997 ),
998 ];
999
1000 assert_input_report_sequence_generates_events!(
1001 input_reports: input_reports,
1002 expected_events: expected_events,
1003 device_descriptor: descriptor,
1004 device_type: MouseBinding,
1005 );
1006 }
1007
1008 #[fasync::run_until_stalled(test)]
1010 async fn absolute_movement_to_origin() {
1011 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1012 let descriptor = mouse_device_descriptor(DEVICE_ID);
1013
1014 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
1015 Position::zero(),
1016 None, None, vec![],
1019 event_time_i64,
1020 )];
1021 let expected_events = vec![testing_utilities::create_mouse_event(
1022 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1023 None, None, None, MousePhase::Move,
1027 SortedVecSet::new(),
1028 SortedVecSet::new(),
1029 event_time_u64,
1030 &descriptor,
1031 )];
1032
1033 assert_input_report_sequence_generates_events!(
1034 input_reports: input_reports,
1035 expected_events: expected_events,
1036 device_descriptor: descriptor,
1037 device_type: MouseBinding,
1038 );
1039 }
1040
1041 #[fasync::run_until_stalled(test)]
1044 async fn report_with_both_movement_and_position() {
1045 let relative_movement = Position { x: 5.0, y: 5.0 };
1046 let absolute_position = Position { x: 10.0, y: 10.0 };
1047 let expected_location = MouseLocation::Absolute(absolute_position);
1048
1049 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1050 let descriptor = mouse_device_descriptor(DEVICE_ID);
1051
1052 let input_reports = vec![fidl_next_fuchsia_input_report::InputReport {
1053 event_time: Some(event_time_i64),
1054 keyboard: None,
1055 mouse: Some(fidl_next_fuchsia_input_report::MouseInputReport {
1056 movement_x: Some(relative_movement.x as i64),
1057 movement_y: Some(relative_movement.y as i64),
1058 position_x: Some(absolute_position.x as i64),
1059 position_y: Some(absolute_position.y as i64),
1060 scroll_h: None,
1061 scroll_v: None,
1062 pressed_buttons: None,
1063 ..Default::default()
1064 }),
1065 touch: None,
1066 sensor: None,
1067 consumer_control: None,
1068 trace_id: None,
1069 ..Default::default()
1070 }];
1071 let expected_events = vec![testing_utilities::create_mouse_event(
1072 expected_location,
1073 None, None, None, MousePhase::Move,
1077 SortedVecSet::new(),
1078 SortedVecSet::new(),
1079 event_time_u64,
1080 &descriptor,
1081 )];
1082
1083 assert_input_report_sequence_generates_events!(
1084 input_reports: input_reports,
1085 expected_events: expected_events,
1086 device_descriptor: descriptor,
1087 device_type: MouseBinding,
1088 );
1089 }
1090
1091 #[fasync::run_singlethreaded(test)]
1094 async fn down_down() {
1095 const PRIMARY_BUTTON: u8 = 1;
1096 const SECONDARY_BUTTON: u8 = 2;
1097
1098 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1099 let first_report = testing_utilities::create_mouse_input_report_relative(
1100 Position::zero(),
1101 None, None, vec![PRIMARY_BUTTON],
1104 event_time_i64,
1105 );
1106 let second_report = testing_utilities::create_mouse_input_report_relative(
1107 Position::zero(),
1108 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1111 event_time_i64,
1112 );
1113 let descriptor = mouse_device_descriptor(DEVICE_ID);
1114
1115 let input_reports = vec![first_report, second_report];
1116 let expected_events = vec![
1117 testing_utilities::create_mouse_event(
1118 MouseLocation::Relative(Default::default()),
1119 None, None, None, MousePhase::Down,
1123 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1124 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1125 event_time_u64,
1126 &descriptor,
1127 ),
1128 testing_utilities::create_mouse_event(
1129 MouseLocation::Relative(Default::default()),
1130 None, None, None, MousePhase::Down,
1134 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1135 SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1136 event_time_u64,
1137 &descriptor,
1138 ),
1139 ];
1140
1141 assert_input_report_sequence_generates_events!(
1142 input_reports: input_reports,
1143 expected_events: expected_events,
1144 device_descriptor: descriptor,
1145 device_type: MouseBinding,
1146 );
1147 }
1148
1149 #[fasync::run_singlethreaded(test)]
1159 async fn down_down_up_up() {
1160 const PRIMARY_BUTTON: u8 = 1;
1161 const SECONDARY_BUTTON: u8 = 2;
1162
1163 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1164 let first_report = testing_utilities::create_mouse_input_report_relative(
1165 Position::zero(),
1166 None, None, vec![PRIMARY_BUTTON],
1169 event_time_i64,
1170 );
1171 let second_report = testing_utilities::create_mouse_input_report_relative(
1172 Position::zero(),
1173 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1176 event_time_i64,
1177 );
1178 let third_report = testing_utilities::create_mouse_input_report_relative(
1179 Position::zero(),
1180 None, None, vec![SECONDARY_BUTTON],
1183 event_time_i64,
1184 );
1185 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1186 Position::zero(),
1187 None, None, vec![],
1190 event_time_i64,
1191 );
1192 let descriptor = mouse_device_descriptor(DEVICE_ID);
1193
1194 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1195 let expected_events = vec![
1196 testing_utilities::create_mouse_event(
1197 MouseLocation::Relative(Default::default()),
1198 None, None, None, MousePhase::Down,
1202 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1203 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1204 event_time_u64,
1205 &descriptor,
1206 ),
1207 testing_utilities::create_mouse_event(
1208 MouseLocation::Relative(Default::default()),
1209 None, None, None, MousePhase::Down,
1213 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1214 SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1215 event_time_u64,
1216 &descriptor,
1217 ),
1218 testing_utilities::create_mouse_event(
1219 MouseLocation::Relative(Default::default()),
1220 None, None, None, MousePhase::Up,
1224 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1225 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1226 event_time_u64,
1227 &descriptor,
1228 ),
1229 testing_utilities::create_mouse_event(
1230 MouseLocation::Relative(Default::default()),
1231 None, None, None, MousePhase::Up,
1235 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1236 SortedVecSet::new(),
1237 event_time_u64,
1238 &descriptor,
1239 ),
1240 ];
1241
1242 assert_input_report_sequence_generates_events!(
1243 input_reports: input_reports,
1244 expected_events: expected_events,
1245 device_descriptor: descriptor,
1246 device_type: MouseBinding,
1247 );
1248 }
1249
1250 #[fasync::run_singlethreaded(test)]
1252 async fn scroll() {
1253 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1254 let first_report = testing_utilities::create_mouse_input_report_relative(
1255 Position::zero(),
1256 Some(1),
1257 None,
1258 vec![],
1259 event_time_i64,
1260 );
1261 let second_report = testing_utilities::create_mouse_input_report_relative(
1262 Position::zero(),
1263 None,
1264 Some(1),
1265 vec![],
1266 event_time_i64,
1267 );
1268
1269 let descriptor = mouse_device_descriptor(DEVICE_ID);
1270
1271 let input_reports = vec![first_report, second_report];
1272 let expected_events = vec![
1273 testing_utilities::create_mouse_event(
1274 MouseLocation::Relative(Default::default()),
1275 wheel_delta_ticks(1),
1276 None,
1277 Some(PrecisionScroll::No),
1278 MousePhase::Wheel,
1279 SortedVecSet::new(),
1280 SortedVecSet::new(),
1281 event_time_u64,
1282 &descriptor,
1283 ),
1284 testing_utilities::create_mouse_event(
1285 MouseLocation::Relative(Default::default()),
1286 None,
1287 wheel_delta_ticks(1),
1288 Some(PrecisionScroll::No),
1289 MousePhase::Wheel,
1290 SortedVecSet::new(),
1291 SortedVecSet::new(),
1292 event_time_u64,
1293 &descriptor,
1294 ),
1295 ];
1296
1297 assert_input_report_sequence_generates_events!(
1298 input_reports: input_reports,
1299 expected_events: expected_events,
1300 device_descriptor: descriptor,
1301 device_type: MouseBinding,
1302 );
1303 }
1304
1305 #[fasync::run_singlethreaded(test)]
1307 async fn down_scroll_up_scroll() {
1308 const PRIMARY_BUTTON: u8 = 1;
1309
1310 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1311 let first_report = testing_utilities::create_mouse_input_report_relative(
1312 Position::zero(),
1313 None, None, vec![PRIMARY_BUTTON],
1316 event_time_i64,
1317 );
1318 let second_report = testing_utilities::create_mouse_input_report_relative(
1319 Position::zero(),
1320 Some(1),
1321 None,
1322 vec![PRIMARY_BUTTON],
1323 event_time_i64,
1324 );
1325 let third_report = testing_utilities::create_mouse_input_report_relative(
1326 Position::zero(),
1327 None, None, vec![],
1330 event_time_i64,
1331 );
1332 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1333 Position::zero(),
1334 Some(1),
1335 None,
1336 vec![],
1337 event_time_i64,
1338 );
1339
1340 let descriptor = mouse_device_descriptor(DEVICE_ID);
1341
1342 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1343 let expected_events = vec![
1344 testing_utilities::create_mouse_event(
1345 MouseLocation::Relative(Default::default()),
1346 None, None, None, MousePhase::Down,
1350 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1351 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1352 event_time_u64,
1353 &descriptor,
1354 ),
1355 testing_utilities::create_mouse_event(
1356 MouseLocation::Relative(Default::default()),
1357 wheel_delta_ticks(1),
1358 None,
1359 Some(PrecisionScroll::No),
1360 MousePhase::Wheel,
1361 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1362 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1363 event_time_u64,
1364 &descriptor,
1365 ),
1366 testing_utilities::create_mouse_event(
1367 MouseLocation::Relative(Default::default()),
1368 None, None, None, MousePhase::Up,
1372 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1373 SortedVecSet::new(),
1374 event_time_u64,
1375 &descriptor,
1376 ),
1377 testing_utilities::create_mouse_event(
1378 MouseLocation::Relative(Default::default()),
1379 wheel_delta_ticks(1),
1380 None,
1381 Some(PrecisionScroll::No),
1382 MousePhase::Wheel,
1383 SortedVecSet::new(),
1384 SortedVecSet::new(),
1385 event_time_u64,
1386 &descriptor,
1387 ),
1388 ];
1389
1390 assert_input_report_sequence_generates_events!(
1391 input_reports: input_reports,
1392 expected_events: expected_events,
1393 device_descriptor: descriptor,
1394 device_type: MouseBinding,
1395 );
1396 }
1397
1398 #[fasync::run_singlethreaded(test)]
1400 async fn down_scroll_bundle_up_scroll_bundle() {
1401 const PRIMARY_BUTTON: u8 = 1;
1402
1403 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1404 let first_report = testing_utilities::create_mouse_input_report_relative(
1405 Position::zero(),
1406 Some(1),
1407 None,
1408 vec![PRIMARY_BUTTON],
1409 event_time_i64,
1410 );
1411 let second_report = testing_utilities::create_mouse_input_report_relative(
1412 Position::zero(),
1413 Some(1),
1414 None,
1415 vec![],
1416 event_time_i64,
1417 );
1418 let third_report = testing_utilities::create_mouse_input_report_relative(
1419 Position::zero(),
1420 Some(1),
1421 None,
1422 vec![],
1423 event_time_i64,
1424 );
1425
1426 let descriptor = mouse_device_descriptor(DEVICE_ID);
1427
1428 let input_reports = vec![first_report, second_report, third_report];
1429 let expected_events = vec![
1430 testing_utilities::create_mouse_event(
1431 MouseLocation::Relative(Default::default()),
1432 None, None, None, MousePhase::Down,
1436 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1437 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1438 event_time_u64,
1439 &descriptor,
1440 ),
1441 testing_utilities::create_mouse_event(
1442 MouseLocation::Relative(Default::default()),
1443 wheel_delta_ticks(1),
1444 None,
1445 Some(PrecisionScroll::No),
1446 MousePhase::Wheel,
1447 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1448 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1449 event_time_u64,
1450 &descriptor,
1451 ),
1452 testing_utilities::create_mouse_event(
1453 MouseLocation::Relative(Default::default()),
1454 wheel_delta_ticks(1),
1455 None,
1456 Some(PrecisionScroll::No),
1457 MousePhase::Wheel,
1458 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1459 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1460 event_time_u64,
1461 &descriptor,
1462 ),
1463 testing_utilities::create_mouse_event(
1464 MouseLocation::Relative(Default::default()),
1465 None, None, None, MousePhase::Up,
1469 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1470 SortedVecSet::new(),
1471 event_time_u64,
1472 &descriptor,
1473 ),
1474 testing_utilities::create_mouse_event(
1475 MouseLocation::Relative(Default::default()),
1476 wheel_delta_ticks(1),
1477 None,
1478 Some(PrecisionScroll::No),
1479 MousePhase::Wheel,
1480 SortedVecSet::new(),
1481 SortedVecSet::new(),
1482 event_time_u64,
1483 &descriptor,
1484 ),
1485 ];
1486
1487 assert_input_report_sequence_generates_events!(
1488 input_reports: input_reports,
1489 expected_events: expected_events,
1490 device_descriptor: descriptor,
1491 device_type: MouseBinding,
1492 );
1493 }
1494}