1use crate::input_device::{self, Handled, InputDeviceBinding, InputDeviceStatus, InputEvent};
6use crate::utils::Position;
7use crate::{metrics, mouse_model_database};
8use anyhow::{format_err, Error};
9use async_trait::async_trait;
10use fidl_fuchsia_input_report as fidl_input_report;
11use fidl_fuchsia_input_report::{InputDeviceProxy, InputReport};
12use fuchsia_inspect::health::Reporter;
13use fuchsia_inspect::ArrayProperty;
14use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
15use metrics_registry::*;
16use std::collections::HashSet;
17
18pub type MouseButton = u8;
19
20#[derive(Copy, Clone, Debug, PartialEq)]
22pub enum PrecisionScroll {
23 Yes,
25 No,
27}
28
29#[derive(Copy, Clone, Debug, PartialEq)]
31pub enum MouseLocation {
32 Relative(RelativeLocation),
34
35 Absolute(Position),
37}
38
39#[derive(Copy, Clone, Debug, PartialEq)]
40pub enum MousePhase {
41 Down, Move, Up, Wheel, }
46
47#[derive(Copy, Clone, Debug, PartialEq)]
49pub struct RelativeLocation {
50 pub millimeters: Position,
52}
53
54impl Default for RelativeLocation {
55 fn default() -> Self {
56 RelativeLocation { millimeters: Position::zero() }
57 }
58}
59
60#[derive(Clone, Debug, PartialEq)]
62pub enum RawWheelDelta {
63 Ticks(i64),
65 Millimeters(f32),
67}
68
69#[derive(Clone, Debug, PartialEq)]
72
73pub struct WheelDelta {
74 pub raw_data: RawWheelDelta,
75 pub physical_pixel: Option<f32>,
76}
77
78#[derive(Clone, Debug, PartialEq)]
98pub struct MouseEvent {
99 pub location: MouseLocation,
101
102 pub wheel_delta_v: Option<WheelDelta>,
104
105 pub wheel_delta_h: Option<WheelDelta>,
107
108 pub is_precision_scroll: Option<PrecisionScroll>,
110
111 pub phase: MousePhase,
113
114 pub affected_buttons: HashSet<MouseButton>,
116
117 pub pressed_buttons: HashSet<MouseButton>,
119}
120
121impl MouseEvent {
122 pub fn new(
129 location: MouseLocation,
130 wheel_delta_v: Option<WheelDelta>,
131 wheel_delta_h: Option<WheelDelta>,
132 phase: MousePhase,
133 affected_buttons: HashSet<MouseButton>,
134 pressed_buttons: HashSet<MouseButton>,
135 is_precision_scroll: Option<PrecisionScroll>,
136 ) -> MouseEvent {
137 MouseEvent {
138 location,
139 wheel_delta_v,
140 wheel_delta_h,
141 phase,
142 affected_buttons,
143 pressed_buttons,
144 is_precision_scroll,
145 }
146 }
147
148 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
149 match self.location {
150 MouseLocation::Relative(pos) => {
151 node.record_child("location_relative", move |location_node| {
152 location_node.record_double("x", f64::from(pos.millimeters.x));
153 location_node.record_double("y", f64::from(pos.millimeters.y));
154 })
155 }
156 MouseLocation::Absolute(pos) => {
157 node.record_child("location_absolute", move |location_node| {
158 location_node.record_double("x", f64::from(pos.x));
159 location_node.record_double("y", f64::from(pos.y));
160 })
161 }
162 };
163
164 if let Some(wheel_delta_v) = &self.wheel_delta_v {
165 node.record_child("wheel_delta_v", move |wheel_delta_v_node| {
166 match wheel_delta_v.raw_data {
167 RawWheelDelta::Ticks(ticks) => wheel_delta_v_node.record_int("ticks", ticks),
168 RawWheelDelta::Millimeters(mm) => {
169 wheel_delta_v_node.record_double("millimeters", f64::from(mm))
170 }
171 }
172 if let Some(physical_pixel) = wheel_delta_v.physical_pixel {
173 wheel_delta_v_node.record_double("physical_pixel", f64::from(physical_pixel));
174 }
175 });
176 }
177
178 if let Some(wheel_delta_h) = &self.wheel_delta_h {
179 node.record_child("wheel_delta_h", move |wheel_delta_h_node| {
180 match wheel_delta_h.raw_data {
181 RawWheelDelta::Ticks(ticks) => wheel_delta_h_node.record_int("ticks", ticks),
182 RawWheelDelta::Millimeters(mm) => {
183 wheel_delta_h_node.record_double("millimeters", f64::from(mm))
184 }
185 }
186 if let Some(physical_pixel) = wheel_delta_h.physical_pixel {
187 wheel_delta_h_node.record_double("physical_pixel", f64::from(physical_pixel));
188 }
189 });
190 }
191
192 if let Some(is_precision_scroll) = self.is_precision_scroll {
193 match is_precision_scroll {
194 PrecisionScroll::Yes => node.record_string("is_precision_scroll", "yes"),
195 PrecisionScroll::No => node.record_string("is_precision_scroll", "no"),
196 }
197 }
198
199 match self.phase {
200 MousePhase::Down => node.record_string("phase", "down"),
201 MousePhase::Move => node.record_string("phase", "move"),
202 MousePhase::Up => node.record_string("phase", "up"),
203 MousePhase::Wheel => node.record_string("phase", "wheel"),
204 }
205
206 let affected_buttons_node =
207 node.create_uint_array("affected_buttons", self.affected_buttons.len());
208 self.affected_buttons.iter().enumerate().for_each(|(i, button)| {
209 affected_buttons_node.set(i, *button);
210 });
211 node.record(affected_buttons_node);
212
213 let pressed_buttons_node =
214 node.create_uint_array("pressed_buttons", self.pressed_buttons.len());
215 self.pressed_buttons.iter().enumerate().for_each(|(i, button)| {
216 pressed_buttons_node.set(i, *button);
217 });
218 node.record(pressed_buttons_node);
219 }
220}
221
222pub struct MouseBinding {
228 event_sender: UnboundedSender<input_device::InputEvent>,
230
231 device_descriptor: MouseDeviceDescriptor,
233}
234
235#[derive(Clone, Debug, Eq, PartialEq)]
236pub struct MouseDeviceDescriptor {
237 pub device_id: u32,
239
240 pub absolute_x_range: Option<fidl_input_report::Range>,
242
243 pub absolute_y_range: Option<fidl_input_report::Range>,
245
246 pub wheel_v_range: Option<fidl_input_report::Axis>,
248
249 pub wheel_h_range: Option<fidl_input_report::Axis>,
251
252 pub buttons: Option<Vec<MouseButton>>,
254
255 pub counts_per_mm: u32,
258}
259
260#[async_trait]
261impl input_device::InputDeviceBinding for MouseBinding {
262 fn input_event_sender(&self) -> UnboundedSender<input_device::InputEvent> {
263 self.event_sender.clone()
264 }
265
266 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
267 input_device::InputDeviceDescriptor::Mouse(self.device_descriptor.clone())
268 }
269}
270
271impl MouseBinding {
272 pub async fn new(
287 device_proxy: InputDeviceProxy,
288 device_id: u32,
289 input_event_sender: UnboundedSender<input_device::InputEvent>,
290 device_node: fuchsia_inspect::Node,
291 metrics_logger: metrics::MetricsLogger,
292 ) -> Result<Self, Error> {
293 let (device_binding, mut inspect_status) =
294 Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
295 inspect_status.health_node.set_ok();
296 input_device::initialize_report_stream(
297 device_proxy,
298 device_binding.get_device_descriptor(),
299 device_binding.input_event_sender(),
300 inspect_status,
301 metrics_logger,
302 Self::process_reports,
303 );
304
305 Ok(device_binding)
306 }
307
308 async fn bind_device(
320 device: &InputDeviceProxy,
321 device_id: u32,
322 input_event_sender: UnboundedSender<input_device::InputEvent>,
323 device_node: fuchsia_inspect::Node,
324 ) -> Result<(Self, InputDeviceStatus), Error> {
325 let mut input_device_status = InputDeviceStatus::new(device_node);
326 let device_descriptor: fidl_input_report::DeviceDescriptor = match device
327 .get_descriptor()
328 .await
329 {
330 Ok(descriptor) => descriptor,
331 Err(_) => {
332 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
333 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
334 }
335 };
336
337 let mouse_descriptor = device_descriptor.mouse.ok_or_else(|| {
338 input_device_status
339 .health_node
340 .set_unhealthy("DeviceDescriptor does not have a MouseDescriptor.");
341 format_err!("DeviceDescriptor does not have a MouseDescriptor")
342 })?;
343
344 let mouse_input_descriptor = mouse_descriptor.input.ok_or_else(|| {
345 input_device_status
346 .health_node
347 .set_unhealthy("MouseDescriptor does not have a MouseInputDescriptor.");
348 format_err!("MouseDescriptor does not have a MouseInputDescriptor")
349 })?;
350
351 let model = mouse_model_database::db::get_mouse_model(device_descriptor.device_information);
352
353 let device_descriptor: MouseDeviceDescriptor = MouseDeviceDescriptor {
354 device_id,
355 absolute_x_range: mouse_input_descriptor.position_x.map(|axis| axis.range),
356 absolute_y_range: mouse_input_descriptor.position_y.map(|axis| axis.range),
357 wheel_v_range: mouse_input_descriptor.scroll_v,
358 wheel_h_range: mouse_input_descriptor.scroll_h,
359 buttons: mouse_input_descriptor.buttons,
360 counts_per_mm: model.counts_per_mm,
361 };
362
363 Ok((
364 MouseBinding { event_sender: input_event_sender, device_descriptor },
365 input_device_status,
366 ))
367 }
368
369 fn process_reports(
389 report: InputReport,
390 previous_report: Option<InputReport>,
391 device_descriptor: &input_device::InputDeviceDescriptor,
392 input_event_sender: &mut UnboundedSender<input_device::InputEvent>,
393 inspect_status: &InputDeviceStatus,
394 metrics_logger: &metrics::MetricsLogger,
395 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
396 inspect_status.count_received_report(&report);
397 let mouse_report: &fidl_input_report::MouseInputReport = match &report.mouse {
399 Some(mouse) => mouse,
400 None => {
401 inspect_status.count_filtered_report();
402 return (previous_report, None);
403 }
404 };
405
406 let previous_buttons: HashSet<MouseButton> =
407 buttons_from_optional_report(&previous_report.as_ref());
408 let current_buttons: HashSet<MouseButton> = buttons_from_report(&report);
409
410 send_mouse_event(
416 MouseLocation::Relative(Default::default()),
417 None, None, MousePhase::Down,
420 current_buttons.difference(&previous_buttons).cloned().collect(),
421 current_buttons.clone(),
422 device_descriptor,
423 input_event_sender,
424 inspect_status,
425 metrics_logger,
426 );
427
428 let counts_per_mm = match device_descriptor {
429 input_device::InputDeviceDescriptor::Mouse(ds) => ds.counts_per_mm,
430 _ => {
431 metrics_logger.log_error(
432 InputPipelineErrorMetricDimensionEvent::MouseDescriptionNotMouse,
433 "mouse_binding::process_reports got device_descriptor not mouse".to_string(),
434 );
435 mouse_model_database::db::DEFAULT_COUNTS_PER_MM
436 }
437 };
438
439 let location = if let (Some(position_x), Some(position_y)) =
441 (mouse_report.position_x, mouse_report.position_y)
442 {
443 MouseLocation::Absolute(Position { x: position_x as f32, y: position_y as f32 })
444 } else {
445 let movement_x = mouse_report.movement_x.unwrap_or_default() as f32;
446 let movement_y = mouse_report.movement_y.unwrap_or_default() as f32;
447 MouseLocation::Relative(RelativeLocation {
448 millimeters: Position {
449 x: movement_x / counts_per_mm as f32,
450 y: movement_y / counts_per_mm as f32,
451 },
452 })
453 };
454
455 send_mouse_event(
459 location,
460 None, None, MousePhase::Move,
463 current_buttons.union(&previous_buttons).cloned().collect(),
464 current_buttons.union(&previous_buttons).cloned().collect(),
465 device_descriptor,
466 input_event_sender,
467 inspect_status,
468 metrics_logger,
469 );
470
471 let wheel_delta_v = match mouse_report.scroll_v {
472 None => None,
473 Some(ticks) => {
474 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
475 }
476 };
477
478 let wheel_delta_h = match mouse_report.scroll_h {
479 None => None,
480 Some(ticks) => {
481 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
482 }
483 };
484
485 send_mouse_event(
487 MouseLocation::Relative(Default::default()),
488 wheel_delta_v,
489 wheel_delta_h,
490 MousePhase::Wheel,
491 current_buttons.union(&previous_buttons).cloned().collect(),
492 current_buttons.union(&previous_buttons).cloned().collect(),
493 device_descriptor,
494 input_event_sender,
495 inspect_status,
496 metrics_logger,
497 );
498
499 send_mouse_event(
505 MouseLocation::Relative(Default::default()),
506 None, None, MousePhase::Up,
509 previous_buttons.difference(¤t_buttons).cloned().collect(),
510 current_buttons.clone(),
511 device_descriptor,
512 input_event_sender,
513 inspect_status,
514 metrics_logger,
515 );
516
517 (Some(report), None)
518 }
519}
520
521fn send_mouse_event(
535 location: MouseLocation,
536 wheel_delta_v: Option<WheelDelta>,
537 wheel_delta_h: Option<WheelDelta>,
538 phase: MousePhase,
539 affected_buttons: HashSet<MouseButton>,
540 pressed_buttons: HashSet<MouseButton>,
541 device_descriptor: &input_device::InputDeviceDescriptor,
542 sender: &mut UnboundedSender<input_device::InputEvent>,
543 inspect_status: &InputDeviceStatus,
544 metrics_logger: &metrics::MetricsLogger,
545) {
546 if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
548 return;
549 }
550
551 if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
554 return;
555 }
556
557 if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
559 return;
560 }
561
562 let event = input_device::InputEvent {
563 device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
564 location,
565 wheel_delta_v,
566 wheel_delta_h,
567 phase,
568 affected_buttons,
569 pressed_buttons,
570 match phase {
571 MousePhase::Wheel => Some(PrecisionScroll::No),
572 _ => None,
573 },
574 )),
575 device_descriptor: device_descriptor.clone(),
576 event_time: zx::MonotonicInstant::get(),
577 handled: Handled::No,
578 trace_id: None,
579 };
580
581 match sender.unbounded_send(event.clone()) {
582 Err(e) => {
583 metrics_logger.log_error(
584 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
585 std::format!("Failed to send MouseEvent with error: {:?}", e),
586 );
587 }
588 _ => inspect_status.count_generated_event(event),
589 }
590}
591
592pub fn get_u32_from_buttons(buttons: &HashSet<MouseButton>) -> u32 {
606 let mut bits: u32 = 0;
607 for button in buttons {
608 if *button > 0 && *button <= fidl_input_report::MOUSE_MAX_NUM_BUTTONS as u8 {
609 bits = ((1 as u32) << *button - 1) | bits;
610 }
611 }
612
613 bits
614}
615
616fn buttons_from_report(input_report: &fidl_input_report::InputReport) -> HashSet<MouseButton> {
621 buttons_from_optional_report(&Some(input_report))
622}
623
624fn buttons_from_optional_report(
629 input_report: &Option<&fidl_input_report::InputReport>,
630) -> HashSet<MouseButton> {
631 input_report
632 .as_ref()
633 .and_then(|unwrapped_report| unwrapped_report.mouse.as_ref())
634 .and_then(|mouse_report| match &mouse_report.pressed_buttons {
635 Some(buttons) => Some(HashSet::from_iter(buttons.iter().cloned())),
636 None => None,
637 })
638 .unwrap_or_default()
639}
640
641#[cfg(test)]
642mod tests {
643 use super::*;
644 use crate::testing_utilities;
645 use fuchsia_async as fasync;
646 use futures::StreamExt;
647 use pretty_assertions::assert_eq;
648
649 const DEVICE_ID: u32 = 1;
650 const COUNTS_PER_MM: u32 = 12;
651
652 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
653 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
654 device_id,
655 absolute_x_range: None,
656 absolute_y_range: None,
657 wheel_v_range: Some(fidl_fuchsia_input_report::Axis {
658 range: fidl_input_report::Range { min: -1, max: 1 },
659 unit: fidl_input_report::Unit {
660 type_: fidl_input_report::UnitType::Other,
661 exponent: 1,
662 },
663 }),
664 wheel_h_range: Some(fidl_fuchsia_input_report::Axis {
665 range: fidl_input_report::Range { min: -1, max: 1 },
666 unit: fidl_input_report::Unit {
667 type_: fidl_input_report::UnitType::Other,
668 exponent: 1,
669 },
670 }),
671 buttons: None,
672 counts_per_mm: COUNTS_PER_MM,
673 })
674 }
675
676 fn wheel_delta_ticks(delta: i64) -> Option<WheelDelta> {
677 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(delta), physical_pixel: None })
678 }
679
680 #[test]
682 fn get_u32_from_buttons_test() {
683 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, 5].into_iter()));
684 assert_eq!(bits, 21 )
685 }
686
687 #[test]
689 fn get_u32_with_0_in_vector() {
690 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![0, 1, 3].into_iter()));
691 assert_eq!(bits, 5 )
692 }
693
694 #[test]
696 fn get_u32_with_empty_vector() {
697 let bits = get_u32_from_buttons(&HashSet::new());
698 assert_eq!(bits, 0 )
699 }
700
701 #[test]
703 fn get_u32_with_u8_max_in_vector() {
704 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, std::u8::MAX].into_iter()));
705 assert_eq!(bits, 5 )
706 }
707
708 #[test]
711 fn get_u32_with_max_mouse_buttons() {
712 let bits = get_u32_from_buttons(&HashSet::from_iter(
713 vec![1, 3, fidl_input_report::MOUSE_MAX_NUM_BUTTONS as MouseButton].into_iter(),
714 ));
715 assert_eq!(bits, 2147483653 )
716 }
717
718 #[fasync::run_singlethreaded(test)]
720 async fn movement_without_button() {
721 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
722 let first_report = testing_utilities::create_mouse_input_report_relative(
723 Position { x: 10.0, y: 16.0 },
724 None, None, vec![],
727 event_time_i64,
728 );
729 let descriptor = mouse_device_descriptor(DEVICE_ID);
730
731 let input_reports = vec![first_report];
732 let expected_events = vec![testing_utilities::create_mouse_event(
733 MouseLocation::Relative(RelativeLocation {
734 millimeters: Position {
735 x: 10.0 / COUNTS_PER_MM as f32,
736 y: 16.0 / COUNTS_PER_MM as f32,
737 },
738 }),
739 None, None, None, MousePhase::Move,
743 HashSet::new(),
744 HashSet::new(),
745 event_time_u64,
746 &descriptor,
747 )];
748
749 assert_input_report_sequence_generates_events!(
750 input_reports: input_reports,
751 expected_events: expected_events,
752 device_descriptor: descriptor,
753 device_type: MouseBinding,
754 );
755 }
756
757 #[fasync::run_singlethreaded(test)]
759 async fn down_without_movement() {
760 let mouse_button: MouseButton = 3;
761 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
762 let first_report = testing_utilities::create_mouse_input_report_relative(
763 Position::zero(),
764 None, None, vec![mouse_button],
767 event_time_i64,
768 );
769 let descriptor = mouse_device_descriptor(DEVICE_ID);
770
771 let input_reports = vec![first_report];
772 let expected_events = vec![testing_utilities::create_mouse_event(
773 MouseLocation::Relative(Default::default()),
774 None, None, None, MousePhase::Down,
778 HashSet::from_iter(vec![mouse_button].into_iter()),
779 HashSet::from_iter(vec![mouse_button].into_iter()),
780 event_time_u64,
781 &descriptor,
782 )];
783
784 assert_input_report_sequence_generates_events!(
785 input_reports: input_reports,
786 expected_events: expected_events,
787 device_descriptor: descriptor,
788 device_type: MouseBinding,
789 );
790 }
791
792 #[fasync::run_singlethreaded(test)]
795 async fn down_with_movement() {
796 let mouse_button: MouseButton = 3;
797 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
798 let first_report = testing_utilities::create_mouse_input_report_relative(
799 Position { x: 10.0, y: 16.0 },
800 None, None, vec![mouse_button],
803 event_time_i64,
804 );
805 let descriptor = mouse_device_descriptor(DEVICE_ID);
806
807 let input_reports = vec![first_report];
808 let expected_events = vec![
809 testing_utilities::create_mouse_event(
810 MouseLocation::Relative(Default::default()),
811 None, None, None, MousePhase::Down,
815 HashSet::from_iter(vec![mouse_button].into_iter()),
816 HashSet::from_iter(vec![mouse_button].into_iter()),
817 event_time_u64,
818 &descriptor,
819 ),
820 testing_utilities::create_mouse_event(
821 MouseLocation::Relative(RelativeLocation {
822 millimeters: Position {
823 x: 10.0 / COUNTS_PER_MM as f32,
824 y: 16.0 / COUNTS_PER_MM as f32,
825 },
826 }),
827 None, None, None, MousePhase::Move,
831 HashSet::from_iter(vec![mouse_button].into_iter()),
832 HashSet::from_iter(vec![mouse_button].into_iter()),
833 event_time_u64,
834 &descriptor,
835 ),
836 ];
837
838 assert_input_report_sequence_generates_events!(
839 input_reports: input_reports,
840 expected_events: expected_events,
841 device_descriptor: descriptor,
842 device_type: MouseBinding,
843 );
844 }
845
846 #[fasync::run_singlethreaded(test)]
848 async fn down_up() {
849 let button = 1;
850 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
851 let first_report = testing_utilities::create_mouse_input_report_relative(
852 Position::zero(),
853 None, None, vec![button],
856 event_time_i64,
857 );
858 let second_report = testing_utilities::create_mouse_input_report_relative(
859 Position::zero(),
860 None, None, vec![],
863 event_time_i64,
864 );
865 let descriptor = mouse_device_descriptor(DEVICE_ID);
866
867 let input_reports = vec![first_report, second_report];
868 let expected_events = vec![
869 testing_utilities::create_mouse_event(
870 MouseLocation::Relative(Default::default()),
871 None, None, None, MousePhase::Down,
875 HashSet::from_iter(vec![button].into_iter()),
876 HashSet::from_iter(vec![button].into_iter()),
877 event_time_u64,
878 &descriptor,
879 ),
880 testing_utilities::create_mouse_event(
881 MouseLocation::Relative(Default::default()),
882 None, None, None, MousePhase::Up,
886 HashSet::from_iter(vec![button].into_iter()),
887 HashSet::new(),
888 event_time_u64,
889 &descriptor,
890 ),
891 ];
892
893 assert_input_report_sequence_generates_events!(
894 input_reports: input_reports,
895 expected_events: expected_events,
896 device_descriptor: descriptor,
897 device_type: MouseBinding,
898 );
899 }
900
901 #[fasync::run_singlethreaded(test)]
903 async fn down_up_with_movement() {
904 let button = 1;
905
906 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
907 let first_report = testing_utilities::create_mouse_input_report_relative(
908 Position::zero(),
909 None, None, vec![button],
912 event_time_i64,
913 );
914 let second_report = testing_utilities::create_mouse_input_report_relative(
915 Position { x: 10.0, y: 16.0 },
916 None, None, vec![],
919 event_time_i64,
920 );
921 let descriptor = mouse_device_descriptor(DEVICE_ID);
922
923 let input_reports = vec![first_report, second_report];
924 let expected_events = vec![
925 testing_utilities::create_mouse_event(
926 MouseLocation::Relative(Default::default()),
927 None, None, None, MousePhase::Down,
931 HashSet::from_iter(vec![button].into_iter()),
932 HashSet::from_iter(vec![button].into_iter()),
933 event_time_u64,
934 &descriptor,
935 ),
936 testing_utilities::create_mouse_event(
937 MouseLocation::Relative(RelativeLocation {
938 millimeters: Position {
939 x: 10.0 / COUNTS_PER_MM as f32,
940 y: 16.0 / COUNTS_PER_MM as f32,
941 },
942 }),
943 None, None, None, MousePhase::Move,
947 HashSet::from_iter(vec![button].into_iter()),
948 HashSet::from_iter(vec![button].into_iter()),
949 event_time_u64,
950 &descriptor,
951 ),
952 testing_utilities::create_mouse_event(
953 MouseLocation::Relative(Default::default()),
954 None, None, None, MousePhase::Up,
958 HashSet::from_iter(vec![button].into_iter()),
959 HashSet::new(),
960 event_time_u64,
961 &descriptor,
962 ),
963 ];
964
965 assert_input_report_sequence_generates_events!(
966 input_reports: input_reports,
967 expected_events: expected_events,
968 device_descriptor: descriptor,
969 device_type: MouseBinding,
970 );
971 }
972
973 #[fasync::run_singlethreaded(test)]
977 async fn down_move_up() {
978 let button = 1;
979
980 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
981 let first_report = testing_utilities::create_mouse_input_report_relative(
982 Position::zero(),
983 None, None, vec![button],
986 event_time_i64,
987 );
988 let second_report = testing_utilities::create_mouse_input_report_relative(
989 Position { x: 10.0, y: 16.0 },
990 None, None, vec![button],
993 event_time_i64,
994 );
995 let third_report = testing_utilities::create_mouse_input_report_relative(
996 Position::zero(),
997 None, None, vec![],
1000 event_time_i64,
1001 );
1002 let descriptor = mouse_device_descriptor(DEVICE_ID);
1003
1004 let input_reports = vec![first_report, second_report, third_report];
1005 let expected_events = vec![
1006 testing_utilities::create_mouse_event(
1007 MouseLocation::Relative(Default::default()),
1008 None, None, None, MousePhase::Down,
1012 HashSet::from_iter(vec![button].into_iter()),
1013 HashSet::from_iter(vec![button].into_iter()),
1014 event_time_u64,
1015 &descriptor,
1016 ),
1017 testing_utilities::create_mouse_event(
1018 MouseLocation::Relative(RelativeLocation {
1019 millimeters: Position {
1020 x: 10.0 / COUNTS_PER_MM as f32,
1021 y: 16.0 / COUNTS_PER_MM as f32,
1022 },
1023 }),
1024 None, None, None, MousePhase::Move,
1028 HashSet::from_iter(vec![button].into_iter()),
1029 HashSet::from_iter(vec![button].into_iter()),
1030 event_time_u64,
1031 &descriptor,
1032 ),
1033 testing_utilities::create_mouse_event(
1034 MouseLocation::Relative(Default::default()),
1035 None, None, None, MousePhase::Up,
1039 HashSet::from_iter(vec![button].into_iter()),
1040 HashSet::new(),
1041 event_time_u64,
1042 &descriptor,
1043 ),
1044 ];
1045
1046 assert_input_report_sequence_generates_events!(
1047 input_reports: input_reports,
1048 expected_events: expected_events,
1049 device_descriptor: descriptor,
1050 device_type: MouseBinding,
1051 );
1052 }
1053
1054 #[fasync::run_until_stalled(test)]
1056 async fn absolute_movement_to_origin() {
1057 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1058 let descriptor = mouse_device_descriptor(DEVICE_ID);
1059
1060 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
1061 Position::zero(),
1062 None, None, vec![],
1065 event_time_i64,
1066 )];
1067 let expected_events = vec![testing_utilities::create_mouse_event(
1068 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1069 None, None, None, MousePhase::Move,
1073 HashSet::new(),
1074 HashSet::new(),
1075 event_time_u64,
1076 &descriptor,
1077 )];
1078
1079 assert_input_report_sequence_generates_events!(
1080 input_reports: input_reports,
1081 expected_events: expected_events,
1082 device_descriptor: descriptor,
1083 device_type: MouseBinding,
1084 );
1085 }
1086
1087 #[fasync::run_until_stalled(test)]
1090 async fn report_with_both_movement_and_position() {
1091 let relative_movement = Position { x: 5.0, y: 5.0 };
1092 let absolute_position = Position { x: 10.0, y: 10.0 };
1093 let expected_location = MouseLocation::Absolute(absolute_position);
1094
1095 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1096 let descriptor = mouse_device_descriptor(DEVICE_ID);
1097
1098 let input_reports = vec![fidl_input_report::InputReport {
1099 event_time: Some(event_time_i64),
1100 keyboard: None,
1101 mouse: Some(fidl_input_report::MouseInputReport {
1102 movement_x: Some(relative_movement.x as i64),
1103 movement_y: Some(relative_movement.y as i64),
1104 position_x: Some(absolute_position.x as i64),
1105 position_y: Some(absolute_position.y as i64),
1106 scroll_h: None,
1107 scroll_v: None,
1108 pressed_buttons: None,
1109 ..Default::default()
1110 }),
1111 touch: None,
1112 sensor: None,
1113 consumer_control: None,
1114 trace_id: None,
1115 ..Default::default()
1116 }];
1117 let expected_events = vec![testing_utilities::create_mouse_event(
1118 expected_location,
1119 None, None, None, MousePhase::Move,
1123 HashSet::new(),
1124 HashSet::new(),
1125 event_time_u64,
1126 &descriptor,
1127 )];
1128
1129 assert_input_report_sequence_generates_events!(
1130 input_reports: input_reports,
1131 expected_events: expected_events,
1132 device_descriptor: descriptor,
1133 device_type: MouseBinding,
1134 );
1135 }
1136
1137 #[fasync::run_singlethreaded(test)]
1140 async fn down_down() {
1141 const PRIMARY_BUTTON: u8 = 1;
1142 const SECONDARY_BUTTON: u8 = 2;
1143
1144 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1145 let first_report = testing_utilities::create_mouse_input_report_relative(
1146 Position::zero(),
1147 None, None, vec![PRIMARY_BUTTON],
1150 event_time_i64,
1151 );
1152 let second_report = testing_utilities::create_mouse_input_report_relative(
1153 Position::zero(),
1154 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1157 event_time_i64,
1158 );
1159 let descriptor = mouse_device_descriptor(DEVICE_ID);
1160
1161 let input_reports = vec![first_report, second_report];
1162 let expected_events = vec![
1163 testing_utilities::create_mouse_event(
1164 MouseLocation::Relative(Default::default()),
1165 None, None, None, MousePhase::Down,
1169 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1170 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1171 event_time_u64,
1172 &descriptor,
1173 ),
1174 testing_utilities::create_mouse_event(
1175 MouseLocation::Relative(Default::default()),
1176 None, None, None, MousePhase::Down,
1180 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1181 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1182 event_time_u64,
1183 &descriptor,
1184 ),
1185 ];
1186
1187 assert_input_report_sequence_generates_events!(
1188 input_reports: input_reports,
1189 expected_events: expected_events,
1190 device_descriptor: descriptor,
1191 device_type: MouseBinding,
1192 );
1193 }
1194
1195 #[fasync::run_singlethreaded(test)]
1205 async fn down_down_up_up() {
1206 const PRIMARY_BUTTON: u8 = 1;
1207 const SECONDARY_BUTTON: u8 = 2;
1208
1209 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1210 let first_report = testing_utilities::create_mouse_input_report_relative(
1211 Position::zero(),
1212 None, None, vec![PRIMARY_BUTTON],
1215 event_time_i64,
1216 );
1217 let second_report = testing_utilities::create_mouse_input_report_relative(
1218 Position::zero(),
1219 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1222 event_time_i64,
1223 );
1224 let third_report = testing_utilities::create_mouse_input_report_relative(
1225 Position::zero(),
1226 None, None, vec![SECONDARY_BUTTON],
1229 event_time_i64,
1230 );
1231 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1232 Position::zero(),
1233 None, None, vec![],
1236 event_time_i64,
1237 );
1238 let descriptor = mouse_device_descriptor(DEVICE_ID);
1239
1240 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1241 let expected_events = vec![
1242 testing_utilities::create_mouse_event(
1243 MouseLocation::Relative(Default::default()),
1244 None, None, None, MousePhase::Down,
1248 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1249 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1250 event_time_u64,
1251 &descriptor,
1252 ),
1253 testing_utilities::create_mouse_event(
1254 MouseLocation::Relative(Default::default()),
1255 None, None, None, MousePhase::Down,
1259 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1260 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1261 event_time_u64,
1262 &descriptor,
1263 ),
1264 testing_utilities::create_mouse_event(
1265 MouseLocation::Relative(Default::default()),
1266 None, None, None, MousePhase::Up,
1270 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1271 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1272 event_time_u64,
1273 &descriptor,
1274 ),
1275 testing_utilities::create_mouse_event(
1276 MouseLocation::Relative(Default::default()),
1277 None, None, None, MousePhase::Up,
1281 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1282 HashSet::new(),
1283 event_time_u64,
1284 &descriptor,
1285 ),
1286 ];
1287
1288 assert_input_report_sequence_generates_events!(
1289 input_reports: input_reports,
1290 expected_events: expected_events,
1291 device_descriptor: descriptor,
1292 device_type: MouseBinding,
1293 );
1294 }
1295
1296 #[fasync::run_singlethreaded(test)]
1298 async fn scroll() {
1299 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1300 let first_report = testing_utilities::create_mouse_input_report_relative(
1301 Position::zero(),
1302 Some(1),
1303 None,
1304 vec![],
1305 event_time_i64,
1306 );
1307 let second_report = testing_utilities::create_mouse_input_report_relative(
1308 Position::zero(),
1309 None,
1310 Some(1),
1311 vec![],
1312 event_time_i64,
1313 );
1314
1315 let descriptor = mouse_device_descriptor(DEVICE_ID);
1316
1317 let input_reports = vec![first_report, second_report];
1318 let expected_events = vec![
1319 testing_utilities::create_mouse_event(
1320 MouseLocation::Relative(Default::default()),
1321 wheel_delta_ticks(1),
1322 None,
1323 Some(PrecisionScroll::No),
1324 MousePhase::Wheel,
1325 HashSet::new(),
1326 HashSet::new(),
1327 event_time_u64,
1328 &descriptor,
1329 ),
1330 testing_utilities::create_mouse_event(
1331 MouseLocation::Relative(Default::default()),
1332 None,
1333 wheel_delta_ticks(1),
1334 Some(PrecisionScroll::No),
1335 MousePhase::Wheel,
1336 HashSet::new(),
1337 HashSet::new(),
1338 event_time_u64,
1339 &descriptor,
1340 ),
1341 ];
1342
1343 assert_input_report_sequence_generates_events!(
1344 input_reports: input_reports,
1345 expected_events: expected_events,
1346 device_descriptor: descriptor,
1347 device_type: MouseBinding,
1348 );
1349 }
1350
1351 #[fasync::run_singlethreaded(test)]
1353 async fn down_scroll_up_scroll() {
1354 const PRIMARY_BUTTON: u8 = 1;
1355
1356 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1357 let first_report = testing_utilities::create_mouse_input_report_relative(
1358 Position::zero(),
1359 None, None, vec![PRIMARY_BUTTON],
1362 event_time_i64,
1363 );
1364 let second_report = testing_utilities::create_mouse_input_report_relative(
1365 Position::zero(),
1366 Some(1),
1367 None,
1368 vec![PRIMARY_BUTTON],
1369 event_time_i64,
1370 );
1371 let third_report = testing_utilities::create_mouse_input_report_relative(
1372 Position::zero(),
1373 None, None, vec![],
1376 event_time_i64,
1377 );
1378 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1379 Position::zero(),
1380 Some(1),
1381 None,
1382 vec![],
1383 event_time_i64,
1384 );
1385
1386 let descriptor = mouse_device_descriptor(DEVICE_ID);
1387
1388 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1389 let expected_events = vec![
1390 testing_utilities::create_mouse_event(
1391 MouseLocation::Relative(Default::default()),
1392 None, None, None, MousePhase::Down,
1396 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1397 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1398 event_time_u64,
1399 &descriptor,
1400 ),
1401 testing_utilities::create_mouse_event(
1402 MouseLocation::Relative(Default::default()),
1403 wheel_delta_ticks(1),
1404 None,
1405 Some(PrecisionScroll::No),
1406 MousePhase::Wheel,
1407 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1408 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1409 event_time_u64,
1410 &descriptor,
1411 ),
1412 testing_utilities::create_mouse_event(
1413 MouseLocation::Relative(Default::default()),
1414 None, None, None, MousePhase::Up,
1418 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1419 HashSet::new(),
1420 event_time_u64,
1421 &descriptor,
1422 ),
1423 testing_utilities::create_mouse_event(
1424 MouseLocation::Relative(Default::default()),
1425 wheel_delta_ticks(1),
1426 None,
1427 Some(PrecisionScroll::No),
1428 MousePhase::Wheel,
1429 HashSet::new(),
1430 HashSet::new(),
1431 event_time_u64,
1432 &descriptor,
1433 ),
1434 ];
1435
1436 assert_input_report_sequence_generates_events!(
1437 input_reports: input_reports,
1438 expected_events: expected_events,
1439 device_descriptor: descriptor,
1440 device_type: MouseBinding,
1441 );
1442 }
1443
1444 #[fasync::run_singlethreaded(test)]
1446 async fn down_scroll_bundle_up_scroll_bundle() {
1447 const PRIMARY_BUTTON: u8 = 1;
1448
1449 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1450 let first_report = testing_utilities::create_mouse_input_report_relative(
1451 Position::zero(),
1452 Some(1),
1453 None,
1454 vec![PRIMARY_BUTTON],
1455 event_time_i64,
1456 );
1457 let second_report = testing_utilities::create_mouse_input_report_relative(
1458 Position::zero(),
1459 Some(1),
1460 None,
1461 vec![],
1462 event_time_i64,
1463 );
1464 let third_report = testing_utilities::create_mouse_input_report_relative(
1465 Position::zero(),
1466 Some(1),
1467 None,
1468 vec![],
1469 event_time_i64,
1470 );
1471
1472 let descriptor = mouse_device_descriptor(DEVICE_ID);
1473
1474 let input_reports = vec![first_report, second_report, third_report];
1475 let expected_events = vec![
1476 testing_utilities::create_mouse_event(
1477 MouseLocation::Relative(Default::default()),
1478 None, None, None, MousePhase::Down,
1482 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1483 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1484 event_time_u64,
1485 &descriptor,
1486 ),
1487 testing_utilities::create_mouse_event(
1488 MouseLocation::Relative(Default::default()),
1489 wheel_delta_ticks(1),
1490 None,
1491 Some(PrecisionScroll::No),
1492 MousePhase::Wheel,
1493 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1494 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1495 event_time_u64,
1496 &descriptor,
1497 ),
1498 testing_utilities::create_mouse_event(
1499 MouseLocation::Relative(Default::default()),
1500 wheel_delta_ticks(1),
1501 None,
1502 Some(PrecisionScroll::No),
1503 MousePhase::Wheel,
1504 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1505 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1506 event_time_u64,
1507 &descriptor,
1508 ),
1509 testing_utilities::create_mouse_event(
1510 MouseLocation::Relative(Default::default()),
1511 None, None, None, MousePhase::Up,
1515 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1516 HashSet::new(),
1517 event_time_u64,
1518 &descriptor,
1519 ),
1520 testing_utilities::create_mouse_event(
1521 MouseLocation::Relative(Default::default()),
1522 wheel_delta_ticks(1),
1523 None,
1524 Some(PrecisionScroll::No),
1525 MousePhase::Wheel,
1526 HashSet::new(),
1527 HashSet::new(),
1528 event_time_u64,
1529 &descriptor,
1530 ),
1531 ];
1532
1533 assert_input_report_sequence_generates_events!(
1534 input_reports: input_reports,
1535 expected_events: expected_events,
1536 device_descriptor: descriptor,
1537 device_type: MouseBinding,
1538 );
1539 }
1540}