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 fuchsia_trace::duration!(c"input", c"mouse-binding-process-report");
397 if let Some(trace_id) = report.trace_id {
398 fuchsia_trace::flow_end!(c"input", c"input_report", trace_id.into());
399 }
400
401 inspect_status.count_received_report(&report);
402 let mouse_report: &fidl_input_report::MouseInputReport = match &report.mouse {
404 Some(mouse) => mouse,
405 None => {
406 inspect_status.count_filtered_report();
407 return (previous_report, None);
408 }
409 };
410
411 let previous_buttons: HashSet<MouseButton> =
412 buttons_from_optional_report(&previous_report.as_ref());
413 let current_buttons: HashSet<MouseButton> = buttons_from_report(&report);
414
415 send_mouse_event(
421 MouseLocation::Relative(Default::default()),
422 None, None, MousePhase::Down,
425 current_buttons.difference(&previous_buttons).cloned().collect(),
426 current_buttons.clone(),
427 device_descriptor,
428 input_event_sender,
429 inspect_status,
430 metrics_logger,
431 );
432
433 let counts_per_mm = match device_descriptor {
434 input_device::InputDeviceDescriptor::Mouse(ds) => ds.counts_per_mm,
435 _ => {
436 metrics_logger.log_error(
437 InputPipelineErrorMetricDimensionEvent::MouseDescriptionNotMouse,
438 "mouse_binding::process_reports got device_descriptor not mouse".to_string(),
439 );
440 mouse_model_database::db::DEFAULT_COUNTS_PER_MM
441 }
442 };
443
444 let location = if let (Some(position_x), Some(position_y)) =
446 (mouse_report.position_x, mouse_report.position_y)
447 {
448 MouseLocation::Absolute(Position { x: position_x as f32, y: position_y as f32 })
449 } else {
450 let movement_x = mouse_report.movement_x.unwrap_or_default() as f32;
451 let movement_y = mouse_report.movement_y.unwrap_or_default() as f32;
452 MouseLocation::Relative(RelativeLocation {
453 millimeters: Position {
454 x: movement_x / counts_per_mm as f32,
455 y: movement_y / counts_per_mm as f32,
456 },
457 })
458 };
459
460 send_mouse_event(
464 location,
465 None, None, MousePhase::Move,
468 current_buttons.union(&previous_buttons).cloned().collect(),
469 current_buttons.union(&previous_buttons).cloned().collect(),
470 device_descriptor,
471 input_event_sender,
472 inspect_status,
473 metrics_logger,
474 );
475
476 let wheel_delta_v = match mouse_report.scroll_v {
477 None => None,
478 Some(ticks) => {
479 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
480 }
481 };
482
483 let wheel_delta_h = match mouse_report.scroll_h {
484 None => None,
485 Some(ticks) => {
486 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
487 }
488 };
489
490 send_mouse_event(
492 MouseLocation::Relative(Default::default()),
493 wheel_delta_v,
494 wheel_delta_h,
495 MousePhase::Wheel,
496 current_buttons.union(&previous_buttons).cloned().collect(),
497 current_buttons.union(&previous_buttons).cloned().collect(),
498 device_descriptor,
499 input_event_sender,
500 inspect_status,
501 metrics_logger,
502 );
503
504 send_mouse_event(
510 MouseLocation::Relative(Default::default()),
511 None, None, MousePhase::Up,
514 previous_buttons.difference(¤t_buttons).cloned().collect(),
515 current_buttons.clone(),
516 device_descriptor,
517 input_event_sender,
518 inspect_status,
519 metrics_logger,
520 );
521
522 (Some(report), None)
523 }
524}
525
526fn send_mouse_event(
540 location: MouseLocation,
541 wheel_delta_v: Option<WheelDelta>,
542 wheel_delta_h: Option<WheelDelta>,
543 phase: MousePhase,
544 affected_buttons: HashSet<MouseButton>,
545 pressed_buttons: HashSet<MouseButton>,
546 device_descriptor: &input_device::InputDeviceDescriptor,
547 sender: &mut UnboundedSender<input_device::InputEvent>,
548 inspect_status: &InputDeviceStatus,
549 metrics_logger: &metrics::MetricsLogger,
550) {
551 if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
553 return;
554 }
555
556 if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
559 return;
560 }
561
562 if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
564 return;
565 }
566
567 let trace_id = fuchsia_trace::Id::random();
568 fuchsia_trace::duration!(c"input", c"mouse-binding-send-event");
569 fuchsia_trace::flow_begin!(c"input", c"event_in_input_pipeline", trace_id);
570
571 let event = input_device::InputEvent {
572 device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
573 location,
574 wheel_delta_v,
575 wheel_delta_h,
576 phase,
577 affected_buttons,
578 pressed_buttons,
579 match phase {
580 MousePhase::Wheel => Some(PrecisionScroll::No),
581 _ => None,
582 },
583 )),
584 device_descriptor: device_descriptor.clone(),
585 event_time: zx::MonotonicInstant::get(),
586 handled: Handled::No,
587 trace_id: Some(trace_id),
588 };
589
590 match sender.unbounded_send(event.clone()) {
591 Err(e) => {
592 metrics_logger.log_error(
593 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
594 std::format!("Failed to send MouseEvent with error: {:?}", e),
595 );
596 }
597 _ => inspect_status.count_generated_event(event),
598 }
599}
600
601pub fn get_u32_from_buttons(buttons: &HashSet<MouseButton>) -> u32 {
615 let mut bits: u32 = 0;
616 for button in buttons {
617 if *button > 0 && *button <= fidl_input_report::MOUSE_MAX_NUM_BUTTONS as u8 {
618 bits = ((1 as u32) << *button - 1) | bits;
619 }
620 }
621
622 bits
623}
624
625fn buttons_from_report(input_report: &fidl_input_report::InputReport) -> HashSet<MouseButton> {
630 buttons_from_optional_report(&Some(input_report))
631}
632
633fn buttons_from_optional_report(
638 input_report: &Option<&fidl_input_report::InputReport>,
639) -> HashSet<MouseButton> {
640 input_report
641 .as_ref()
642 .and_then(|unwrapped_report| unwrapped_report.mouse.as_ref())
643 .and_then(|mouse_report| match &mouse_report.pressed_buttons {
644 Some(buttons) => Some(HashSet::from_iter(buttons.iter().cloned())),
645 None => None,
646 })
647 .unwrap_or_default()
648}
649
650#[cfg(test)]
651mod tests {
652 use super::*;
653 use crate::testing_utilities;
654 use fuchsia_async as fasync;
655 use futures::StreamExt;
656 use pretty_assertions::assert_eq;
657
658 const DEVICE_ID: u32 = 1;
659 const COUNTS_PER_MM: u32 = 12;
660
661 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
662 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
663 device_id,
664 absolute_x_range: None,
665 absolute_y_range: None,
666 wheel_v_range: Some(fidl_fuchsia_input_report::Axis {
667 range: fidl_input_report::Range { min: -1, max: 1 },
668 unit: fidl_input_report::Unit {
669 type_: fidl_input_report::UnitType::Other,
670 exponent: 1,
671 },
672 }),
673 wheel_h_range: Some(fidl_fuchsia_input_report::Axis {
674 range: fidl_input_report::Range { min: -1, max: 1 },
675 unit: fidl_input_report::Unit {
676 type_: fidl_input_report::UnitType::Other,
677 exponent: 1,
678 },
679 }),
680 buttons: None,
681 counts_per_mm: COUNTS_PER_MM,
682 })
683 }
684
685 fn wheel_delta_ticks(delta: i64) -> Option<WheelDelta> {
686 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(delta), physical_pixel: None })
687 }
688
689 #[test]
691 fn get_u32_from_buttons_test() {
692 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, 5].into_iter()));
693 assert_eq!(bits, 21 )
694 }
695
696 #[test]
698 fn get_u32_with_0_in_vector() {
699 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![0, 1, 3].into_iter()));
700 assert_eq!(bits, 5 )
701 }
702
703 #[test]
705 fn get_u32_with_empty_vector() {
706 let bits = get_u32_from_buttons(&HashSet::new());
707 assert_eq!(bits, 0 )
708 }
709
710 #[test]
712 fn get_u32_with_u8_max_in_vector() {
713 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, std::u8::MAX].into_iter()));
714 assert_eq!(bits, 5 )
715 }
716
717 #[test]
720 fn get_u32_with_max_mouse_buttons() {
721 let bits = get_u32_from_buttons(&HashSet::from_iter(
722 vec![1, 3, fidl_input_report::MOUSE_MAX_NUM_BUTTONS as MouseButton].into_iter(),
723 ));
724 assert_eq!(bits, 2147483653 )
725 }
726
727 #[fasync::run_singlethreaded(test)]
729 async fn movement_without_button() {
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 { x: 10.0, y: 16.0 },
733 None, None, vec![],
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(RelativeLocation {
743 millimeters: Position {
744 x: 10.0 / COUNTS_PER_MM as f32,
745 y: 16.0 / COUNTS_PER_MM as f32,
746 },
747 }),
748 None, None, None, MousePhase::Move,
752 HashSet::new(),
753 HashSet::new(),
754 event_time_u64,
755 &descriptor,
756 )];
757
758 assert_input_report_sequence_generates_events!(
759 input_reports: input_reports,
760 expected_events: expected_events,
761 device_descriptor: descriptor,
762 device_type: MouseBinding,
763 );
764 }
765
766 #[fasync::run_singlethreaded(test)]
768 async fn down_without_movement() {
769 let mouse_button: MouseButton = 3;
770 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
771 let first_report = testing_utilities::create_mouse_input_report_relative(
772 Position::zero(),
773 None, None, vec![mouse_button],
776 event_time_i64,
777 );
778 let descriptor = mouse_device_descriptor(DEVICE_ID);
779
780 let input_reports = vec![first_report];
781 let expected_events = vec![testing_utilities::create_mouse_event(
782 MouseLocation::Relative(Default::default()),
783 None, None, None, MousePhase::Down,
787 HashSet::from_iter(vec![mouse_button].into_iter()),
788 HashSet::from_iter(vec![mouse_button].into_iter()),
789 event_time_u64,
790 &descriptor,
791 )];
792
793 assert_input_report_sequence_generates_events!(
794 input_reports: input_reports,
795 expected_events: expected_events,
796 device_descriptor: descriptor,
797 device_type: MouseBinding,
798 );
799 }
800
801 #[fasync::run_singlethreaded(test)]
804 async fn down_with_movement() {
805 let mouse_button: MouseButton = 3;
806 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
807 let first_report = testing_utilities::create_mouse_input_report_relative(
808 Position { x: 10.0, y: 16.0 },
809 None, None, vec![mouse_button],
812 event_time_i64,
813 );
814 let descriptor = mouse_device_descriptor(DEVICE_ID);
815
816 let input_reports = vec![first_report];
817 let expected_events = vec![
818 testing_utilities::create_mouse_event(
819 MouseLocation::Relative(Default::default()),
820 None, None, None, MousePhase::Down,
824 HashSet::from_iter(vec![mouse_button].into_iter()),
825 HashSet::from_iter(vec![mouse_button].into_iter()),
826 event_time_u64,
827 &descriptor,
828 ),
829 testing_utilities::create_mouse_event(
830 MouseLocation::Relative(RelativeLocation {
831 millimeters: Position {
832 x: 10.0 / COUNTS_PER_MM as f32,
833 y: 16.0 / COUNTS_PER_MM as f32,
834 },
835 }),
836 None, None, None, MousePhase::Move,
840 HashSet::from_iter(vec![mouse_button].into_iter()),
841 HashSet::from_iter(vec![mouse_button].into_iter()),
842 event_time_u64,
843 &descriptor,
844 ),
845 ];
846
847 assert_input_report_sequence_generates_events!(
848 input_reports: input_reports,
849 expected_events: expected_events,
850 device_descriptor: descriptor,
851 device_type: MouseBinding,
852 );
853 }
854
855 #[fasync::run_singlethreaded(test)]
857 async fn down_up() {
858 let button = 1;
859 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
860 let first_report = testing_utilities::create_mouse_input_report_relative(
861 Position::zero(),
862 None, None, vec![button],
865 event_time_i64,
866 );
867 let second_report = testing_utilities::create_mouse_input_report_relative(
868 Position::zero(),
869 None, None, vec![],
872 event_time_i64,
873 );
874 let descriptor = mouse_device_descriptor(DEVICE_ID);
875
876 let input_reports = vec![first_report, second_report];
877 let expected_events = vec![
878 testing_utilities::create_mouse_event(
879 MouseLocation::Relative(Default::default()),
880 None, None, None, MousePhase::Down,
884 HashSet::from_iter(vec![button].into_iter()),
885 HashSet::from_iter(vec![button].into_iter()),
886 event_time_u64,
887 &descriptor,
888 ),
889 testing_utilities::create_mouse_event(
890 MouseLocation::Relative(Default::default()),
891 None, None, None, MousePhase::Up,
895 HashSet::from_iter(vec![button].into_iter()),
896 HashSet::new(),
897 event_time_u64,
898 &descriptor,
899 ),
900 ];
901
902 assert_input_report_sequence_generates_events!(
903 input_reports: input_reports,
904 expected_events: expected_events,
905 device_descriptor: descriptor,
906 device_type: MouseBinding,
907 );
908 }
909
910 #[fasync::run_singlethreaded(test)]
912 async fn down_up_with_movement() {
913 let button = 1;
914
915 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
916 let first_report = testing_utilities::create_mouse_input_report_relative(
917 Position::zero(),
918 None, None, vec![button],
921 event_time_i64,
922 );
923 let second_report = testing_utilities::create_mouse_input_report_relative(
924 Position { x: 10.0, y: 16.0 },
925 None, None, vec![],
928 event_time_i64,
929 );
930 let descriptor = mouse_device_descriptor(DEVICE_ID);
931
932 let input_reports = vec![first_report, second_report];
933 let expected_events = vec![
934 testing_utilities::create_mouse_event(
935 MouseLocation::Relative(Default::default()),
936 None, None, None, MousePhase::Down,
940 HashSet::from_iter(vec![button].into_iter()),
941 HashSet::from_iter(vec![button].into_iter()),
942 event_time_u64,
943 &descriptor,
944 ),
945 testing_utilities::create_mouse_event(
946 MouseLocation::Relative(RelativeLocation {
947 millimeters: Position {
948 x: 10.0 / COUNTS_PER_MM as f32,
949 y: 16.0 / COUNTS_PER_MM as f32,
950 },
951 }),
952 None, None, None, MousePhase::Move,
956 HashSet::from_iter(vec![button].into_iter()),
957 HashSet::from_iter(vec![button].into_iter()),
958 event_time_u64,
959 &descriptor,
960 ),
961 testing_utilities::create_mouse_event(
962 MouseLocation::Relative(Default::default()),
963 None, None, None, MousePhase::Up,
967 HashSet::from_iter(vec![button].into_iter()),
968 HashSet::new(),
969 event_time_u64,
970 &descriptor,
971 ),
972 ];
973
974 assert_input_report_sequence_generates_events!(
975 input_reports: input_reports,
976 expected_events: expected_events,
977 device_descriptor: descriptor,
978 device_type: MouseBinding,
979 );
980 }
981
982 #[fasync::run_singlethreaded(test)]
986 async fn down_move_up() {
987 let button = 1;
988
989 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
990 let first_report = testing_utilities::create_mouse_input_report_relative(
991 Position::zero(),
992 None, None, vec![button],
995 event_time_i64,
996 );
997 let second_report = testing_utilities::create_mouse_input_report_relative(
998 Position { x: 10.0, y: 16.0 },
999 None, None, vec![button],
1002 event_time_i64,
1003 );
1004 let third_report = testing_utilities::create_mouse_input_report_relative(
1005 Position::zero(),
1006 None, None, vec![],
1009 event_time_i64,
1010 );
1011 let descriptor = mouse_device_descriptor(DEVICE_ID);
1012
1013 let input_reports = vec![first_report, second_report, third_report];
1014 let expected_events = vec![
1015 testing_utilities::create_mouse_event(
1016 MouseLocation::Relative(Default::default()),
1017 None, None, None, MousePhase::Down,
1021 HashSet::from_iter(vec![button].into_iter()),
1022 HashSet::from_iter(vec![button].into_iter()),
1023 event_time_u64,
1024 &descriptor,
1025 ),
1026 testing_utilities::create_mouse_event(
1027 MouseLocation::Relative(RelativeLocation {
1028 millimeters: Position {
1029 x: 10.0 / COUNTS_PER_MM as f32,
1030 y: 16.0 / COUNTS_PER_MM as f32,
1031 },
1032 }),
1033 None, None, None, MousePhase::Move,
1037 HashSet::from_iter(vec![button].into_iter()),
1038 HashSet::from_iter(vec![button].into_iter()),
1039 event_time_u64,
1040 &descriptor,
1041 ),
1042 testing_utilities::create_mouse_event(
1043 MouseLocation::Relative(Default::default()),
1044 None, None, None, MousePhase::Up,
1048 HashSet::from_iter(vec![button].into_iter()),
1049 HashSet::new(),
1050 event_time_u64,
1051 &descriptor,
1052 ),
1053 ];
1054
1055 assert_input_report_sequence_generates_events!(
1056 input_reports: input_reports,
1057 expected_events: expected_events,
1058 device_descriptor: descriptor,
1059 device_type: MouseBinding,
1060 );
1061 }
1062
1063 #[fasync::run_until_stalled(test)]
1065 async fn absolute_movement_to_origin() {
1066 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1067 let descriptor = mouse_device_descriptor(DEVICE_ID);
1068
1069 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
1070 Position::zero(),
1071 None, None, vec![],
1074 event_time_i64,
1075 )];
1076 let expected_events = vec![testing_utilities::create_mouse_event(
1077 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1078 None, None, None, MousePhase::Move,
1082 HashSet::new(),
1083 HashSet::new(),
1084 event_time_u64,
1085 &descriptor,
1086 )];
1087
1088 assert_input_report_sequence_generates_events!(
1089 input_reports: input_reports,
1090 expected_events: expected_events,
1091 device_descriptor: descriptor,
1092 device_type: MouseBinding,
1093 );
1094 }
1095
1096 #[fasync::run_until_stalled(test)]
1099 async fn report_with_both_movement_and_position() {
1100 let relative_movement = Position { x: 5.0, y: 5.0 };
1101 let absolute_position = Position { x: 10.0, y: 10.0 };
1102 let expected_location = MouseLocation::Absolute(absolute_position);
1103
1104 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1105 let descriptor = mouse_device_descriptor(DEVICE_ID);
1106
1107 let input_reports = vec![fidl_input_report::InputReport {
1108 event_time: Some(event_time_i64),
1109 keyboard: None,
1110 mouse: Some(fidl_input_report::MouseInputReport {
1111 movement_x: Some(relative_movement.x as i64),
1112 movement_y: Some(relative_movement.y as i64),
1113 position_x: Some(absolute_position.x as i64),
1114 position_y: Some(absolute_position.y as i64),
1115 scroll_h: None,
1116 scroll_v: None,
1117 pressed_buttons: None,
1118 ..Default::default()
1119 }),
1120 touch: None,
1121 sensor: None,
1122 consumer_control: None,
1123 trace_id: None,
1124 ..Default::default()
1125 }];
1126 let expected_events = vec![testing_utilities::create_mouse_event(
1127 expected_location,
1128 None, None, None, MousePhase::Move,
1132 HashSet::new(),
1133 HashSet::new(),
1134 event_time_u64,
1135 &descriptor,
1136 )];
1137
1138 assert_input_report_sequence_generates_events!(
1139 input_reports: input_reports,
1140 expected_events: expected_events,
1141 device_descriptor: descriptor,
1142 device_type: MouseBinding,
1143 );
1144 }
1145
1146 #[fasync::run_singlethreaded(test)]
1149 async fn down_down() {
1150 const PRIMARY_BUTTON: u8 = 1;
1151 const SECONDARY_BUTTON: u8 = 2;
1152
1153 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1154 let first_report = testing_utilities::create_mouse_input_report_relative(
1155 Position::zero(),
1156 None, None, vec![PRIMARY_BUTTON],
1159 event_time_i64,
1160 );
1161 let second_report = testing_utilities::create_mouse_input_report_relative(
1162 Position::zero(),
1163 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1166 event_time_i64,
1167 );
1168 let descriptor = mouse_device_descriptor(DEVICE_ID);
1169
1170 let input_reports = vec![first_report, second_report];
1171 let expected_events = vec![
1172 testing_utilities::create_mouse_event(
1173 MouseLocation::Relative(Default::default()),
1174 None, None, None, MousePhase::Down,
1178 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1179 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1180 event_time_u64,
1181 &descriptor,
1182 ),
1183 testing_utilities::create_mouse_event(
1184 MouseLocation::Relative(Default::default()),
1185 None, None, None, MousePhase::Down,
1189 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1190 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1191 event_time_u64,
1192 &descriptor,
1193 ),
1194 ];
1195
1196 assert_input_report_sequence_generates_events!(
1197 input_reports: input_reports,
1198 expected_events: expected_events,
1199 device_descriptor: descriptor,
1200 device_type: MouseBinding,
1201 );
1202 }
1203
1204 #[fasync::run_singlethreaded(test)]
1214 async fn down_down_up_up() {
1215 const PRIMARY_BUTTON: u8 = 1;
1216 const SECONDARY_BUTTON: u8 = 2;
1217
1218 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1219 let first_report = testing_utilities::create_mouse_input_report_relative(
1220 Position::zero(),
1221 None, None, vec![PRIMARY_BUTTON],
1224 event_time_i64,
1225 );
1226 let second_report = testing_utilities::create_mouse_input_report_relative(
1227 Position::zero(),
1228 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1231 event_time_i64,
1232 );
1233 let third_report = testing_utilities::create_mouse_input_report_relative(
1234 Position::zero(),
1235 None, None, vec![SECONDARY_BUTTON],
1238 event_time_i64,
1239 );
1240 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1241 Position::zero(),
1242 None, None, vec![],
1245 event_time_i64,
1246 );
1247 let descriptor = mouse_device_descriptor(DEVICE_ID);
1248
1249 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1250 let expected_events = vec![
1251 testing_utilities::create_mouse_event(
1252 MouseLocation::Relative(Default::default()),
1253 None, None, None, MousePhase::Down,
1257 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1258 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1259 event_time_u64,
1260 &descriptor,
1261 ),
1262 testing_utilities::create_mouse_event(
1263 MouseLocation::Relative(Default::default()),
1264 None, None, None, MousePhase::Down,
1268 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1269 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1270 event_time_u64,
1271 &descriptor,
1272 ),
1273 testing_utilities::create_mouse_event(
1274 MouseLocation::Relative(Default::default()),
1275 None, None, None, MousePhase::Up,
1279 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1280 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1281 event_time_u64,
1282 &descriptor,
1283 ),
1284 testing_utilities::create_mouse_event(
1285 MouseLocation::Relative(Default::default()),
1286 None, None, None, MousePhase::Up,
1290 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1291 HashSet::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 scroll() {
1308 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1309 let first_report = testing_utilities::create_mouse_input_report_relative(
1310 Position::zero(),
1311 Some(1),
1312 None,
1313 vec![],
1314 event_time_i64,
1315 );
1316 let second_report = testing_utilities::create_mouse_input_report_relative(
1317 Position::zero(),
1318 None,
1319 Some(1),
1320 vec![],
1321 event_time_i64,
1322 );
1323
1324 let descriptor = mouse_device_descriptor(DEVICE_ID);
1325
1326 let input_reports = vec![first_report, second_report];
1327 let expected_events = vec![
1328 testing_utilities::create_mouse_event(
1329 MouseLocation::Relative(Default::default()),
1330 wheel_delta_ticks(1),
1331 None,
1332 Some(PrecisionScroll::No),
1333 MousePhase::Wheel,
1334 HashSet::new(),
1335 HashSet::new(),
1336 event_time_u64,
1337 &descriptor,
1338 ),
1339 testing_utilities::create_mouse_event(
1340 MouseLocation::Relative(Default::default()),
1341 None,
1342 wheel_delta_ticks(1),
1343 Some(PrecisionScroll::No),
1344 MousePhase::Wheel,
1345 HashSet::new(),
1346 HashSet::new(),
1347 event_time_u64,
1348 &descriptor,
1349 ),
1350 ];
1351
1352 assert_input_report_sequence_generates_events!(
1353 input_reports: input_reports,
1354 expected_events: expected_events,
1355 device_descriptor: descriptor,
1356 device_type: MouseBinding,
1357 );
1358 }
1359
1360 #[fasync::run_singlethreaded(test)]
1362 async fn down_scroll_up_scroll() {
1363 const PRIMARY_BUTTON: u8 = 1;
1364
1365 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1366 let first_report = testing_utilities::create_mouse_input_report_relative(
1367 Position::zero(),
1368 None, None, vec![PRIMARY_BUTTON],
1371 event_time_i64,
1372 );
1373 let second_report = testing_utilities::create_mouse_input_report_relative(
1374 Position::zero(),
1375 Some(1),
1376 None,
1377 vec![PRIMARY_BUTTON],
1378 event_time_i64,
1379 );
1380 let third_report = testing_utilities::create_mouse_input_report_relative(
1381 Position::zero(),
1382 None, None, vec![],
1385 event_time_i64,
1386 );
1387 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1388 Position::zero(),
1389 Some(1),
1390 None,
1391 vec![],
1392 event_time_i64,
1393 );
1394
1395 let descriptor = mouse_device_descriptor(DEVICE_ID);
1396
1397 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1398 let expected_events = vec![
1399 testing_utilities::create_mouse_event(
1400 MouseLocation::Relative(Default::default()),
1401 None, None, None, MousePhase::Down,
1405 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1406 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1407 event_time_u64,
1408 &descriptor,
1409 ),
1410 testing_utilities::create_mouse_event(
1411 MouseLocation::Relative(Default::default()),
1412 wheel_delta_ticks(1),
1413 None,
1414 Some(PrecisionScroll::No),
1415 MousePhase::Wheel,
1416 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1417 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1418 event_time_u64,
1419 &descriptor,
1420 ),
1421 testing_utilities::create_mouse_event(
1422 MouseLocation::Relative(Default::default()),
1423 None, None, None, MousePhase::Up,
1427 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1428 HashSet::new(),
1429 event_time_u64,
1430 &descriptor,
1431 ),
1432 testing_utilities::create_mouse_event(
1433 MouseLocation::Relative(Default::default()),
1434 wheel_delta_ticks(1),
1435 None,
1436 Some(PrecisionScroll::No),
1437 MousePhase::Wheel,
1438 HashSet::new(),
1439 HashSet::new(),
1440 event_time_u64,
1441 &descriptor,
1442 ),
1443 ];
1444
1445 assert_input_report_sequence_generates_events!(
1446 input_reports: input_reports,
1447 expected_events: expected_events,
1448 device_descriptor: descriptor,
1449 device_type: MouseBinding,
1450 );
1451 }
1452
1453 #[fasync::run_singlethreaded(test)]
1455 async fn down_scroll_bundle_up_scroll_bundle() {
1456 const PRIMARY_BUTTON: u8 = 1;
1457
1458 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1459 let first_report = testing_utilities::create_mouse_input_report_relative(
1460 Position::zero(),
1461 Some(1),
1462 None,
1463 vec![PRIMARY_BUTTON],
1464 event_time_i64,
1465 );
1466 let second_report = testing_utilities::create_mouse_input_report_relative(
1467 Position::zero(),
1468 Some(1),
1469 None,
1470 vec![],
1471 event_time_i64,
1472 );
1473 let third_report = testing_utilities::create_mouse_input_report_relative(
1474 Position::zero(),
1475 Some(1),
1476 None,
1477 vec![],
1478 event_time_i64,
1479 );
1480
1481 let descriptor = mouse_device_descriptor(DEVICE_ID);
1482
1483 let input_reports = vec![first_report, second_report, third_report];
1484 let expected_events = vec![
1485 testing_utilities::create_mouse_event(
1486 MouseLocation::Relative(Default::default()),
1487 None, None, None, MousePhase::Down,
1491 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1492 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1493 event_time_u64,
1494 &descriptor,
1495 ),
1496 testing_utilities::create_mouse_event(
1497 MouseLocation::Relative(Default::default()),
1498 wheel_delta_ticks(1),
1499 None,
1500 Some(PrecisionScroll::No),
1501 MousePhase::Wheel,
1502 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1503 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1504 event_time_u64,
1505 &descriptor,
1506 ),
1507 testing_utilities::create_mouse_event(
1508 MouseLocation::Relative(Default::default()),
1509 wheel_delta_ticks(1),
1510 None,
1511 Some(PrecisionScroll::No),
1512 MousePhase::Wheel,
1513 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1514 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1515 event_time_u64,
1516 &descriptor,
1517 ),
1518 testing_utilities::create_mouse_event(
1519 MouseLocation::Relative(Default::default()),
1520 None, None, None, MousePhase::Up,
1524 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1525 HashSet::new(),
1526 event_time_u64,
1527 &descriptor,
1528 ),
1529 testing_utilities::create_mouse_event(
1530 MouseLocation::Relative(Default::default()),
1531 wheel_delta_ticks(1),
1532 None,
1533 Some(PrecisionScroll::No),
1534 MousePhase::Wheel,
1535 HashSet::new(),
1536 HashSet::new(),
1537 event_time_u64,
1538 &descriptor,
1539 ),
1540 ];
1541
1542 assert_input_report_sequence_generates_events!(
1543 input_reports: input_reports,
1544 expected_events: expected_events,
1545 device_descriptor: descriptor,
1546 device_type: MouseBinding,
1547 );
1548 }
1549}