1use crate::input_device::{self, Handled, InputDeviceBinding, InputDeviceStatus, InputEvent};
6use crate::utils::Position;
7use crate::{metrics, mouse_model_database};
8use anyhow::{Error, format_err};
9use async_trait::async_trait;
10use fidl::HandleBased;
11use fidl_fuchsia_input_report as fidl_input_report;
12use fidl_fuchsia_input_report::{InputDeviceProxy, InputReport};
13use fuchsia_inspect::ArrayProperty;
14use fuchsia_inspect::health::Reporter;
15use fuchsia_sync::Mutex;
16use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
17use metrics_registry::*;
18use std::collections::HashSet;
19use zx;
20
21pub type MouseButton = u8;
22
23#[derive(Copy, Clone, Debug, PartialEq)]
25pub enum PrecisionScroll {
26 Yes,
28 No,
30}
31
32#[derive(Copy, Clone, Debug, PartialEq)]
34pub enum MouseLocation {
35 Relative(RelativeLocation),
37
38 Absolute(Position),
40}
41
42#[derive(Copy, Clone, Debug, PartialEq)]
43pub enum MousePhase {
44 Down, Move, Up, Wheel, }
49
50#[derive(Copy, Clone, Debug, PartialEq)]
52pub struct RelativeLocation {
53 pub millimeters: Position,
55}
56
57impl Default for RelativeLocation {
58 fn default() -> Self {
59 RelativeLocation { millimeters: Position::zero() }
60 }
61}
62
63#[derive(Clone, Debug, PartialEq)]
65pub enum RawWheelDelta {
66 Ticks(i64),
68 Millimeters(f32),
70}
71
72#[derive(Clone, Debug, PartialEq)]
75
76pub struct WheelDelta {
77 pub raw_data: RawWheelDelta,
78 pub physical_pixel: Option<f32>,
79}
80
81#[derive(Debug)]
102pub struct MouseEvent {
103 pub location: MouseLocation,
105
106 pub wheel_delta_v: Option<WheelDelta>,
108
109 pub wheel_delta_h: Option<WheelDelta>,
111
112 pub is_precision_scroll: Option<PrecisionScroll>,
114
115 pub phase: MousePhase,
117
118 pub affected_buttons: HashSet<MouseButton>,
120
121 pub pressed_buttons: HashSet<MouseButton>,
123
124 pub wake_lease: Mutex<Option<zx::EventPair>>,
126}
127
128impl Clone for MouseEvent {
129 fn clone(&self) -> Self {
130 log::debug!("MouseEvent cloned without wake lease.");
131 Self {
132 location: self.location,
133 wheel_delta_v: self.wheel_delta_v.clone(),
134 wheel_delta_h: self.wheel_delta_h.clone(),
135 is_precision_scroll: self.is_precision_scroll,
136 phase: self.phase,
137 affected_buttons: self.affected_buttons.clone(),
138 pressed_buttons: self.pressed_buttons.clone(),
139 wake_lease: None.into(),
140 }
141 }
142}
143
144impl PartialEq for MouseEvent {
145 fn eq(&self, other: &Self) -> bool {
146 self.location == other.location
147 && self.wheel_delta_v == other.wheel_delta_v
148 && self.wheel_delta_h == other.wheel_delta_h
149 && self.is_precision_scroll == other.is_precision_scroll
150 && self.phase == other.phase
151 && self.affected_buttons == other.affected_buttons
152 && self.pressed_buttons == other.pressed_buttons
153 }
154}
155
156impl MouseEvent {
157 pub fn new(
165 location: MouseLocation,
166 wheel_delta_v: Option<WheelDelta>,
167 wheel_delta_h: Option<WheelDelta>,
168 phase: MousePhase,
169 affected_buttons: HashSet<MouseButton>,
170 pressed_buttons: HashSet<MouseButton>,
171 is_precision_scroll: Option<PrecisionScroll>,
172 wake_lease: Option<zx::EventPair>,
173 ) -> MouseEvent {
174 MouseEvent {
175 location,
176 wheel_delta_v,
177 wheel_delta_h,
178 phase,
179 affected_buttons,
180 pressed_buttons,
181 is_precision_scroll,
182 wake_lease: Mutex::new(wake_lease),
183 }
184 }
185
186 pub fn clone_with_wake_lease(&self) -> Self {
187 log::debug!("MouseEvent cloned with wake lease: {:?}", self.wake_lease);
188 Self {
189 location: self.location,
190 wheel_delta_v: self.wheel_delta_v.clone(),
191 wheel_delta_h: self.wheel_delta_h.clone(),
192 is_precision_scroll: self.is_precision_scroll,
193 phase: self.phase,
194 affected_buttons: self.affected_buttons.clone(),
195 pressed_buttons: self.pressed_buttons.clone(),
196 wake_lease: Mutex::new(self.wake_lease.lock().as_ref().map(|lease| {
197 lease
198 .duplicate_handle(zx::Rights::SAME_RIGHTS)
199 .expect("failed to duplicate event pair")
200 })),
201 }
202 }
203
204 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
205 match self.location {
206 MouseLocation::Relative(pos) => {
207 node.record_child("location_relative", move |location_node| {
208 location_node.record_double("x", f64::from(pos.millimeters.x));
209 location_node.record_double("y", f64::from(pos.millimeters.y));
210 })
211 }
212 MouseLocation::Absolute(pos) => {
213 node.record_child("location_absolute", move |location_node| {
214 location_node.record_double("x", f64::from(pos.x));
215 location_node.record_double("y", f64::from(pos.y));
216 })
217 }
218 };
219
220 if let Some(wheel_delta_v) = &self.wheel_delta_v {
221 node.record_child("wheel_delta_v", move |wheel_delta_v_node| {
222 match wheel_delta_v.raw_data {
223 RawWheelDelta::Ticks(ticks) => wheel_delta_v_node.record_int("ticks", ticks),
224 RawWheelDelta::Millimeters(mm) => {
225 wheel_delta_v_node.record_double("millimeters", f64::from(mm))
226 }
227 }
228 if let Some(physical_pixel) = wheel_delta_v.physical_pixel {
229 wheel_delta_v_node.record_double("physical_pixel", f64::from(physical_pixel));
230 }
231 });
232 }
233
234 if let Some(wheel_delta_h) = &self.wheel_delta_h {
235 node.record_child("wheel_delta_h", move |wheel_delta_h_node| {
236 match wheel_delta_h.raw_data {
237 RawWheelDelta::Ticks(ticks) => wheel_delta_h_node.record_int("ticks", ticks),
238 RawWheelDelta::Millimeters(mm) => {
239 wheel_delta_h_node.record_double("millimeters", f64::from(mm))
240 }
241 }
242 if let Some(physical_pixel) = wheel_delta_h.physical_pixel {
243 wheel_delta_h_node.record_double("physical_pixel", f64::from(physical_pixel));
244 }
245 });
246 }
247
248 if let Some(is_precision_scroll) = self.is_precision_scroll {
249 match is_precision_scroll {
250 PrecisionScroll::Yes => node.record_string("is_precision_scroll", "yes"),
251 PrecisionScroll::No => node.record_string("is_precision_scroll", "no"),
252 }
253 }
254
255 match self.phase {
256 MousePhase::Down => node.record_string("phase", "down"),
257 MousePhase::Move => node.record_string("phase", "move"),
258 MousePhase::Up => node.record_string("phase", "up"),
259 MousePhase::Wheel => node.record_string("phase", "wheel"),
260 }
261
262 let affected_buttons_node =
263 node.create_uint_array("affected_buttons", self.affected_buttons.len());
264 self.affected_buttons.iter().enumerate().for_each(|(i, button)| {
265 affected_buttons_node.set(i, *button);
266 });
267 node.record(affected_buttons_node);
268
269 let pressed_buttons_node =
270 node.create_uint_array("pressed_buttons", self.pressed_buttons.len());
271 self.pressed_buttons.iter().enumerate().for_each(|(i, button)| {
272 pressed_buttons_node.set(i, *button);
273 });
274 node.record(pressed_buttons_node);
275 }
276}
277
278pub struct MouseBinding {
284 event_sender: UnboundedSender<Vec<InputEvent>>,
286
287 device_descriptor: MouseDeviceDescriptor,
289}
290
291#[derive(Clone, Debug, Eq, PartialEq)]
292pub struct MouseDeviceDescriptor {
293 pub device_id: u32,
295
296 pub absolute_x_range: Option<fidl_input_report::Range>,
298
299 pub absolute_y_range: Option<fidl_input_report::Range>,
301
302 pub wheel_v_range: Option<fidl_input_report::Axis>,
304
305 pub wheel_h_range: Option<fidl_input_report::Axis>,
307
308 pub buttons: Option<Vec<MouseButton>>,
310
311 pub counts_per_mm: u32,
314}
315
316#[async_trait]
317impl input_device::InputDeviceBinding for MouseBinding {
318 fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>> {
319 self.event_sender.clone()
320 }
321
322 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
323 input_device::InputDeviceDescriptor::Mouse(self.device_descriptor.clone())
324 }
325}
326
327impl MouseBinding {
328 pub async fn new(
343 device_proxy: InputDeviceProxy,
344 device_id: u32,
345 input_event_sender: UnboundedSender<Vec<InputEvent>>,
346 device_node: fuchsia_inspect::Node,
347 _feature_flags: input_device::InputPipelineFeatureFlags,
348 metrics_logger: metrics::MetricsLogger,
349 ) -> Result<Self, Error> {
350 let (device_binding, mut inspect_status) =
351 Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
352 inspect_status.health_node.set_ok();
353 input_device::initialize_report_stream(
354 device_proxy,
355 device_binding.get_device_descriptor(),
356 device_binding.input_event_sender(),
357 inspect_status,
358 metrics_logger,
359 _feature_flags,
360 Self::process_reports,
361 );
362
363 Ok(device_binding)
364 }
365
366 async fn bind_device(
378 device: &InputDeviceProxy,
379 device_id: u32,
380 input_event_sender: UnboundedSender<Vec<InputEvent>>,
381 device_node: fuchsia_inspect::Node,
382 ) -> Result<(Self, InputDeviceStatus), Error> {
383 let mut input_device_status = InputDeviceStatus::new(device_node);
384 let device_descriptor: fidl_input_report::DeviceDescriptor = match device
385 .get_descriptor()
386 .await
387 {
388 Ok(descriptor) => descriptor,
389 Err(_) => {
390 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
391 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
392 }
393 };
394
395 let mouse_descriptor = device_descriptor.mouse.ok_or_else(|| {
396 input_device_status
397 .health_node
398 .set_unhealthy("DeviceDescriptor does not have a MouseDescriptor.");
399 format_err!("DeviceDescriptor does not have a MouseDescriptor")
400 })?;
401
402 let mouse_input_descriptor = mouse_descriptor.input.ok_or_else(|| {
403 input_device_status
404 .health_node
405 .set_unhealthy("MouseDescriptor does not have a MouseInputDescriptor.");
406 format_err!("MouseDescriptor does not have a MouseInputDescriptor")
407 })?;
408
409 let model = mouse_model_database::db::get_mouse_model(device_descriptor.device_information);
410
411 let device_descriptor: MouseDeviceDescriptor = MouseDeviceDescriptor {
412 device_id,
413 absolute_x_range: mouse_input_descriptor.position_x.map(|axis| axis.range),
414 absolute_y_range: mouse_input_descriptor.position_y.map(|axis| axis.range),
415 wheel_v_range: mouse_input_descriptor.scroll_v,
416 wheel_h_range: mouse_input_descriptor.scroll_h,
417 buttons: mouse_input_descriptor.buttons,
418 counts_per_mm: model.counts_per_mm,
419 };
420
421 Ok((
422 MouseBinding { event_sender: input_event_sender, device_descriptor },
423 input_device_status,
424 ))
425 }
426
427 fn process_reports(
449 reports: Vec<InputReport>,
450 mut previous_report: Option<InputReport>,
451 device_descriptor: &input_device::InputDeviceDescriptor,
452 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
453 inspect_status: &InputDeviceStatus,
454 metrics_logger: &metrics::MetricsLogger,
455 _feature_flags: &input_device::InputPipelineFeatureFlags,
456 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
457 fuchsia_trace::duration!("input", "mouse-binding-process-reports", "num_reports" => reports.len());
458 for report in reports {
459 previous_report = Self::process_report(
460 report,
461 previous_report,
462 device_descriptor,
463 input_event_sender,
464 inspect_status,
465 metrics_logger,
466 );
467 }
468 (previous_report, None)
469 }
470
471 fn process_report(
472 mut report: InputReport,
473 previous_report: Option<InputReport>,
474 device_descriptor: &input_device::InputDeviceDescriptor,
475 input_event_sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
476 inspect_status: &InputDeviceStatus,
477 metrics_logger: &metrics::MetricsLogger,
478 ) -> Option<InputReport> {
479 if let Some(trace_id) = report.trace_id {
480 fuchsia_trace::flow_end!("input", "input_report", trace_id.into());
481 }
482
483 let wake_lease = report.wake_lease.take();
487
488 inspect_status.count_received_report(&report);
489 let mouse_report: &fidl_input_report::MouseInputReport = match &report.mouse {
491 Some(mouse) => mouse,
492 None => {
493 inspect_status.count_filtered_report();
494 return previous_report;
495 }
496 };
497
498 let previous_buttons: HashSet<MouseButton> =
499 buttons_from_optional_report(&previous_report.as_ref());
500 let current_buttons: HashSet<MouseButton> = buttons_from_report(&report);
501
502 send_mouse_event(
508 MouseLocation::Relative(Default::default()),
509 None, None, MousePhase::Down,
512 current_buttons.difference(&previous_buttons).cloned().collect(),
513 current_buttons.clone(),
514 device_descriptor,
515 input_event_sender,
516 inspect_status,
517 metrics_logger,
518 wake_lease.as_ref().map(|lease| {
519 lease
520 .duplicate_handle(zx::Rights::SAME_RIGHTS)
521 .expect("failed to duplicate event pair")
522 }),
523 );
524
525 let counts_per_mm = match device_descriptor {
526 input_device::InputDeviceDescriptor::Mouse(ds) => ds.counts_per_mm,
527 _ => {
528 metrics_logger.log_error(
529 InputPipelineErrorMetricDimensionEvent::MouseDescriptionNotMouse,
530 "mouse_binding::process_reports got device_descriptor not mouse".to_string(),
531 );
532 mouse_model_database::db::DEFAULT_COUNTS_PER_MM
533 }
534 };
535
536 let location = if let (Some(position_x), Some(position_y)) =
538 (mouse_report.position_x, mouse_report.position_y)
539 {
540 MouseLocation::Absolute(Position { x: position_x as f32, y: position_y as f32 })
541 } else {
542 let movement_x = mouse_report.movement_x.unwrap_or_default() as f32;
543 let movement_y = mouse_report.movement_y.unwrap_or_default() as f32;
544 MouseLocation::Relative(RelativeLocation {
545 millimeters: Position {
546 x: movement_x / counts_per_mm as f32,
547 y: movement_y / counts_per_mm as f32,
548 },
549 })
550 };
551
552 send_mouse_event(
556 location,
557 None, None, MousePhase::Move,
560 current_buttons.union(&previous_buttons).cloned().collect(),
561 current_buttons.union(&previous_buttons).cloned().collect(),
562 device_descriptor,
563 input_event_sender,
564 inspect_status,
565 metrics_logger,
566 wake_lease.as_ref().map(|lease| {
567 lease
568 .duplicate_handle(zx::Rights::SAME_RIGHTS)
569 .expect("failed to duplicate event pair")
570 }),
571 );
572
573 let wheel_delta_v = match mouse_report.scroll_v {
574 None => None,
575 Some(ticks) => {
576 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
577 }
578 };
579
580 let wheel_delta_h = match mouse_report.scroll_h {
581 None => None,
582 Some(ticks) => {
583 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
584 }
585 };
586
587 send_mouse_event(
589 MouseLocation::Relative(Default::default()),
590 wheel_delta_v,
591 wheel_delta_h,
592 MousePhase::Wheel,
593 current_buttons.union(&previous_buttons).cloned().collect(),
594 current_buttons.union(&previous_buttons).cloned().collect(),
595 device_descriptor,
596 input_event_sender,
597 inspect_status,
598 metrics_logger,
599 wake_lease.as_ref().map(|lease| {
600 lease
601 .duplicate_handle(zx::Rights::SAME_RIGHTS)
602 .expect("failed to duplicate event pair")
603 }),
604 );
605
606 send_mouse_event(
612 MouseLocation::Relative(Default::default()),
613 None, None, MousePhase::Up,
616 previous_buttons.difference(¤t_buttons).cloned().collect(),
617 current_buttons.clone(),
618 device_descriptor,
619 input_event_sender,
620 inspect_status,
621 metrics_logger,
622 wake_lease,
623 );
624
625 Some(report)
626 }
627}
628
629fn send_mouse_event(
644 location: MouseLocation,
645 wheel_delta_v: Option<WheelDelta>,
646 wheel_delta_h: Option<WheelDelta>,
647 phase: MousePhase,
648 affected_buttons: HashSet<MouseButton>,
649 pressed_buttons: HashSet<MouseButton>,
650 device_descriptor: &input_device::InputDeviceDescriptor,
651 sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
652 inspect_status: &InputDeviceStatus,
653 metrics_logger: &metrics::MetricsLogger,
654 wake_lease: Option<zx::EventPair>,
655) {
656 if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
658 return;
659 }
660
661 if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
664 return;
665 }
666
667 if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
669 return;
670 }
671
672 let trace_id = fuchsia_trace::Id::random();
673 fuchsia_trace::duration!("input", "mouse-binding-send-event");
674 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
675
676 let event = input_device::InputEvent {
677 device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
678 location,
679 wheel_delta_v,
680 wheel_delta_h,
681 phase,
682 affected_buttons,
683 pressed_buttons,
684 match phase {
685 MousePhase::Wheel => Some(PrecisionScroll::No),
686 _ => None,
687 },
688 wake_lease,
689 )),
690 device_descriptor: device_descriptor.clone(),
691 event_time: zx::MonotonicInstant::get(),
692 handled: Handled::No,
693 trace_id: Some(trace_id),
694 };
695 let events = vec![event.clone_with_wake_lease()];
696
697 match sender.unbounded_send(events.clone()) {
698 Err(e) => {
699 metrics_logger.log_error(
700 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
701 std::format!("Failed to send MouseEvent with error: {:?}", e),
702 );
703 }
704 _ => inspect_status.count_generated_events(&events),
705 }
706}
707
708pub fn get_u32_from_buttons(buttons: &HashSet<MouseButton>) -> u32 {
722 let mut bits: u32 = 0;
723 for button in buttons {
724 if *button > 0 && *button <= fidl_input_report::MOUSE_MAX_NUM_BUTTONS as u8 {
725 bits = ((1 as u32) << *button - 1) | bits;
726 }
727 }
728
729 bits
730}
731
732fn buttons_from_report(input_report: &fidl_input_report::InputReport) -> HashSet<MouseButton> {
737 buttons_from_optional_report(&Some(input_report))
738}
739
740fn buttons_from_optional_report(
745 input_report: &Option<&fidl_input_report::InputReport>,
746) -> HashSet<MouseButton> {
747 input_report
748 .as_ref()
749 .and_then(|unwrapped_report| unwrapped_report.mouse.as_ref())
750 .and_then(|mouse_report| match &mouse_report.pressed_buttons {
751 Some(buttons) => Some(HashSet::from_iter(buttons.iter().cloned())),
752 None => None,
753 })
754 .unwrap_or_default()
755}
756
757#[cfg(test)]
758mod tests {
759 use super::*;
760 use crate::testing_utilities;
761 use fuchsia_async as fasync;
762 use futures::StreamExt;
763 use pretty_assertions::assert_eq;
764
765 const DEVICE_ID: u32 = 1;
766 const COUNTS_PER_MM: u32 = 12;
767
768 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
769 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
770 device_id,
771 absolute_x_range: None,
772 absolute_y_range: None,
773 wheel_v_range: Some(fidl_fuchsia_input_report::Axis {
774 range: fidl_input_report::Range { min: -1, max: 1 },
775 unit: fidl_input_report::Unit {
776 type_: fidl_input_report::UnitType::Other,
777 exponent: 1,
778 },
779 }),
780 wheel_h_range: Some(fidl_fuchsia_input_report::Axis {
781 range: fidl_input_report::Range { min: -1, max: 1 },
782 unit: fidl_input_report::Unit {
783 type_: fidl_input_report::UnitType::Other,
784 exponent: 1,
785 },
786 }),
787 buttons: None,
788 counts_per_mm: COUNTS_PER_MM,
789 })
790 }
791
792 fn wheel_delta_ticks(delta: i64) -> Option<WheelDelta> {
793 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(delta), physical_pixel: None })
794 }
795
796 #[test]
798 fn get_u32_from_buttons_test() {
799 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, 5].into_iter()));
800 assert_eq!(bits, 21 )
801 }
802
803 #[test]
805 fn get_u32_with_0_in_vector() {
806 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![0, 1, 3].into_iter()));
807 assert_eq!(bits, 5 )
808 }
809
810 #[test]
812 fn get_u32_with_empty_vector() {
813 let bits = get_u32_from_buttons(&HashSet::new());
814 assert_eq!(bits, 0 )
815 }
816
817 #[test]
819 fn get_u32_with_u8_max_in_vector() {
820 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, std::u8::MAX].into_iter()));
821 assert_eq!(bits, 5 )
822 }
823
824 #[test]
827 fn get_u32_with_max_mouse_buttons() {
828 let bits = get_u32_from_buttons(&HashSet::from_iter(
829 vec![1, 3, fidl_input_report::MOUSE_MAX_NUM_BUTTONS as MouseButton].into_iter(),
830 ));
831 assert_eq!(bits, 2147483653 )
832 }
833
834 #[fasync::run_singlethreaded(test)]
836 async fn movement_without_button() {
837 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
838 let first_report = testing_utilities::create_mouse_input_report_relative(
839 Position { x: 10.0, y: 16.0 },
840 None, None, vec![],
843 event_time_i64,
844 );
845 let descriptor = mouse_device_descriptor(DEVICE_ID);
846
847 let input_reports = vec![first_report];
848 let expected_events = vec![testing_utilities::create_mouse_event(
849 MouseLocation::Relative(RelativeLocation {
850 millimeters: Position {
851 x: 10.0 / COUNTS_PER_MM as f32,
852 y: 16.0 / COUNTS_PER_MM as f32,
853 },
854 }),
855 None, None, None, MousePhase::Move,
859 HashSet::new(),
860 HashSet::new(),
861 event_time_u64,
862 &descriptor,
863 )];
864
865 assert_input_report_sequence_generates_events!(
866 input_reports: input_reports,
867 expected_events: expected_events,
868 device_descriptor: descriptor,
869 device_type: MouseBinding,
870 );
871 }
872
873 #[fasync::run_singlethreaded(test)]
875 async fn down_without_movement() {
876 let mouse_button: MouseButton = 3;
877 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
878 let first_report = testing_utilities::create_mouse_input_report_relative(
879 Position::zero(),
880 None, None, vec![mouse_button],
883 event_time_i64,
884 );
885 let descriptor = mouse_device_descriptor(DEVICE_ID);
886
887 let input_reports = vec![first_report];
888 let expected_events = vec![testing_utilities::create_mouse_event(
889 MouseLocation::Relative(Default::default()),
890 None, None, None, MousePhase::Down,
894 HashSet::from_iter(vec![mouse_button].into_iter()),
895 HashSet::from_iter(vec![mouse_button].into_iter()),
896 event_time_u64,
897 &descriptor,
898 )];
899
900 assert_input_report_sequence_generates_events!(
901 input_reports: input_reports,
902 expected_events: expected_events,
903 device_descriptor: descriptor,
904 device_type: MouseBinding,
905 );
906 }
907
908 #[fasync::run_singlethreaded(test)]
911 async fn down_with_movement() {
912 let mouse_button: MouseButton = 3;
913 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
914 let first_report = testing_utilities::create_mouse_input_report_relative(
915 Position { x: 10.0, y: 16.0 },
916 None, None, vec![mouse_button],
919 event_time_i64,
920 );
921 let descriptor = mouse_device_descriptor(DEVICE_ID);
922
923 let input_reports = vec![first_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![mouse_button].into_iter()),
932 HashSet::from_iter(vec![mouse_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![mouse_button].into_iter()),
948 HashSet::from_iter(vec![mouse_button].into_iter()),
949 event_time_u64,
950 &descriptor,
951 ),
952 ];
953
954 assert_input_report_sequence_generates_events!(
955 input_reports: input_reports,
956 expected_events: expected_events,
957 device_descriptor: descriptor,
958 device_type: MouseBinding,
959 );
960 }
961
962 #[fasync::run_singlethreaded(test)]
964 async fn down_up() {
965 let button = 1;
966 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
967 let first_report = testing_utilities::create_mouse_input_report_relative(
968 Position::zero(),
969 None, None, vec![button],
972 event_time_i64,
973 );
974 let second_report = testing_utilities::create_mouse_input_report_relative(
975 Position::zero(),
976 None, None, vec![],
979 event_time_i64,
980 );
981 let descriptor = mouse_device_descriptor(DEVICE_ID);
982
983 let input_reports = vec![first_report, second_report];
984 let expected_events = vec![
985 testing_utilities::create_mouse_event(
986 MouseLocation::Relative(Default::default()),
987 None, None, None, MousePhase::Down,
991 HashSet::from_iter(vec![button].into_iter()),
992 HashSet::from_iter(vec![button].into_iter()),
993 event_time_u64,
994 &descriptor,
995 ),
996 testing_utilities::create_mouse_event(
997 MouseLocation::Relative(Default::default()),
998 None, None, None, MousePhase::Up,
1002 HashSet::from_iter(vec![button].into_iter()),
1003 HashSet::new(),
1004 event_time_u64,
1005 &descriptor,
1006 ),
1007 ];
1008
1009 assert_input_report_sequence_generates_events!(
1010 input_reports: input_reports,
1011 expected_events: expected_events,
1012 device_descriptor: descriptor,
1013 device_type: MouseBinding,
1014 );
1015 }
1016
1017 #[fasync::run_singlethreaded(test)]
1019 async fn down_up_with_movement() {
1020 let button = 1;
1021
1022 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1023 let first_report = testing_utilities::create_mouse_input_report_relative(
1024 Position::zero(),
1025 None, None, vec![button],
1028 event_time_i64,
1029 );
1030 let second_report = testing_utilities::create_mouse_input_report_relative(
1031 Position { x: 10.0, y: 16.0 },
1032 None, None, vec![],
1035 event_time_i64,
1036 );
1037 let descriptor = mouse_device_descriptor(DEVICE_ID);
1038
1039 let input_reports = vec![first_report, second_report];
1040 let expected_events = vec![
1041 testing_utilities::create_mouse_event(
1042 MouseLocation::Relative(Default::default()),
1043 None, None, None, MousePhase::Down,
1047 HashSet::from_iter(vec![button].into_iter()),
1048 HashSet::from_iter(vec![button].into_iter()),
1049 event_time_u64,
1050 &descriptor,
1051 ),
1052 testing_utilities::create_mouse_event(
1053 MouseLocation::Relative(RelativeLocation {
1054 millimeters: Position {
1055 x: 10.0 / COUNTS_PER_MM as f32,
1056 y: 16.0 / COUNTS_PER_MM as f32,
1057 },
1058 }),
1059 None, None, None, MousePhase::Move,
1063 HashSet::from_iter(vec![button].into_iter()),
1064 HashSet::from_iter(vec![button].into_iter()),
1065 event_time_u64,
1066 &descriptor,
1067 ),
1068 testing_utilities::create_mouse_event(
1069 MouseLocation::Relative(Default::default()),
1070 None, None, None, MousePhase::Up,
1074 HashSet::from_iter(vec![button].into_iter()),
1075 HashSet::new(),
1076 event_time_u64,
1077 &descriptor,
1078 ),
1079 ];
1080
1081 assert_input_report_sequence_generates_events!(
1082 input_reports: input_reports,
1083 expected_events: expected_events,
1084 device_descriptor: descriptor,
1085 device_type: MouseBinding,
1086 );
1087 }
1088
1089 #[fasync::run_singlethreaded(test)]
1093 async fn down_move_up() {
1094 let button = 1;
1095
1096 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1097 let first_report = testing_utilities::create_mouse_input_report_relative(
1098 Position::zero(),
1099 None, None, vec![button],
1102 event_time_i64,
1103 );
1104 let second_report = testing_utilities::create_mouse_input_report_relative(
1105 Position { x: 10.0, y: 16.0 },
1106 None, None, vec![button],
1109 event_time_i64,
1110 );
1111 let third_report = testing_utilities::create_mouse_input_report_relative(
1112 Position::zero(),
1113 None, None, vec![],
1116 event_time_i64,
1117 );
1118 let descriptor = mouse_device_descriptor(DEVICE_ID);
1119
1120 let input_reports = vec![first_report, second_report, third_report];
1121 let expected_events = vec![
1122 testing_utilities::create_mouse_event(
1123 MouseLocation::Relative(Default::default()),
1124 None, None, None, MousePhase::Down,
1128 HashSet::from_iter(vec![button].into_iter()),
1129 HashSet::from_iter(vec![button].into_iter()),
1130 event_time_u64,
1131 &descriptor,
1132 ),
1133 testing_utilities::create_mouse_event(
1134 MouseLocation::Relative(RelativeLocation {
1135 millimeters: Position {
1136 x: 10.0 / COUNTS_PER_MM as f32,
1137 y: 16.0 / COUNTS_PER_MM as f32,
1138 },
1139 }),
1140 None, None, None, MousePhase::Move,
1144 HashSet::from_iter(vec![button].into_iter()),
1145 HashSet::from_iter(vec![button].into_iter()),
1146 event_time_u64,
1147 &descriptor,
1148 ),
1149 testing_utilities::create_mouse_event(
1150 MouseLocation::Relative(Default::default()),
1151 None, None, None, MousePhase::Up,
1155 HashSet::from_iter(vec![button].into_iter()),
1156 HashSet::new(),
1157 event_time_u64,
1158 &descriptor,
1159 ),
1160 ];
1161
1162 assert_input_report_sequence_generates_events!(
1163 input_reports: input_reports,
1164 expected_events: expected_events,
1165 device_descriptor: descriptor,
1166 device_type: MouseBinding,
1167 );
1168 }
1169
1170 #[fasync::run_until_stalled(test)]
1172 async fn absolute_movement_to_origin() {
1173 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1174 let descriptor = mouse_device_descriptor(DEVICE_ID);
1175
1176 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
1177 Position::zero(),
1178 None, None, vec![],
1181 event_time_i64,
1182 )];
1183 let expected_events = vec![testing_utilities::create_mouse_event(
1184 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1185 None, None, None, MousePhase::Move,
1189 HashSet::new(),
1190 HashSet::new(),
1191 event_time_u64,
1192 &descriptor,
1193 )];
1194
1195 assert_input_report_sequence_generates_events!(
1196 input_reports: input_reports,
1197 expected_events: expected_events,
1198 device_descriptor: descriptor,
1199 device_type: MouseBinding,
1200 );
1201 }
1202
1203 #[fasync::run_until_stalled(test)]
1206 async fn report_with_both_movement_and_position() {
1207 let relative_movement = Position { x: 5.0, y: 5.0 };
1208 let absolute_position = Position { x: 10.0, y: 10.0 };
1209 let expected_location = MouseLocation::Absolute(absolute_position);
1210
1211 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1212 let descriptor = mouse_device_descriptor(DEVICE_ID);
1213
1214 let input_reports = vec![fidl_input_report::InputReport {
1215 event_time: Some(event_time_i64),
1216 keyboard: None,
1217 mouse: Some(fidl_input_report::MouseInputReport {
1218 movement_x: Some(relative_movement.x as i64),
1219 movement_y: Some(relative_movement.y as i64),
1220 position_x: Some(absolute_position.x as i64),
1221 position_y: Some(absolute_position.y as i64),
1222 scroll_h: None,
1223 scroll_v: None,
1224 pressed_buttons: None,
1225 ..Default::default()
1226 }),
1227 touch: None,
1228 sensor: None,
1229 consumer_control: None,
1230 trace_id: None,
1231 ..Default::default()
1232 }];
1233 let expected_events = vec![testing_utilities::create_mouse_event(
1234 expected_location,
1235 None, None, None, MousePhase::Move,
1239 HashSet::new(),
1240 HashSet::new(),
1241 event_time_u64,
1242 &descriptor,
1243 )];
1244
1245 assert_input_report_sequence_generates_events!(
1246 input_reports: input_reports,
1247 expected_events: expected_events,
1248 device_descriptor: descriptor,
1249 device_type: MouseBinding,
1250 );
1251 }
1252
1253 #[fasync::run_singlethreaded(test)]
1256 async fn down_down() {
1257 const PRIMARY_BUTTON: u8 = 1;
1258 const SECONDARY_BUTTON: u8 = 2;
1259
1260 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1261 let first_report = testing_utilities::create_mouse_input_report_relative(
1262 Position::zero(),
1263 None, None, vec![PRIMARY_BUTTON],
1266 event_time_i64,
1267 );
1268 let second_report = testing_utilities::create_mouse_input_report_relative(
1269 Position::zero(),
1270 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1273 event_time_i64,
1274 );
1275 let descriptor = mouse_device_descriptor(DEVICE_ID);
1276
1277 let input_reports = vec![first_report, second_report];
1278 let expected_events = vec![
1279 testing_utilities::create_mouse_event(
1280 MouseLocation::Relative(Default::default()),
1281 None, None, None, MousePhase::Down,
1285 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1286 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1287 event_time_u64,
1288 &descriptor,
1289 ),
1290 testing_utilities::create_mouse_event(
1291 MouseLocation::Relative(Default::default()),
1292 None, None, None, MousePhase::Down,
1296 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1297 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1298 event_time_u64,
1299 &descriptor,
1300 ),
1301 ];
1302
1303 assert_input_report_sequence_generates_events!(
1304 input_reports: input_reports,
1305 expected_events: expected_events,
1306 device_descriptor: descriptor,
1307 device_type: MouseBinding,
1308 );
1309 }
1310
1311 #[fasync::run_singlethreaded(test)]
1321 async fn down_down_up_up() {
1322 const PRIMARY_BUTTON: u8 = 1;
1323 const SECONDARY_BUTTON: u8 = 2;
1324
1325 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1326 let first_report = testing_utilities::create_mouse_input_report_relative(
1327 Position::zero(),
1328 None, None, vec![PRIMARY_BUTTON],
1331 event_time_i64,
1332 );
1333 let second_report = testing_utilities::create_mouse_input_report_relative(
1334 Position::zero(),
1335 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1338 event_time_i64,
1339 );
1340 let third_report = testing_utilities::create_mouse_input_report_relative(
1341 Position::zero(),
1342 None, None, vec![SECONDARY_BUTTON],
1345 event_time_i64,
1346 );
1347 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1348 Position::zero(),
1349 None, None, vec![],
1352 event_time_i64,
1353 );
1354 let descriptor = mouse_device_descriptor(DEVICE_ID);
1355
1356 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1357 let expected_events = vec![
1358 testing_utilities::create_mouse_event(
1359 MouseLocation::Relative(Default::default()),
1360 None, None, None, MousePhase::Down,
1364 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1365 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1366 event_time_u64,
1367 &descriptor,
1368 ),
1369 testing_utilities::create_mouse_event(
1370 MouseLocation::Relative(Default::default()),
1371 None, None, None, MousePhase::Down,
1375 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1376 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1377 event_time_u64,
1378 &descriptor,
1379 ),
1380 testing_utilities::create_mouse_event(
1381 MouseLocation::Relative(Default::default()),
1382 None, None, None, MousePhase::Up,
1386 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1387 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1388 event_time_u64,
1389 &descriptor,
1390 ),
1391 testing_utilities::create_mouse_event(
1392 MouseLocation::Relative(Default::default()),
1393 None, None, None, MousePhase::Up,
1397 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1398 HashSet::new(),
1399 event_time_u64,
1400 &descriptor,
1401 ),
1402 ];
1403
1404 assert_input_report_sequence_generates_events!(
1405 input_reports: input_reports,
1406 expected_events: expected_events,
1407 device_descriptor: descriptor,
1408 device_type: MouseBinding,
1409 );
1410 }
1411
1412 #[fasync::run_singlethreaded(test)]
1414 async fn scroll() {
1415 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1416 let first_report = testing_utilities::create_mouse_input_report_relative(
1417 Position::zero(),
1418 Some(1),
1419 None,
1420 vec![],
1421 event_time_i64,
1422 );
1423 let second_report = testing_utilities::create_mouse_input_report_relative(
1424 Position::zero(),
1425 None,
1426 Some(1),
1427 vec![],
1428 event_time_i64,
1429 );
1430
1431 let descriptor = mouse_device_descriptor(DEVICE_ID);
1432
1433 let input_reports = vec![first_report, second_report];
1434 let expected_events = vec![
1435 testing_utilities::create_mouse_event(
1436 MouseLocation::Relative(Default::default()),
1437 wheel_delta_ticks(1),
1438 None,
1439 Some(PrecisionScroll::No),
1440 MousePhase::Wheel,
1441 HashSet::new(),
1442 HashSet::new(),
1443 event_time_u64,
1444 &descriptor,
1445 ),
1446 testing_utilities::create_mouse_event(
1447 MouseLocation::Relative(Default::default()),
1448 None,
1449 wheel_delta_ticks(1),
1450 Some(PrecisionScroll::No),
1451 MousePhase::Wheel,
1452 HashSet::new(),
1453 HashSet::new(),
1454 event_time_u64,
1455 &descriptor,
1456 ),
1457 ];
1458
1459 assert_input_report_sequence_generates_events!(
1460 input_reports: input_reports,
1461 expected_events: expected_events,
1462 device_descriptor: descriptor,
1463 device_type: MouseBinding,
1464 );
1465 }
1466
1467 #[fasync::run_singlethreaded(test)]
1469 async fn down_scroll_up_scroll() {
1470 const PRIMARY_BUTTON: u8 = 1;
1471
1472 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1473 let first_report = testing_utilities::create_mouse_input_report_relative(
1474 Position::zero(),
1475 None, None, vec![PRIMARY_BUTTON],
1478 event_time_i64,
1479 );
1480 let second_report = testing_utilities::create_mouse_input_report_relative(
1481 Position::zero(),
1482 Some(1),
1483 None,
1484 vec![PRIMARY_BUTTON],
1485 event_time_i64,
1486 );
1487 let third_report = testing_utilities::create_mouse_input_report_relative(
1488 Position::zero(),
1489 None, None, vec![],
1492 event_time_i64,
1493 );
1494 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1495 Position::zero(),
1496 Some(1),
1497 None,
1498 vec![],
1499 event_time_i64,
1500 );
1501
1502 let descriptor = mouse_device_descriptor(DEVICE_ID);
1503
1504 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1505 let expected_events = vec![
1506 testing_utilities::create_mouse_event(
1507 MouseLocation::Relative(Default::default()),
1508 None, None, None, MousePhase::Down,
1512 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1513 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1514 event_time_u64,
1515 &descriptor,
1516 ),
1517 testing_utilities::create_mouse_event(
1518 MouseLocation::Relative(Default::default()),
1519 wheel_delta_ticks(1),
1520 None,
1521 Some(PrecisionScroll::No),
1522 MousePhase::Wheel,
1523 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1524 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1525 event_time_u64,
1526 &descriptor,
1527 ),
1528 testing_utilities::create_mouse_event(
1529 MouseLocation::Relative(Default::default()),
1530 None, None, None, MousePhase::Up,
1534 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1535 HashSet::new(),
1536 event_time_u64,
1537 &descriptor,
1538 ),
1539 testing_utilities::create_mouse_event(
1540 MouseLocation::Relative(Default::default()),
1541 wheel_delta_ticks(1),
1542 None,
1543 Some(PrecisionScroll::No),
1544 MousePhase::Wheel,
1545 HashSet::new(),
1546 HashSet::new(),
1547 event_time_u64,
1548 &descriptor,
1549 ),
1550 ];
1551
1552 assert_input_report_sequence_generates_events!(
1553 input_reports: input_reports,
1554 expected_events: expected_events,
1555 device_descriptor: descriptor,
1556 device_type: MouseBinding,
1557 );
1558 }
1559
1560 #[fasync::run_singlethreaded(test)]
1562 async fn down_scroll_bundle_up_scroll_bundle() {
1563 const PRIMARY_BUTTON: u8 = 1;
1564
1565 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1566 let first_report = testing_utilities::create_mouse_input_report_relative(
1567 Position::zero(),
1568 Some(1),
1569 None,
1570 vec![PRIMARY_BUTTON],
1571 event_time_i64,
1572 );
1573 let second_report = testing_utilities::create_mouse_input_report_relative(
1574 Position::zero(),
1575 Some(1),
1576 None,
1577 vec![],
1578 event_time_i64,
1579 );
1580 let third_report = testing_utilities::create_mouse_input_report_relative(
1581 Position::zero(),
1582 Some(1),
1583 None,
1584 vec![],
1585 event_time_i64,
1586 );
1587
1588 let descriptor = mouse_device_descriptor(DEVICE_ID);
1589
1590 let input_reports = vec![first_report, second_report, third_report];
1591 let expected_events = vec![
1592 testing_utilities::create_mouse_event(
1593 MouseLocation::Relative(Default::default()),
1594 None, None, None, MousePhase::Down,
1598 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1599 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1600 event_time_u64,
1601 &descriptor,
1602 ),
1603 testing_utilities::create_mouse_event(
1604 MouseLocation::Relative(Default::default()),
1605 wheel_delta_ticks(1),
1606 None,
1607 Some(PrecisionScroll::No),
1608 MousePhase::Wheel,
1609 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1610 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1611 event_time_u64,
1612 &descriptor,
1613 ),
1614 testing_utilities::create_mouse_event(
1615 MouseLocation::Relative(Default::default()),
1616 wheel_delta_ticks(1),
1617 None,
1618 Some(PrecisionScroll::No),
1619 MousePhase::Wheel,
1620 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1621 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1622 event_time_u64,
1623 &descriptor,
1624 ),
1625 testing_utilities::create_mouse_event(
1626 MouseLocation::Relative(Default::default()),
1627 None, None, None, MousePhase::Up,
1631 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1632 HashSet::new(),
1633 event_time_u64,
1634 &descriptor,
1635 ),
1636 testing_utilities::create_mouse_event(
1637 MouseLocation::Relative(Default::default()),
1638 wheel_delta_ticks(1),
1639 None,
1640 Some(PrecisionScroll::No),
1641 MousePhase::Wheel,
1642 HashSet::new(),
1643 HashSet::new(),
1644 event_time_u64,
1645 &descriptor,
1646 ),
1647 ];
1648
1649 assert_input_report_sequence_generates_events!(
1650 input_reports: input_reports,
1651 expected_events: expected_events,
1652 device_descriptor: descriptor,
1653 device_type: MouseBinding,
1654 );
1655 }
1656}