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::{InputDeviceProxy, InputReport};
12use fuchsia_inspect::ArrayProperty;
13use fuchsia_inspect::health::Reporter;
14use fuchsia_sync::Mutex;
15use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
16use metrics_registry::*;
17use std::collections::HashSet;
18use {fidl_fuchsia_input_report as fidl_input_report, zx};
19
20pub type MouseButton = u8;
21
22#[derive(Copy, Clone, Debug, PartialEq)]
24pub enum PrecisionScroll {
25 Yes,
27 No,
29}
30
31#[derive(Copy, Clone, Debug, PartialEq)]
33pub enum MouseLocation {
34 Relative(RelativeLocation),
36
37 Absolute(Position),
39}
40
41#[derive(Copy, Clone, Debug, PartialEq)]
42pub enum MousePhase {
43 Down, Move, Up, Wheel, }
48
49#[derive(Copy, Clone, Debug, PartialEq)]
51pub struct RelativeLocation {
52 pub millimeters: Position,
54}
55
56impl Default for RelativeLocation {
57 fn default() -> Self {
58 RelativeLocation { millimeters: Position::zero() }
59 }
60}
61
62#[derive(Clone, Debug, PartialEq)]
64pub enum RawWheelDelta {
65 Ticks(i64),
67 Millimeters(f32),
69}
70
71#[derive(Clone, Debug, PartialEq)]
74
75pub struct WheelDelta {
76 pub raw_data: RawWheelDelta,
77 pub physical_pixel: Option<f32>,
78}
79
80#[derive(Debug)]
101pub struct MouseEvent {
102 pub location: MouseLocation,
104
105 pub wheel_delta_v: Option<WheelDelta>,
107
108 pub wheel_delta_h: Option<WheelDelta>,
110
111 pub is_precision_scroll: Option<PrecisionScroll>,
113
114 pub phase: MousePhase,
116
117 pub affected_buttons: HashSet<MouseButton>,
119
120 pub pressed_buttons: HashSet<MouseButton>,
122
123 pub wake_lease: Mutex<Option<zx::EventPair>>,
125}
126
127impl Clone for MouseEvent {
128 fn clone(&self) -> Self {
129 log::debug!("MouseEvent cloned without wake lease.");
130 Self {
131 location: self.location,
132 wheel_delta_v: self.wheel_delta_v.clone(),
133 wheel_delta_h: self.wheel_delta_h.clone(),
134 is_precision_scroll: self.is_precision_scroll,
135 phase: self.phase,
136 affected_buttons: self.affected_buttons.clone(),
137 pressed_buttons: self.pressed_buttons.clone(),
138 wake_lease: None.into(),
139 }
140 }
141}
142
143impl PartialEq for MouseEvent {
144 fn eq(&self, other: &Self) -> bool {
145 self.location == other.location
146 && self.wheel_delta_v == other.wheel_delta_v
147 && self.wheel_delta_h == other.wheel_delta_h
148 && self.is_precision_scroll == other.is_precision_scroll
149 && self.phase == other.phase
150 && self.affected_buttons == other.affected_buttons
151 && self.pressed_buttons == other.pressed_buttons
152 }
153}
154
155impl MouseEvent {
156 pub fn new(
164 location: MouseLocation,
165 wheel_delta_v: Option<WheelDelta>,
166 wheel_delta_h: Option<WheelDelta>,
167 phase: MousePhase,
168 affected_buttons: HashSet<MouseButton>,
169 pressed_buttons: HashSet<MouseButton>,
170 is_precision_scroll: Option<PrecisionScroll>,
171 wake_lease: Option<zx::EventPair>,
172 ) -> MouseEvent {
173 MouseEvent {
174 location,
175 wheel_delta_v,
176 wheel_delta_h,
177 phase,
178 affected_buttons,
179 pressed_buttons,
180 is_precision_scroll,
181 wake_lease: Mutex::new(wake_lease),
182 }
183 }
184
185 pub fn clone_with_wake_lease(&self) -> Self {
186 log::debug!("MouseEvent cloned with wake lease: {:?}", self.wake_lease);
187 Self {
188 location: self.location,
189 wheel_delta_v: self.wheel_delta_v.clone(),
190 wheel_delta_h: self.wheel_delta_h.clone(),
191 is_precision_scroll: self.is_precision_scroll,
192 phase: self.phase,
193 affected_buttons: self.affected_buttons.clone(),
194 pressed_buttons: self.pressed_buttons.clone(),
195 wake_lease: Mutex::new(self.wake_lease.lock().as_ref().map(|lease| {
196 lease
197 .duplicate_handle(zx::Rights::SAME_RIGHTS)
198 .expect("failed to duplicate event pair")
199 })),
200 }
201 }
202
203 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
204 match self.location {
205 MouseLocation::Relative(pos) => {
206 node.record_child("location_relative", move |location_node| {
207 location_node.record_double("x", f64::from(pos.millimeters.x));
208 location_node.record_double("y", f64::from(pos.millimeters.y));
209 })
210 }
211 MouseLocation::Absolute(pos) => {
212 node.record_child("location_absolute", move |location_node| {
213 location_node.record_double("x", f64::from(pos.x));
214 location_node.record_double("y", f64::from(pos.y));
215 })
216 }
217 };
218
219 if let Some(wheel_delta_v) = &self.wheel_delta_v {
220 node.record_child("wheel_delta_v", move |wheel_delta_v_node| {
221 match wheel_delta_v.raw_data {
222 RawWheelDelta::Ticks(ticks) => wheel_delta_v_node.record_int("ticks", ticks),
223 RawWheelDelta::Millimeters(mm) => {
224 wheel_delta_v_node.record_double("millimeters", f64::from(mm))
225 }
226 }
227 if let Some(physical_pixel) = wheel_delta_v.physical_pixel {
228 wheel_delta_v_node.record_double("physical_pixel", f64::from(physical_pixel));
229 }
230 });
231 }
232
233 if let Some(wheel_delta_h) = &self.wheel_delta_h {
234 node.record_child("wheel_delta_h", move |wheel_delta_h_node| {
235 match wheel_delta_h.raw_data {
236 RawWheelDelta::Ticks(ticks) => wheel_delta_h_node.record_int("ticks", ticks),
237 RawWheelDelta::Millimeters(mm) => {
238 wheel_delta_h_node.record_double("millimeters", f64::from(mm))
239 }
240 }
241 if let Some(physical_pixel) = wheel_delta_h.physical_pixel {
242 wheel_delta_h_node.record_double("physical_pixel", f64::from(physical_pixel));
243 }
244 });
245 }
246
247 if let Some(is_precision_scroll) = self.is_precision_scroll {
248 match is_precision_scroll {
249 PrecisionScroll::Yes => node.record_string("is_precision_scroll", "yes"),
250 PrecisionScroll::No => node.record_string("is_precision_scroll", "no"),
251 }
252 }
253
254 match self.phase {
255 MousePhase::Down => node.record_string("phase", "down"),
256 MousePhase::Move => node.record_string("phase", "move"),
257 MousePhase::Up => node.record_string("phase", "up"),
258 MousePhase::Wheel => node.record_string("phase", "wheel"),
259 }
260
261 let affected_buttons_node =
262 node.create_uint_array("affected_buttons", self.affected_buttons.len());
263 self.affected_buttons.iter().enumerate().for_each(|(i, button)| {
264 affected_buttons_node.set(i, *button);
265 });
266 node.record(affected_buttons_node);
267
268 let pressed_buttons_node =
269 node.create_uint_array("pressed_buttons", self.pressed_buttons.len());
270 self.pressed_buttons.iter().enumerate().for_each(|(i, button)| {
271 pressed_buttons_node.set(i, *button);
272 });
273 node.record(pressed_buttons_node);
274 }
275}
276
277pub struct MouseBinding {
283 event_sender: UnboundedSender<input_device::InputEvent>,
285
286 device_descriptor: MouseDeviceDescriptor,
288}
289
290#[derive(Clone, Debug, Eq, PartialEq)]
291pub struct MouseDeviceDescriptor {
292 pub device_id: u32,
294
295 pub absolute_x_range: Option<fidl_input_report::Range>,
297
298 pub absolute_y_range: Option<fidl_input_report::Range>,
300
301 pub wheel_v_range: Option<fidl_input_report::Axis>,
303
304 pub wheel_h_range: Option<fidl_input_report::Axis>,
306
307 pub buttons: Option<Vec<MouseButton>>,
309
310 pub counts_per_mm: u32,
313}
314
315#[async_trait]
316impl input_device::InputDeviceBinding for MouseBinding {
317 fn input_event_sender(&self) -> UnboundedSender<input_device::InputEvent> {
318 self.event_sender.clone()
319 }
320
321 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
322 input_device::InputDeviceDescriptor::Mouse(self.device_descriptor.clone())
323 }
324}
325
326impl MouseBinding {
327 pub async fn new(
342 device_proxy: InputDeviceProxy,
343 device_id: u32,
344 input_event_sender: UnboundedSender<input_device::InputEvent>,
345 device_node: fuchsia_inspect::Node,
346 metrics_logger: metrics::MetricsLogger,
347 ) -> Result<Self, Error> {
348 let (device_binding, mut inspect_status) =
349 Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
350 inspect_status.health_node.set_ok();
351 input_device::initialize_report_stream(
352 device_proxy,
353 device_binding.get_device_descriptor(),
354 device_binding.input_event_sender(),
355 inspect_status,
356 metrics_logger,
357 Self::process_reports,
358 );
359
360 Ok(device_binding)
361 }
362
363 async fn bind_device(
375 device: &InputDeviceProxy,
376 device_id: u32,
377 input_event_sender: UnboundedSender<input_device::InputEvent>,
378 device_node: fuchsia_inspect::Node,
379 ) -> Result<(Self, InputDeviceStatus), Error> {
380 let mut input_device_status = InputDeviceStatus::new(device_node);
381 let device_descriptor: fidl_input_report::DeviceDescriptor = match device
382 .get_descriptor()
383 .await
384 {
385 Ok(descriptor) => descriptor,
386 Err(_) => {
387 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
388 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
389 }
390 };
391
392 let mouse_descriptor = device_descriptor.mouse.ok_or_else(|| {
393 input_device_status
394 .health_node
395 .set_unhealthy("DeviceDescriptor does not have a MouseDescriptor.");
396 format_err!("DeviceDescriptor does not have a MouseDescriptor")
397 })?;
398
399 let mouse_input_descriptor = mouse_descriptor.input.ok_or_else(|| {
400 input_device_status
401 .health_node
402 .set_unhealthy("MouseDescriptor does not have a MouseInputDescriptor.");
403 format_err!("MouseDescriptor does not have a MouseInputDescriptor")
404 })?;
405
406 let model = mouse_model_database::db::get_mouse_model(device_descriptor.device_information);
407
408 let device_descriptor: MouseDeviceDescriptor = MouseDeviceDescriptor {
409 device_id,
410 absolute_x_range: mouse_input_descriptor.position_x.map(|axis| axis.range),
411 absolute_y_range: mouse_input_descriptor.position_y.map(|axis| axis.range),
412 wheel_v_range: mouse_input_descriptor.scroll_v,
413 wheel_h_range: mouse_input_descriptor.scroll_h,
414 buttons: mouse_input_descriptor.buttons,
415 counts_per_mm: model.counts_per_mm,
416 };
417
418 Ok((
419 MouseBinding { event_sender: input_event_sender, device_descriptor },
420 input_device_status,
421 ))
422 }
423
424 fn process_reports(
444 mut report: InputReport,
445 previous_report: Option<InputReport>,
446 device_descriptor: &input_device::InputDeviceDescriptor,
447 input_event_sender: &mut UnboundedSender<input_device::InputEvent>,
448 inspect_status: &InputDeviceStatus,
449 metrics_logger: &metrics::MetricsLogger,
450 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
451 fuchsia_trace::duration!(c"input", c"mouse-binding-process-report");
452 if let Some(trace_id) = report.trace_id {
453 fuchsia_trace::flow_end!(c"input", c"input_report", trace_id.into());
454 }
455
456 inspect_status.count_received_report(&report);
457 let mouse_report: &fidl_input_report::MouseInputReport = match &report.mouse {
459 Some(mouse) => mouse,
460 None => {
461 inspect_status.count_filtered_report();
462 return (previous_report, None);
463 }
464 };
465
466 let previous_buttons: HashSet<MouseButton> =
467 buttons_from_optional_report(&previous_report.as_ref());
468 let current_buttons: HashSet<MouseButton> = buttons_from_report(&report);
469 let wake_lease = report.wake_lease.take();
470
471 send_mouse_event(
477 MouseLocation::Relative(Default::default()),
478 None, None, MousePhase::Down,
481 current_buttons.difference(&previous_buttons).cloned().collect(),
482 current_buttons.clone(),
483 device_descriptor,
484 input_event_sender,
485 inspect_status,
486 metrics_logger,
487 wake_lease.as_ref().map(|lease| {
488 lease
489 .duplicate_handle(zx::Rights::SAME_RIGHTS)
490 .expect("failed to duplicate event pair")
491 }),
492 );
493
494 let counts_per_mm = match device_descriptor {
495 input_device::InputDeviceDescriptor::Mouse(ds) => ds.counts_per_mm,
496 _ => {
497 metrics_logger.log_error(
498 InputPipelineErrorMetricDimensionEvent::MouseDescriptionNotMouse,
499 "mouse_binding::process_reports got device_descriptor not mouse".to_string(),
500 );
501 mouse_model_database::db::DEFAULT_COUNTS_PER_MM
502 }
503 };
504
505 let location = if let (Some(position_x), Some(position_y)) =
507 (mouse_report.position_x, mouse_report.position_y)
508 {
509 MouseLocation::Absolute(Position { x: position_x as f32, y: position_y as f32 })
510 } else {
511 let movement_x = mouse_report.movement_x.unwrap_or_default() as f32;
512 let movement_y = mouse_report.movement_y.unwrap_or_default() as f32;
513 MouseLocation::Relative(RelativeLocation {
514 millimeters: Position {
515 x: movement_x / counts_per_mm as f32,
516 y: movement_y / counts_per_mm as f32,
517 },
518 })
519 };
520
521 send_mouse_event(
525 location,
526 None, None, MousePhase::Move,
529 current_buttons.union(&previous_buttons).cloned().collect(),
530 current_buttons.union(&previous_buttons).cloned().collect(),
531 device_descriptor,
532 input_event_sender,
533 inspect_status,
534 metrics_logger,
535 wake_lease.as_ref().map(|lease| {
536 lease
537 .duplicate_handle(zx::Rights::SAME_RIGHTS)
538 .expect("failed to duplicate event pair")
539 }),
540 );
541
542 let wheel_delta_v = match mouse_report.scroll_v {
543 None => None,
544 Some(ticks) => {
545 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
546 }
547 };
548
549 let wheel_delta_h = match mouse_report.scroll_h {
550 None => None,
551 Some(ticks) => {
552 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
553 }
554 };
555
556 send_mouse_event(
558 MouseLocation::Relative(Default::default()),
559 wheel_delta_v,
560 wheel_delta_h,
561 MousePhase::Wheel,
562 current_buttons.union(&previous_buttons).cloned().collect(),
563 current_buttons.union(&previous_buttons).cloned().collect(),
564 device_descriptor,
565 input_event_sender,
566 inspect_status,
567 metrics_logger,
568 wake_lease.as_ref().map(|lease| {
569 lease
570 .duplicate_handle(zx::Rights::SAME_RIGHTS)
571 .expect("failed to duplicate event pair")
572 }),
573 );
574
575 send_mouse_event(
581 MouseLocation::Relative(Default::default()),
582 None, None, MousePhase::Up,
585 previous_buttons.difference(¤t_buttons).cloned().collect(),
586 current_buttons.clone(),
587 device_descriptor,
588 input_event_sender,
589 inspect_status,
590 metrics_logger,
591 wake_lease,
592 );
593
594 (Some(report), None)
595 }
596}
597
598fn send_mouse_event(
613 location: MouseLocation,
614 wheel_delta_v: Option<WheelDelta>,
615 wheel_delta_h: Option<WheelDelta>,
616 phase: MousePhase,
617 affected_buttons: HashSet<MouseButton>,
618 pressed_buttons: HashSet<MouseButton>,
619 device_descriptor: &input_device::InputDeviceDescriptor,
620 sender: &mut UnboundedSender<input_device::InputEvent>,
621 inspect_status: &InputDeviceStatus,
622 metrics_logger: &metrics::MetricsLogger,
623 wake_lease: Option<zx::EventPair>,
624) {
625 if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
627 return;
628 }
629
630 if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
633 return;
634 }
635
636 if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
638 return;
639 }
640
641 let trace_id = fuchsia_trace::Id::random();
642 fuchsia_trace::duration!(c"input", c"mouse-binding-send-event");
643 fuchsia_trace::flow_begin!(c"input", c"event_in_input_pipeline", trace_id);
644
645 let event = input_device::InputEvent {
646 device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
647 location,
648 wheel_delta_v,
649 wheel_delta_h,
650 phase,
651 affected_buttons,
652 pressed_buttons,
653 match phase {
654 MousePhase::Wheel => Some(PrecisionScroll::No),
655 _ => None,
656 },
657 wake_lease,
658 )),
659 device_descriptor: device_descriptor.clone(),
660 event_time: zx::MonotonicInstant::get(),
661 handled: Handled::No,
662 trace_id: Some(trace_id),
663 };
664
665 match sender.unbounded_send(event.clone_with_wake_lease()) {
666 Err(e) => {
667 metrics_logger.log_error(
668 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
669 std::format!("Failed to send MouseEvent with error: {:?}", e),
670 );
671 }
672 _ => inspect_status.count_generated_event(event),
673 }
674}
675
676pub fn get_u32_from_buttons(buttons: &HashSet<MouseButton>) -> u32 {
690 let mut bits: u32 = 0;
691 for button in buttons {
692 if *button > 0 && *button <= fidl_input_report::MOUSE_MAX_NUM_BUTTONS as u8 {
693 bits = ((1 as u32) << *button - 1) | bits;
694 }
695 }
696
697 bits
698}
699
700fn buttons_from_report(input_report: &fidl_input_report::InputReport) -> HashSet<MouseButton> {
705 buttons_from_optional_report(&Some(input_report))
706}
707
708fn buttons_from_optional_report(
713 input_report: &Option<&fidl_input_report::InputReport>,
714) -> HashSet<MouseButton> {
715 input_report
716 .as_ref()
717 .and_then(|unwrapped_report| unwrapped_report.mouse.as_ref())
718 .and_then(|mouse_report| match &mouse_report.pressed_buttons {
719 Some(buttons) => Some(HashSet::from_iter(buttons.iter().cloned())),
720 None => None,
721 })
722 .unwrap_or_default()
723}
724
725#[cfg(test)]
726mod tests {
727 use super::*;
728 use crate::testing_utilities;
729 use fuchsia_async as fasync;
730 use futures::StreamExt;
731 use pretty_assertions::assert_eq;
732
733 const DEVICE_ID: u32 = 1;
734 const COUNTS_PER_MM: u32 = 12;
735
736 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
737 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
738 device_id,
739 absolute_x_range: None,
740 absolute_y_range: None,
741 wheel_v_range: Some(fidl_fuchsia_input_report::Axis {
742 range: fidl_input_report::Range { min: -1, max: 1 },
743 unit: fidl_input_report::Unit {
744 type_: fidl_input_report::UnitType::Other,
745 exponent: 1,
746 },
747 }),
748 wheel_h_range: Some(fidl_fuchsia_input_report::Axis {
749 range: fidl_input_report::Range { min: -1, max: 1 },
750 unit: fidl_input_report::Unit {
751 type_: fidl_input_report::UnitType::Other,
752 exponent: 1,
753 },
754 }),
755 buttons: None,
756 counts_per_mm: COUNTS_PER_MM,
757 })
758 }
759
760 fn wheel_delta_ticks(delta: i64) -> Option<WheelDelta> {
761 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(delta), physical_pixel: None })
762 }
763
764 #[test]
766 fn get_u32_from_buttons_test() {
767 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, 5].into_iter()));
768 assert_eq!(bits, 21 )
769 }
770
771 #[test]
773 fn get_u32_with_0_in_vector() {
774 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![0, 1, 3].into_iter()));
775 assert_eq!(bits, 5 )
776 }
777
778 #[test]
780 fn get_u32_with_empty_vector() {
781 let bits = get_u32_from_buttons(&HashSet::new());
782 assert_eq!(bits, 0 )
783 }
784
785 #[test]
787 fn get_u32_with_u8_max_in_vector() {
788 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, std::u8::MAX].into_iter()));
789 assert_eq!(bits, 5 )
790 }
791
792 #[test]
795 fn get_u32_with_max_mouse_buttons() {
796 let bits = get_u32_from_buttons(&HashSet::from_iter(
797 vec![1, 3, fidl_input_report::MOUSE_MAX_NUM_BUTTONS as MouseButton].into_iter(),
798 ));
799 assert_eq!(bits, 2147483653 )
800 }
801
802 #[fasync::run_singlethreaded(test)]
804 async fn movement_without_button() {
805 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
806 let first_report = testing_utilities::create_mouse_input_report_relative(
807 Position { x: 10.0, y: 16.0 },
808 None, None, vec![],
811 event_time_i64,
812 );
813 let descriptor = mouse_device_descriptor(DEVICE_ID);
814
815 let input_reports = vec![first_report];
816 let expected_events = vec![testing_utilities::create_mouse_event(
817 MouseLocation::Relative(RelativeLocation {
818 millimeters: Position {
819 x: 10.0 / COUNTS_PER_MM as f32,
820 y: 16.0 / COUNTS_PER_MM as f32,
821 },
822 }),
823 None, None, None, MousePhase::Move,
827 HashSet::new(),
828 HashSet::new(),
829 event_time_u64,
830 &descriptor,
831 )];
832
833 assert_input_report_sequence_generates_events!(
834 input_reports: input_reports,
835 expected_events: expected_events,
836 device_descriptor: descriptor,
837 device_type: MouseBinding,
838 );
839 }
840
841 #[fasync::run_singlethreaded(test)]
843 async fn down_without_movement() {
844 let mouse_button: MouseButton = 3;
845 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
846 let first_report = testing_utilities::create_mouse_input_report_relative(
847 Position::zero(),
848 None, None, vec![mouse_button],
851 event_time_i64,
852 );
853 let descriptor = mouse_device_descriptor(DEVICE_ID);
854
855 let input_reports = vec![first_report];
856 let expected_events = vec![testing_utilities::create_mouse_event(
857 MouseLocation::Relative(Default::default()),
858 None, None, None, MousePhase::Down,
862 HashSet::from_iter(vec![mouse_button].into_iter()),
863 HashSet::from_iter(vec![mouse_button].into_iter()),
864 event_time_u64,
865 &descriptor,
866 )];
867
868 assert_input_report_sequence_generates_events!(
869 input_reports: input_reports,
870 expected_events: expected_events,
871 device_descriptor: descriptor,
872 device_type: MouseBinding,
873 );
874 }
875
876 #[fasync::run_singlethreaded(test)]
879 async fn down_with_movement() {
880 let mouse_button: MouseButton = 3;
881 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
882 let first_report = testing_utilities::create_mouse_input_report_relative(
883 Position { x: 10.0, y: 16.0 },
884 None, None, vec![mouse_button],
887 event_time_i64,
888 );
889 let descriptor = mouse_device_descriptor(DEVICE_ID);
890
891 let input_reports = vec![first_report];
892 let expected_events = vec![
893 testing_utilities::create_mouse_event(
894 MouseLocation::Relative(Default::default()),
895 None, None, None, MousePhase::Down,
899 HashSet::from_iter(vec![mouse_button].into_iter()),
900 HashSet::from_iter(vec![mouse_button].into_iter()),
901 event_time_u64,
902 &descriptor,
903 ),
904 testing_utilities::create_mouse_event(
905 MouseLocation::Relative(RelativeLocation {
906 millimeters: Position {
907 x: 10.0 / COUNTS_PER_MM as f32,
908 y: 16.0 / COUNTS_PER_MM as f32,
909 },
910 }),
911 None, None, None, MousePhase::Move,
915 HashSet::from_iter(vec![mouse_button].into_iter()),
916 HashSet::from_iter(vec![mouse_button].into_iter()),
917 event_time_u64,
918 &descriptor,
919 ),
920 ];
921
922 assert_input_report_sequence_generates_events!(
923 input_reports: input_reports,
924 expected_events: expected_events,
925 device_descriptor: descriptor,
926 device_type: MouseBinding,
927 );
928 }
929
930 #[fasync::run_singlethreaded(test)]
932 async fn down_up() {
933 let button = 1;
934 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
935 let first_report = testing_utilities::create_mouse_input_report_relative(
936 Position::zero(),
937 None, None, vec![button],
940 event_time_i64,
941 );
942 let second_report = testing_utilities::create_mouse_input_report_relative(
943 Position::zero(),
944 None, None, vec![],
947 event_time_i64,
948 );
949 let descriptor = mouse_device_descriptor(DEVICE_ID);
950
951 let input_reports = vec![first_report, second_report];
952 let expected_events = vec![
953 testing_utilities::create_mouse_event(
954 MouseLocation::Relative(Default::default()),
955 None, None, None, MousePhase::Down,
959 HashSet::from_iter(vec![button].into_iter()),
960 HashSet::from_iter(vec![button].into_iter()),
961 event_time_u64,
962 &descriptor,
963 ),
964 testing_utilities::create_mouse_event(
965 MouseLocation::Relative(Default::default()),
966 None, None, None, MousePhase::Up,
970 HashSet::from_iter(vec![button].into_iter()),
971 HashSet::new(),
972 event_time_u64,
973 &descriptor,
974 ),
975 ];
976
977 assert_input_report_sequence_generates_events!(
978 input_reports: input_reports,
979 expected_events: expected_events,
980 device_descriptor: descriptor,
981 device_type: MouseBinding,
982 );
983 }
984
985 #[fasync::run_singlethreaded(test)]
987 async fn down_up_with_movement() {
988 let button = 1;
989
990 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
991 let first_report = testing_utilities::create_mouse_input_report_relative(
992 Position::zero(),
993 None, None, vec![button],
996 event_time_i64,
997 );
998 let second_report = testing_utilities::create_mouse_input_report_relative(
999 Position { x: 10.0, y: 16.0 },
1000 None, None, vec![],
1003 event_time_i64,
1004 );
1005 let descriptor = mouse_device_descriptor(DEVICE_ID);
1006
1007 let input_reports = vec![first_report, second_report];
1008 let expected_events = vec![
1009 testing_utilities::create_mouse_event(
1010 MouseLocation::Relative(Default::default()),
1011 None, None, None, MousePhase::Down,
1015 HashSet::from_iter(vec![button].into_iter()),
1016 HashSet::from_iter(vec![button].into_iter()),
1017 event_time_u64,
1018 &descriptor,
1019 ),
1020 testing_utilities::create_mouse_event(
1021 MouseLocation::Relative(RelativeLocation {
1022 millimeters: Position {
1023 x: 10.0 / COUNTS_PER_MM as f32,
1024 y: 16.0 / COUNTS_PER_MM as f32,
1025 },
1026 }),
1027 None, None, None, MousePhase::Move,
1031 HashSet::from_iter(vec![button].into_iter()),
1032 HashSet::from_iter(vec![button].into_iter()),
1033 event_time_u64,
1034 &descriptor,
1035 ),
1036 testing_utilities::create_mouse_event(
1037 MouseLocation::Relative(Default::default()),
1038 None, None, None, MousePhase::Up,
1042 HashSet::from_iter(vec![button].into_iter()),
1043 HashSet::new(),
1044 event_time_u64,
1045 &descriptor,
1046 ),
1047 ];
1048
1049 assert_input_report_sequence_generates_events!(
1050 input_reports: input_reports,
1051 expected_events: expected_events,
1052 device_descriptor: descriptor,
1053 device_type: MouseBinding,
1054 );
1055 }
1056
1057 #[fasync::run_singlethreaded(test)]
1061 async fn down_move_up() {
1062 let button = 1;
1063
1064 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1065 let first_report = testing_utilities::create_mouse_input_report_relative(
1066 Position::zero(),
1067 None, None, vec![button],
1070 event_time_i64,
1071 );
1072 let second_report = testing_utilities::create_mouse_input_report_relative(
1073 Position { x: 10.0, y: 16.0 },
1074 None, None, vec![button],
1077 event_time_i64,
1078 );
1079 let third_report = testing_utilities::create_mouse_input_report_relative(
1080 Position::zero(),
1081 None, None, vec![],
1084 event_time_i64,
1085 );
1086 let descriptor = mouse_device_descriptor(DEVICE_ID);
1087
1088 let input_reports = vec![first_report, second_report, third_report];
1089 let expected_events = vec![
1090 testing_utilities::create_mouse_event(
1091 MouseLocation::Relative(Default::default()),
1092 None, None, None, MousePhase::Down,
1096 HashSet::from_iter(vec![button].into_iter()),
1097 HashSet::from_iter(vec![button].into_iter()),
1098 event_time_u64,
1099 &descriptor,
1100 ),
1101 testing_utilities::create_mouse_event(
1102 MouseLocation::Relative(RelativeLocation {
1103 millimeters: Position {
1104 x: 10.0 / COUNTS_PER_MM as f32,
1105 y: 16.0 / COUNTS_PER_MM as f32,
1106 },
1107 }),
1108 None, None, None, MousePhase::Move,
1112 HashSet::from_iter(vec![button].into_iter()),
1113 HashSet::from_iter(vec![button].into_iter()),
1114 event_time_u64,
1115 &descriptor,
1116 ),
1117 testing_utilities::create_mouse_event(
1118 MouseLocation::Relative(Default::default()),
1119 None, None, None, MousePhase::Up,
1123 HashSet::from_iter(vec![button].into_iter()),
1124 HashSet::new(),
1125 event_time_u64,
1126 &descriptor,
1127 ),
1128 ];
1129
1130 assert_input_report_sequence_generates_events!(
1131 input_reports: input_reports,
1132 expected_events: expected_events,
1133 device_descriptor: descriptor,
1134 device_type: MouseBinding,
1135 );
1136 }
1137
1138 #[fasync::run_until_stalled(test)]
1140 async fn absolute_movement_to_origin() {
1141 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1142 let descriptor = mouse_device_descriptor(DEVICE_ID);
1143
1144 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
1145 Position::zero(),
1146 None, None, vec![],
1149 event_time_i64,
1150 )];
1151 let expected_events = vec![testing_utilities::create_mouse_event(
1152 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1153 None, None, None, MousePhase::Move,
1157 HashSet::new(),
1158 HashSet::new(),
1159 event_time_u64,
1160 &descriptor,
1161 )];
1162
1163 assert_input_report_sequence_generates_events!(
1164 input_reports: input_reports,
1165 expected_events: expected_events,
1166 device_descriptor: descriptor,
1167 device_type: MouseBinding,
1168 );
1169 }
1170
1171 #[fasync::run_until_stalled(test)]
1174 async fn report_with_both_movement_and_position() {
1175 let relative_movement = Position { x: 5.0, y: 5.0 };
1176 let absolute_position = Position { x: 10.0, y: 10.0 };
1177 let expected_location = MouseLocation::Absolute(absolute_position);
1178
1179 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1180 let descriptor = mouse_device_descriptor(DEVICE_ID);
1181
1182 let input_reports = vec![fidl_input_report::InputReport {
1183 event_time: Some(event_time_i64),
1184 keyboard: None,
1185 mouse: Some(fidl_input_report::MouseInputReport {
1186 movement_x: Some(relative_movement.x as i64),
1187 movement_y: Some(relative_movement.y as i64),
1188 position_x: Some(absolute_position.x as i64),
1189 position_y: Some(absolute_position.y as i64),
1190 scroll_h: None,
1191 scroll_v: None,
1192 pressed_buttons: None,
1193 ..Default::default()
1194 }),
1195 touch: None,
1196 sensor: None,
1197 consumer_control: None,
1198 trace_id: None,
1199 ..Default::default()
1200 }];
1201 let expected_events = vec![testing_utilities::create_mouse_event(
1202 expected_location,
1203 None, None, None, MousePhase::Move,
1207 HashSet::new(),
1208 HashSet::new(),
1209 event_time_u64,
1210 &descriptor,
1211 )];
1212
1213 assert_input_report_sequence_generates_events!(
1214 input_reports: input_reports,
1215 expected_events: expected_events,
1216 device_descriptor: descriptor,
1217 device_type: MouseBinding,
1218 );
1219 }
1220
1221 #[fasync::run_singlethreaded(test)]
1224 async fn down_down() {
1225 const PRIMARY_BUTTON: u8 = 1;
1226 const SECONDARY_BUTTON: u8 = 2;
1227
1228 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1229 let first_report = testing_utilities::create_mouse_input_report_relative(
1230 Position::zero(),
1231 None, None, vec![PRIMARY_BUTTON],
1234 event_time_i64,
1235 );
1236 let second_report = testing_utilities::create_mouse_input_report_relative(
1237 Position::zero(),
1238 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1241 event_time_i64,
1242 );
1243 let descriptor = mouse_device_descriptor(DEVICE_ID);
1244
1245 let input_reports = vec![first_report, second_report];
1246 let expected_events = vec![
1247 testing_utilities::create_mouse_event(
1248 MouseLocation::Relative(Default::default()),
1249 None, None, None, MousePhase::Down,
1253 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1254 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1255 event_time_u64,
1256 &descriptor,
1257 ),
1258 testing_utilities::create_mouse_event(
1259 MouseLocation::Relative(Default::default()),
1260 None, None, None, MousePhase::Down,
1264 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1265 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1266 event_time_u64,
1267 &descriptor,
1268 ),
1269 ];
1270
1271 assert_input_report_sequence_generates_events!(
1272 input_reports: input_reports,
1273 expected_events: expected_events,
1274 device_descriptor: descriptor,
1275 device_type: MouseBinding,
1276 );
1277 }
1278
1279 #[fasync::run_singlethreaded(test)]
1289 async fn down_down_up_up() {
1290 const PRIMARY_BUTTON: u8 = 1;
1291 const SECONDARY_BUTTON: u8 = 2;
1292
1293 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1294 let first_report = testing_utilities::create_mouse_input_report_relative(
1295 Position::zero(),
1296 None, None, vec![PRIMARY_BUTTON],
1299 event_time_i64,
1300 );
1301 let second_report = testing_utilities::create_mouse_input_report_relative(
1302 Position::zero(),
1303 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1306 event_time_i64,
1307 );
1308 let third_report = testing_utilities::create_mouse_input_report_relative(
1309 Position::zero(),
1310 None, None, vec![SECONDARY_BUTTON],
1313 event_time_i64,
1314 );
1315 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1316 Position::zero(),
1317 None, None, vec![],
1320 event_time_i64,
1321 );
1322 let descriptor = mouse_device_descriptor(DEVICE_ID);
1323
1324 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1325 let expected_events = vec![
1326 testing_utilities::create_mouse_event(
1327 MouseLocation::Relative(Default::default()),
1328 None, None, None, MousePhase::Down,
1332 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1333 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1334 event_time_u64,
1335 &descriptor,
1336 ),
1337 testing_utilities::create_mouse_event(
1338 MouseLocation::Relative(Default::default()),
1339 None, None, None, MousePhase::Down,
1343 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1344 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1345 event_time_u64,
1346 &descriptor,
1347 ),
1348 testing_utilities::create_mouse_event(
1349 MouseLocation::Relative(Default::default()),
1350 None, None, None, MousePhase::Up,
1354 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1355 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1356 event_time_u64,
1357 &descriptor,
1358 ),
1359 testing_utilities::create_mouse_event(
1360 MouseLocation::Relative(Default::default()),
1361 None, None, None, MousePhase::Up,
1365 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1366 HashSet::new(),
1367 event_time_u64,
1368 &descriptor,
1369 ),
1370 ];
1371
1372 assert_input_report_sequence_generates_events!(
1373 input_reports: input_reports,
1374 expected_events: expected_events,
1375 device_descriptor: descriptor,
1376 device_type: MouseBinding,
1377 );
1378 }
1379
1380 #[fasync::run_singlethreaded(test)]
1382 async fn scroll() {
1383 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1384 let first_report = testing_utilities::create_mouse_input_report_relative(
1385 Position::zero(),
1386 Some(1),
1387 None,
1388 vec![],
1389 event_time_i64,
1390 );
1391 let second_report = testing_utilities::create_mouse_input_report_relative(
1392 Position::zero(),
1393 None,
1394 Some(1),
1395 vec![],
1396 event_time_i64,
1397 );
1398
1399 let descriptor = mouse_device_descriptor(DEVICE_ID);
1400
1401 let input_reports = vec![first_report, second_report];
1402 let expected_events = vec![
1403 testing_utilities::create_mouse_event(
1404 MouseLocation::Relative(Default::default()),
1405 wheel_delta_ticks(1),
1406 None,
1407 Some(PrecisionScroll::No),
1408 MousePhase::Wheel,
1409 HashSet::new(),
1410 HashSet::new(),
1411 event_time_u64,
1412 &descriptor,
1413 ),
1414 testing_utilities::create_mouse_event(
1415 MouseLocation::Relative(Default::default()),
1416 None,
1417 wheel_delta_ticks(1),
1418 Some(PrecisionScroll::No),
1419 MousePhase::Wheel,
1420 HashSet::new(),
1421 HashSet::new(),
1422 event_time_u64,
1423 &descriptor,
1424 ),
1425 ];
1426
1427 assert_input_report_sequence_generates_events!(
1428 input_reports: input_reports,
1429 expected_events: expected_events,
1430 device_descriptor: descriptor,
1431 device_type: MouseBinding,
1432 );
1433 }
1434
1435 #[fasync::run_singlethreaded(test)]
1437 async fn down_scroll_up_scroll() {
1438 const PRIMARY_BUTTON: u8 = 1;
1439
1440 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1441 let first_report = testing_utilities::create_mouse_input_report_relative(
1442 Position::zero(),
1443 None, None, vec![PRIMARY_BUTTON],
1446 event_time_i64,
1447 );
1448 let second_report = testing_utilities::create_mouse_input_report_relative(
1449 Position::zero(),
1450 Some(1),
1451 None,
1452 vec![PRIMARY_BUTTON],
1453 event_time_i64,
1454 );
1455 let third_report = testing_utilities::create_mouse_input_report_relative(
1456 Position::zero(),
1457 None, None, vec![],
1460 event_time_i64,
1461 );
1462 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1463 Position::zero(),
1464 Some(1),
1465 None,
1466 vec![],
1467 event_time_i64,
1468 );
1469
1470 let descriptor = mouse_device_descriptor(DEVICE_ID);
1471
1472 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1473 let expected_events = vec![
1474 testing_utilities::create_mouse_event(
1475 MouseLocation::Relative(Default::default()),
1476 None, None, None, MousePhase::Down,
1480 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1481 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1482 event_time_u64,
1483 &descriptor,
1484 ),
1485 testing_utilities::create_mouse_event(
1486 MouseLocation::Relative(Default::default()),
1487 wheel_delta_ticks(1),
1488 None,
1489 Some(PrecisionScroll::No),
1490 MousePhase::Wheel,
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 None, None, None, MousePhase::Up,
1502 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1503 HashSet::new(),
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::new(),
1514 HashSet::new(),
1515 event_time_u64,
1516 &descriptor,
1517 ),
1518 ];
1519
1520 assert_input_report_sequence_generates_events!(
1521 input_reports: input_reports,
1522 expected_events: expected_events,
1523 device_descriptor: descriptor,
1524 device_type: MouseBinding,
1525 );
1526 }
1527
1528 #[fasync::run_singlethreaded(test)]
1530 async fn down_scroll_bundle_up_scroll_bundle() {
1531 const PRIMARY_BUTTON: u8 = 1;
1532
1533 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1534 let first_report = testing_utilities::create_mouse_input_report_relative(
1535 Position::zero(),
1536 Some(1),
1537 None,
1538 vec![PRIMARY_BUTTON],
1539 event_time_i64,
1540 );
1541 let second_report = testing_utilities::create_mouse_input_report_relative(
1542 Position::zero(),
1543 Some(1),
1544 None,
1545 vec![],
1546 event_time_i64,
1547 );
1548 let third_report = testing_utilities::create_mouse_input_report_relative(
1549 Position::zero(),
1550 Some(1),
1551 None,
1552 vec![],
1553 event_time_i64,
1554 );
1555
1556 let descriptor = mouse_device_descriptor(DEVICE_ID);
1557
1558 let input_reports = vec![first_report, second_report, third_report];
1559 let expected_events = vec![
1560 testing_utilities::create_mouse_event(
1561 MouseLocation::Relative(Default::default()),
1562 None, None, None, MousePhase::Down,
1566 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1567 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1568 event_time_u64,
1569 &descriptor,
1570 ),
1571 testing_utilities::create_mouse_event(
1572 MouseLocation::Relative(Default::default()),
1573 wheel_delta_ticks(1),
1574 None,
1575 Some(PrecisionScroll::No),
1576 MousePhase::Wheel,
1577 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1578 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1579 event_time_u64,
1580 &descriptor,
1581 ),
1582 testing_utilities::create_mouse_event(
1583 MouseLocation::Relative(Default::default()),
1584 wheel_delta_ticks(1),
1585 None,
1586 Some(PrecisionScroll::No),
1587 MousePhase::Wheel,
1588 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1589 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1590 event_time_u64,
1591 &descriptor,
1592 ),
1593 testing_utilities::create_mouse_event(
1594 MouseLocation::Relative(Default::default()),
1595 None, None, None, MousePhase::Up,
1599 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1600 HashSet::new(),
1601 event_time_u64,
1602 &descriptor,
1603 ),
1604 testing_utilities::create_mouse_event(
1605 MouseLocation::Relative(Default::default()),
1606 wheel_delta_ticks(1),
1607 None,
1608 Some(PrecisionScroll::No),
1609 MousePhase::Wheel,
1610 HashSet::new(),
1611 HashSet::new(),
1612 event_time_u64,
1613 &descriptor,
1614 ),
1615 ];
1616
1617 assert_input_report_sequence_generates_events!(
1618 input_reports: input_reports,
1619 expected_events: expected_events,
1620 device_descriptor: descriptor,
1621 device_type: MouseBinding,
1622 );
1623 }
1624}