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<Vec<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<Vec<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<Vec<InputEvent>>,
345 device_node: fuchsia_inspect::Node,
346 _feature_flags: input_device::InputPipelineFeatureFlags,
347 metrics_logger: metrics::MetricsLogger,
348 ) -> Result<Self, Error> {
349 let (device_binding, mut inspect_status) =
350 Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
351 inspect_status.health_node.set_ok();
352 input_device::initialize_report_stream(
353 device_proxy,
354 device_binding.get_device_descriptor(),
355 device_binding.input_event_sender(),
356 inspect_status,
357 metrics_logger,
358 _feature_flags,
359 Self::process_reports,
360 );
361
362 Ok(device_binding)
363 }
364
365 async fn bind_device(
377 device: &InputDeviceProxy,
378 device_id: u32,
379 input_event_sender: UnboundedSender<Vec<InputEvent>>,
380 device_node: fuchsia_inspect::Node,
381 ) -> Result<(Self, InputDeviceStatus), Error> {
382 let mut input_device_status = InputDeviceStatus::new(device_node);
383 let device_descriptor: fidl_input_report::DeviceDescriptor = match device
384 .get_descriptor()
385 .await
386 {
387 Ok(descriptor) => descriptor,
388 Err(_) => {
389 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
390 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
391 }
392 };
393
394 let mouse_descriptor = device_descriptor.mouse.ok_or_else(|| {
395 input_device_status
396 .health_node
397 .set_unhealthy("DeviceDescriptor does not have a MouseDescriptor.");
398 format_err!("DeviceDescriptor does not have a MouseDescriptor")
399 })?;
400
401 let mouse_input_descriptor = mouse_descriptor.input.ok_or_else(|| {
402 input_device_status
403 .health_node
404 .set_unhealthy("MouseDescriptor does not have a MouseInputDescriptor.");
405 format_err!("MouseDescriptor does not have a MouseInputDescriptor")
406 })?;
407
408 let model = mouse_model_database::db::get_mouse_model(device_descriptor.device_information);
409
410 let device_descriptor: MouseDeviceDescriptor = MouseDeviceDescriptor {
411 device_id,
412 absolute_x_range: mouse_input_descriptor.position_x.map(|axis| axis.range),
413 absolute_y_range: mouse_input_descriptor.position_y.map(|axis| axis.range),
414 wheel_v_range: mouse_input_descriptor.scroll_v,
415 wheel_h_range: mouse_input_descriptor.scroll_h,
416 buttons: mouse_input_descriptor.buttons,
417 counts_per_mm: model.counts_per_mm,
418 };
419
420 Ok((
421 MouseBinding { event_sender: input_event_sender, device_descriptor },
422 input_device_status,
423 ))
424 }
425
426 fn process_reports(
448 reports: Vec<InputReport>,
449 mut previous_report: Option<InputReport>,
450 device_descriptor: &input_device::InputDeviceDescriptor,
451 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
452 inspect_status: &InputDeviceStatus,
453 metrics_logger: &metrics::MetricsLogger,
454 _feature_flags: &input_device::InputPipelineFeatureFlags,
455 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
456 fuchsia_trace::duration!("input", "mouse-binding-process-reports", "num_reports" => reports.len());
457 for report in reports {
458 previous_report = Self::process_report(
459 report,
460 previous_report,
461 device_descriptor,
462 input_event_sender,
463 inspect_status,
464 metrics_logger,
465 );
466 }
467 (previous_report, None)
468 }
469
470 fn process_report(
471 mut report: InputReport,
472 previous_report: Option<InputReport>,
473 device_descriptor: &input_device::InputDeviceDescriptor,
474 input_event_sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
475 inspect_status: &InputDeviceStatus,
476 metrics_logger: &metrics::MetricsLogger,
477 ) -> Option<InputReport> {
478 if let Some(trace_id) = report.trace_id {
479 fuchsia_trace::flow_end!("input", "input_report", trace_id.into());
480 }
481
482 inspect_status.count_received_report(&report);
483 let mouse_report: &fidl_input_report::MouseInputReport = match &report.mouse {
485 Some(mouse) => mouse,
486 None => {
487 inspect_status.count_filtered_report();
488 return previous_report;
489 }
490 };
491
492 let previous_buttons: HashSet<MouseButton> =
493 buttons_from_optional_report(&previous_report.as_ref());
494 let current_buttons: HashSet<MouseButton> = buttons_from_report(&report);
495 let wake_lease = report.wake_lease.take();
496
497 send_mouse_event(
503 MouseLocation::Relative(Default::default()),
504 None, None, MousePhase::Down,
507 current_buttons.difference(&previous_buttons).cloned().collect(),
508 current_buttons.clone(),
509 device_descriptor,
510 input_event_sender,
511 inspect_status,
512 metrics_logger,
513 wake_lease.as_ref().map(|lease| {
514 lease
515 .duplicate_handle(zx::Rights::SAME_RIGHTS)
516 .expect("failed to duplicate event pair")
517 }),
518 );
519
520 let counts_per_mm = match device_descriptor {
521 input_device::InputDeviceDescriptor::Mouse(ds) => ds.counts_per_mm,
522 _ => {
523 metrics_logger.log_error(
524 InputPipelineErrorMetricDimensionEvent::MouseDescriptionNotMouse,
525 "mouse_binding::process_reports got device_descriptor not mouse".to_string(),
526 );
527 mouse_model_database::db::DEFAULT_COUNTS_PER_MM
528 }
529 };
530
531 let location = if let (Some(position_x), Some(position_y)) =
533 (mouse_report.position_x, mouse_report.position_y)
534 {
535 MouseLocation::Absolute(Position { x: position_x as f32, y: position_y as f32 })
536 } else {
537 let movement_x = mouse_report.movement_x.unwrap_or_default() as f32;
538 let movement_y = mouse_report.movement_y.unwrap_or_default() as f32;
539 MouseLocation::Relative(RelativeLocation {
540 millimeters: Position {
541 x: movement_x / counts_per_mm as f32,
542 y: movement_y / counts_per_mm as f32,
543 },
544 })
545 };
546
547 send_mouse_event(
551 location,
552 None, None, MousePhase::Move,
555 current_buttons.union(&previous_buttons).cloned().collect(),
556 current_buttons.union(&previous_buttons).cloned().collect(),
557 device_descriptor,
558 input_event_sender,
559 inspect_status,
560 metrics_logger,
561 wake_lease.as_ref().map(|lease| {
562 lease
563 .duplicate_handle(zx::Rights::SAME_RIGHTS)
564 .expect("failed to duplicate event pair")
565 }),
566 );
567
568 let wheel_delta_v = match mouse_report.scroll_v {
569 None => None,
570 Some(ticks) => {
571 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
572 }
573 };
574
575 let wheel_delta_h = match mouse_report.scroll_h {
576 None => None,
577 Some(ticks) => {
578 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
579 }
580 };
581
582 send_mouse_event(
584 MouseLocation::Relative(Default::default()),
585 wheel_delta_v,
586 wheel_delta_h,
587 MousePhase::Wheel,
588 current_buttons.union(&previous_buttons).cloned().collect(),
589 current_buttons.union(&previous_buttons).cloned().collect(),
590 device_descriptor,
591 input_event_sender,
592 inspect_status,
593 metrics_logger,
594 wake_lease.as_ref().map(|lease| {
595 lease
596 .duplicate_handle(zx::Rights::SAME_RIGHTS)
597 .expect("failed to duplicate event pair")
598 }),
599 );
600
601 send_mouse_event(
607 MouseLocation::Relative(Default::default()),
608 None, None, MousePhase::Up,
611 previous_buttons.difference(¤t_buttons).cloned().collect(),
612 current_buttons.clone(),
613 device_descriptor,
614 input_event_sender,
615 inspect_status,
616 metrics_logger,
617 wake_lease,
618 );
619
620 Some(report)
621 }
622}
623
624fn send_mouse_event(
639 location: MouseLocation,
640 wheel_delta_v: Option<WheelDelta>,
641 wheel_delta_h: Option<WheelDelta>,
642 phase: MousePhase,
643 affected_buttons: HashSet<MouseButton>,
644 pressed_buttons: HashSet<MouseButton>,
645 device_descriptor: &input_device::InputDeviceDescriptor,
646 sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
647 inspect_status: &InputDeviceStatus,
648 metrics_logger: &metrics::MetricsLogger,
649 wake_lease: Option<zx::EventPair>,
650) {
651 if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
653 return;
654 }
655
656 if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
659 return;
660 }
661
662 if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
664 return;
665 }
666
667 let trace_id = fuchsia_trace::Id::random();
668 fuchsia_trace::duration!("input", "mouse-binding-send-event");
669 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
670
671 let event = input_device::InputEvent {
672 device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
673 location,
674 wheel_delta_v,
675 wheel_delta_h,
676 phase,
677 affected_buttons,
678 pressed_buttons,
679 match phase {
680 MousePhase::Wheel => Some(PrecisionScroll::No),
681 _ => None,
682 },
683 wake_lease,
684 )),
685 device_descriptor: device_descriptor.clone(),
686 event_time: zx::MonotonicInstant::get(),
687 handled: Handled::No,
688 trace_id: Some(trace_id),
689 };
690 let events = vec![event.clone_with_wake_lease()];
691
692 match sender.unbounded_send(events.clone()) {
693 Err(e) => {
694 metrics_logger.log_error(
695 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
696 std::format!("Failed to send MouseEvent with error: {:?}", e),
697 );
698 }
699 _ => inspect_status.count_generated_events(&events),
700 }
701}
702
703pub fn get_u32_from_buttons(buttons: &HashSet<MouseButton>) -> u32 {
717 let mut bits: u32 = 0;
718 for button in buttons {
719 if *button > 0 && *button <= fidl_input_report::MOUSE_MAX_NUM_BUTTONS as u8 {
720 bits = ((1 as u32) << *button - 1) | bits;
721 }
722 }
723
724 bits
725}
726
727fn buttons_from_report(input_report: &fidl_input_report::InputReport) -> HashSet<MouseButton> {
732 buttons_from_optional_report(&Some(input_report))
733}
734
735fn buttons_from_optional_report(
740 input_report: &Option<&fidl_input_report::InputReport>,
741) -> HashSet<MouseButton> {
742 input_report
743 .as_ref()
744 .and_then(|unwrapped_report| unwrapped_report.mouse.as_ref())
745 .and_then(|mouse_report| match &mouse_report.pressed_buttons {
746 Some(buttons) => Some(HashSet::from_iter(buttons.iter().cloned())),
747 None => None,
748 })
749 .unwrap_or_default()
750}
751
752#[cfg(test)]
753mod tests {
754 use super::*;
755 use crate::testing_utilities;
756 use fuchsia_async as fasync;
757 use futures::StreamExt;
758 use pretty_assertions::assert_eq;
759
760 const DEVICE_ID: u32 = 1;
761 const COUNTS_PER_MM: u32 = 12;
762
763 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
764 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
765 device_id,
766 absolute_x_range: None,
767 absolute_y_range: None,
768 wheel_v_range: Some(fidl_fuchsia_input_report::Axis {
769 range: fidl_input_report::Range { min: -1, max: 1 },
770 unit: fidl_input_report::Unit {
771 type_: fidl_input_report::UnitType::Other,
772 exponent: 1,
773 },
774 }),
775 wheel_h_range: Some(fidl_fuchsia_input_report::Axis {
776 range: fidl_input_report::Range { min: -1, max: 1 },
777 unit: fidl_input_report::Unit {
778 type_: fidl_input_report::UnitType::Other,
779 exponent: 1,
780 },
781 }),
782 buttons: None,
783 counts_per_mm: COUNTS_PER_MM,
784 })
785 }
786
787 fn wheel_delta_ticks(delta: i64) -> Option<WheelDelta> {
788 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(delta), physical_pixel: None })
789 }
790
791 #[test]
793 fn get_u32_from_buttons_test() {
794 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, 5].into_iter()));
795 assert_eq!(bits, 21 )
796 }
797
798 #[test]
800 fn get_u32_with_0_in_vector() {
801 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![0, 1, 3].into_iter()));
802 assert_eq!(bits, 5 )
803 }
804
805 #[test]
807 fn get_u32_with_empty_vector() {
808 let bits = get_u32_from_buttons(&HashSet::new());
809 assert_eq!(bits, 0 )
810 }
811
812 #[test]
814 fn get_u32_with_u8_max_in_vector() {
815 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, std::u8::MAX].into_iter()));
816 assert_eq!(bits, 5 )
817 }
818
819 #[test]
822 fn get_u32_with_max_mouse_buttons() {
823 let bits = get_u32_from_buttons(&HashSet::from_iter(
824 vec![1, 3, fidl_input_report::MOUSE_MAX_NUM_BUTTONS as MouseButton].into_iter(),
825 ));
826 assert_eq!(bits, 2147483653 )
827 }
828
829 #[fasync::run_singlethreaded(test)]
831 async fn movement_without_button() {
832 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
833 let first_report = testing_utilities::create_mouse_input_report_relative(
834 Position { x: 10.0, y: 16.0 },
835 None, None, vec![],
838 event_time_i64,
839 );
840 let descriptor = mouse_device_descriptor(DEVICE_ID);
841
842 let input_reports = vec![first_report];
843 let expected_events = vec![testing_utilities::create_mouse_event(
844 MouseLocation::Relative(RelativeLocation {
845 millimeters: Position {
846 x: 10.0 / COUNTS_PER_MM as f32,
847 y: 16.0 / COUNTS_PER_MM as f32,
848 },
849 }),
850 None, None, None, MousePhase::Move,
854 HashSet::new(),
855 HashSet::new(),
856 event_time_u64,
857 &descriptor,
858 )];
859
860 assert_input_report_sequence_generates_events!(
861 input_reports: input_reports,
862 expected_events: expected_events,
863 device_descriptor: descriptor,
864 device_type: MouseBinding,
865 );
866 }
867
868 #[fasync::run_singlethreaded(test)]
870 async fn down_without_movement() {
871 let mouse_button: MouseButton = 3;
872 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
873 let first_report = testing_utilities::create_mouse_input_report_relative(
874 Position::zero(),
875 None, None, vec![mouse_button],
878 event_time_i64,
879 );
880 let descriptor = mouse_device_descriptor(DEVICE_ID);
881
882 let input_reports = vec![first_report];
883 let expected_events = vec![testing_utilities::create_mouse_event(
884 MouseLocation::Relative(Default::default()),
885 None, None, None, MousePhase::Down,
889 HashSet::from_iter(vec![mouse_button].into_iter()),
890 HashSet::from_iter(vec![mouse_button].into_iter()),
891 event_time_u64,
892 &descriptor,
893 )];
894
895 assert_input_report_sequence_generates_events!(
896 input_reports: input_reports,
897 expected_events: expected_events,
898 device_descriptor: descriptor,
899 device_type: MouseBinding,
900 );
901 }
902
903 #[fasync::run_singlethreaded(test)]
906 async fn down_with_movement() {
907 let mouse_button: MouseButton = 3;
908 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
909 let first_report = testing_utilities::create_mouse_input_report_relative(
910 Position { x: 10.0, y: 16.0 },
911 None, None, vec![mouse_button],
914 event_time_i64,
915 );
916 let descriptor = mouse_device_descriptor(DEVICE_ID);
917
918 let input_reports = vec![first_report];
919 let expected_events = vec![
920 testing_utilities::create_mouse_event(
921 MouseLocation::Relative(Default::default()),
922 None, None, None, MousePhase::Down,
926 HashSet::from_iter(vec![mouse_button].into_iter()),
927 HashSet::from_iter(vec![mouse_button].into_iter()),
928 event_time_u64,
929 &descriptor,
930 ),
931 testing_utilities::create_mouse_event(
932 MouseLocation::Relative(RelativeLocation {
933 millimeters: Position {
934 x: 10.0 / COUNTS_PER_MM as f32,
935 y: 16.0 / COUNTS_PER_MM as f32,
936 },
937 }),
938 None, None, None, MousePhase::Move,
942 HashSet::from_iter(vec![mouse_button].into_iter()),
943 HashSet::from_iter(vec![mouse_button].into_iter()),
944 event_time_u64,
945 &descriptor,
946 ),
947 ];
948
949 assert_input_report_sequence_generates_events!(
950 input_reports: input_reports,
951 expected_events: expected_events,
952 device_descriptor: descriptor,
953 device_type: MouseBinding,
954 );
955 }
956
957 #[fasync::run_singlethreaded(test)]
959 async fn down_up() {
960 let button = 1;
961 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
962 let first_report = testing_utilities::create_mouse_input_report_relative(
963 Position::zero(),
964 None, None, vec![button],
967 event_time_i64,
968 );
969 let second_report = testing_utilities::create_mouse_input_report_relative(
970 Position::zero(),
971 None, None, vec![],
974 event_time_i64,
975 );
976 let descriptor = mouse_device_descriptor(DEVICE_ID);
977
978 let input_reports = vec![first_report, second_report];
979 let expected_events = vec![
980 testing_utilities::create_mouse_event(
981 MouseLocation::Relative(Default::default()),
982 None, None, None, MousePhase::Down,
986 HashSet::from_iter(vec![button].into_iter()),
987 HashSet::from_iter(vec![button].into_iter()),
988 event_time_u64,
989 &descriptor,
990 ),
991 testing_utilities::create_mouse_event(
992 MouseLocation::Relative(Default::default()),
993 None, None, None, MousePhase::Up,
997 HashSet::from_iter(vec![button].into_iter()),
998 HashSet::new(),
999 event_time_u64,
1000 &descriptor,
1001 ),
1002 ];
1003
1004 assert_input_report_sequence_generates_events!(
1005 input_reports: input_reports,
1006 expected_events: expected_events,
1007 device_descriptor: descriptor,
1008 device_type: MouseBinding,
1009 );
1010 }
1011
1012 #[fasync::run_singlethreaded(test)]
1014 async fn down_up_with_movement() {
1015 let button = 1;
1016
1017 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1018 let first_report = testing_utilities::create_mouse_input_report_relative(
1019 Position::zero(),
1020 None, None, vec![button],
1023 event_time_i64,
1024 );
1025 let second_report = testing_utilities::create_mouse_input_report_relative(
1026 Position { x: 10.0, y: 16.0 },
1027 None, None, vec![],
1030 event_time_i64,
1031 );
1032 let descriptor = mouse_device_descriptor(DEVICE_ID);
1033
1034 let input_reports = vec![first_report, second_report];
1035 let expected_events = vec![
1036 testing_utilities::create_mouse_event(
1037 MouseLocation::Relative(Default::default()),
1038 None, None, None, MousePhase::Down,
1042 HashSet::from_iter(vec![button].into_iter()),
1043 HashSet::from_iter(vec![button].into_iter()),
1044 event_time_u64,
1045 &descriptor,
1046 ),
1047 testing_utilities::create_mouse_event(
1048 MouseLocation::Relative(RelativeLocation {
1049 millimeters: Position {
1050 x: 10.0 / COUNTS_PER_MM as f32,
1051 y: 16.0 / COUNTS_PER_MM as f32,
1052 },
1053 }),
1054 None, None, None, MousePhase::Move,
1058 HashSet::from_iter(vec![button].into_iter()),
1059 HashSet::from_iter(vec![button].into_iter()),
1060 event_time_u64,
1061 &descriptor,
1062 ),
1063 testing_utilities::create_mouse_event(
1064 MouseLocation::Relative(Default::default()),
1065 None, None, None, MousePhase::Up,
1069 HashSet::from_iter(vec![button].into_iter()),
1070 HashSet::new(),
1071 event_time_u64,
1072 &descriptor,
1073 ),
1074 ];
1075
1076 assert_input_report_sequence_generates_events!(
1077 input_reports: input_reports,
1078 expected_events: expected_events,
1079 device_descriptor: descriptor,
1080 device_type: MouseBinding,
1081 );
1082 }
1083
1084 #[fasync::run_singlethreaded(test)]
1088 async fn down_move_up() {
1089 let button = 1;
1090
1091 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1092 let first_report = testing_utilities::create_mouse_input_report_relative(
1093 Position::zero(),
1094 None, None, vec![button],
1097 event_time_i64,
1098 );
1099 let second_report = testing_utilities::create_mouse_input_report_relative(
1100 Position { x: 10.0, y: 16.0 },
1101 None, None, vec![button],
1104 event_time_i64,
1105 );
1106 let third_report = testing_utilities::create_mouse_input_report_relative(
1107 Position::zero(),
1108 None, None, vec![],
1111 event_time_i64,
1112 );
1113 let descriptor = mouse_device_descriptor(DEVICE_ID);
1114
1115 let input_reports = vec![first_report, second_report, third_report];
1116 let expected_events = vec![
1117 testing_utilities::create_mouse_event(
1118 MouseLocation::Relative(Default::default()),
1119 None, None, None, MousePhase::Down,
1123 HashSet::from_iter(vec![button].into_iter()),
1124 HashSet::from_iter(vec![button].into_iter()),
1125 event_time_u64,
1126 &descriptor,
1127 ),
1128 testing_utilities::create_mouse_event(
1129 MouseLocation::Relative(RelativeLocation {
1130 millimeters: Position {
1131 x: 10.0 / COUNTS_PER_MM as f32,
1132 y: 16.0 / COUNTS_PER_MM as f32,
1133 },
1134 }),
1135 None, None, None, MousePhase::Move,
1139 HashSet::from_iter(vec![button].into_iter()),
1140 HashSet::from_iter(vec![button].into_iter()),
1141 event_time_u64,
1142 &descriptor,
1143 ),
1144 testing_utilities::create_mouse_event(
1145 MouseLocation::Relative(Default::default()),
1146 None, None, None, MousePhase::Up,
1150 HashSet::from_iter(vec![button].into_iter()),
1151 HashSet::new(),
1152 event_time_u64,
1153 &descriptor,
1154 ),
1155 ];
1156
1157 assert_input_report_sequence_generates_events!(
1158 input_reports: input_reports,
1159 expected_events: expected_events,
1160 device_descriptor: descriptor,
1161 device_type: MouseBinding,
1162 );
1163 }
1164
1165 #[fasync::run_until_stalled(test)]
1167 async fn absolute_movement_to_origin() {
1168 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1169 let descriptor = mouse_device_descriptor(DEVICE_ID);
1170
1171 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
1172 Position::zero(),
1173 None, None, vec![],
1176 event_time_i64,
1177 )];
1178 let expected_events = vec![testing_utilities::create_mouse_event(
1179 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1180 None, None, None, MousePhase::Move,
1184 HashSet::new(),
1185 HashSet::new(),
1186 event_time_u64,
1187 &descriptor,
1188 )];
1189
1190 assert_input_report_sequence_generates_events!(
1191 input_reports: input_reports,
1192 expected_events: expected_events,
1193 device_descriptor: descriptor,
1194 device_type: MouseBinding,
1195 );
1196 }
1197
1198 #[fasync::run_until_stalled(test)]
1201 async fn report_with_both_movement_and_position() {
1202 let relative_movement = Position { x: 5.0, y: 5.0 };
1203 let absolute_position = Position { x: 10.0, y: 10.0 };
1204 let expected_location = MouseLocation::Absolute(absolute_position);
1205
1206 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1207 let descriptor = mouse_device_descriptor(DEVICE_ID);
1208
1209 let input_reports = vec![fidl_input_report::InputReport {
1210 event_time: Some(event_time_i64),
1211 keyboard: None,
1212 mouse: Some(fidl_input_report::MouseInputReport {
1213 movement_x: Some(relative_movement.x as i64),
1214 movement_y: Some(relative_movement.y as i64),
1215 position_x: Some(absolute_position.x as i64),
1216 position_y: Some(absolute_position.y as i64),
1217 scroll_h: None,
1218 scroll_v: None,
1219 pressed_buttons: None,
1220 ..Default::default()
1221 }),
1222 touch: None,
1223 sensor: None,
1224 consumer_control: None,
1225 trace_id: None,
1226 ..Default::default()
1227 }];
1228 let expected_events = vec![testing_utilities::create_mouse_event(
1229 expected_location,
1230 None, None, None, MousePhase::Move,
1234 HashSet::new(),
1235 HashSet::new(),
1236 event_time_u64,
1237 &descriptor,
1238 )];
1239
1240 assert_input_report_sequence_generates_events!(
1241 input_reports: input_reports,
1242 expected_events: expected_events,
1243 device_descriptor: descriptor,
1244 device_type: MouseBinding,
1245 );
1246 }
1247
1248 #[fasync::run_singlethreaded(test)]
1251 async fn down_down() {
1252 const PRIMARY_BUTTON: u8 = 1;
1253 const SECONDARY_BUTTON: u8 = 2;
1254
1255 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1256 let first_report = testing_utilities::create_mouse_input_report_relative(
1257 Position::zero(),
1258 None, None, vec![PRIMARY_BUTTON],
1261 event_time_i64,
1262 );
1263 let second_report = testing_utilities::create_mouse_input_report_relative(
1264 Position::zero(),
1265 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1268 event_time_i64,
1269 );
1270 let descriptor = mouse_device_descriptor(DEVICE_ID);
1271
1272 let input_reports = vec![first_report, second_report];
1273 let expected_events = vec![
1274 testing_utilities::create_mouse_event(
1275 MouseLocation::Relative(Default::default()),
1276 None, None, None, MousePhase::Down,
1280 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1281 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1282 event_time_u64,
1283 &descriptor,
1284 ),
1285 testing_utilities::create_mouse_event(
1286 MouseLocation::Relative(Default::default()),
1287 None, None, None, MousePhase::Down,
1291 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1292 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1293 event_time_u64,
1294 &descriptor,
1295 ),
1296 ];
1297
1298 assert_input_report_sequence_generates_events!(
1299 input_reports: input_reports,
1300 expected_events: expected_events,
1301 device_descriptor: descriptor,
1302 device_type: MouseBinding,
1303 );
1304 }
1305
1306 #[fasync::run_singlethreaded(test)]
1316 async fn down_down_up_up() {
1317 const PRIMARY_BUTTON: u8 = 1;
1318 const SECONDARY_BUTTON: u8 = 2;
1319
1320 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1321 let first_report = testing_utilities::create_mouse_input_report_relative(
1322 Position::zero(),
1323 None, None, vec![PRIMARY_BUTTON],
1326 event_time_i64,
1327 );
1328 let second_report = testing_utilities::create_mouse_input_report_relative(
1329 Position::zero(),
1330 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1333 event_time_i64,
1334 );
1335 let third_report = testing_utilities::create_mouse_input_report_relative(
1336 Position::zero(),
1337 None, None, vec![SECONDARY_BUTTON],
1340 event_time_i64,
1341 );
1342 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1343 Position::zero(),
1344 None, None, vec![],
1347 event_time_i64,
1348 );
1349 let descriptor = mouse_device_descriptor(DEVICE_ID);
1350
1351 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1352 let expected_events = vec![
1353 testing_utilities::create_mouse_event(
1354 MouseLocation::Relative(Default::default()),
1355 None, None, None, MousePhase::Down,
1359 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1360 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1361 event_time_u64,
1362 &descriptor,
1363 ),
1364 testing_utilities::create_mouse_event(
1365 MouseLocation::Relative(Default::default()),
1366 None, None, None, MousePhase::Down,
1370 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1371 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1372 event_time_u64,
1373 &descriptor,
1374 ),
1375 testing_utilities::create_mouse_event(
1376 MouseLocation::Relative(Default::default()),
1377 None, None, None, MousePhase::Up,
1381 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1382 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1383 event_time_u64,
1384 &descriptor,
1385 ),
1386 testing_utilities::create_mouse_event(
1387 MouseLocation::Relative(Default::default()),
1388 None, None, None, MousePhase::Up,
1392 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1393 HashSet::new(),
1394 event_time_u64,
1395 &descriptor,
1396 ),
1397 ];
1398
1399 assert_input_report_sequence_generates_events!(
1400 input_reports: input_reports,
1401 expected_events: expected_events,
1402 device_descriptor: descriptor,
1403 device_type: MouseBinding,
1404 );
1405 }
1406
1407 #[fasync::run_singlethreaded(test)]
1409 async fn scroll() {
1410 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1411 let first_report = testing_utilities::create_mouse_input_report_relative(
1412 Position::zero(),
1413 Some(1),
1414 None,
1415 vec![],
1416 event_time_i64,
1417 );
1418 let second_report = testing_utilities::create_mouse_input_report_relative(
1419 Position::zero(),
1420 None,
1421 Some(1),
1422 vec![],
1423 event_time_i64,
1424 );
1425
1426 let descriptor = mouse_device_descriptor(DEVICE_ID);
1427
1428 let input_reports = vec![first_report, second_report];
1429 let expected_events = vec![
1430 testing_utilities::create_mouse_event(
1431 MouseLocation::Relative(Default::default()),
1432 wheel_delta_ticks(1),
1433 None,
1434 Some(PrecisionScroll::No),
1435 MousePhase::Wheel,
1436 HashSet::new(),
1437 HashSet::new(),
1438 event_time_u64,
1439 &descriptor,
1440 ),
1441 testing_utilities::create_mouse_event(
1442 MouseLocation::Relative(Default::default()),
1443 None,
1444 wheel_delta_ticks(1),
1445 Some(PrecisionScroll::No),
1446 MousePhase::Wheel,
1447 HashSet::new(),
1448 HashSet::new(),
1449 event_time_u64,
1450 &descriptor,
1451 ),
1452 ];
1453
1454 assert_input_report_sequence_generates_events!(
1455 input_reports: input_reports,
1456 expected_events: expected_events,
1457 device_descriptor: descriptor,
1458 device_type: MouseBinding,
1459 );
1460 }
1461
1462 #[fasync::run_singlethreaded(test)]
1464 async fn down_scroll_up_scroll() {
1465 const PRIMARY_BUTTON: u8 = 1;
1466
1467 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1468 let first_report = testing_utilities::create_mouse_input_report_relative(
1469 Position::zero(),
1470 None, None, vec![PRIMARY_BUTTON],
1473 event_time_i64,
1474 );
1475 let second_report = testing_utilities::create_mouse_input_report_relative(
1476 Position::zero(),
1477 Some(1),
1478 None,
1479 vec![PRIMARY_BUTTON],
1480 event_time_i64,
1481 );
1482 let third_report = testing_utilities::create_mouse_input_report_relative(
1483 Position::zero(),
1484 None, None, vec![],
1487 event_time_i64,
1488 );
1489 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1490 Position::zero(),
1491 Some(1),
1492 None,
1493 vec![],
1494 event_time_i64,
1495 );
1496
1497 let descriptor = mouse_device_descriptor(DEVICE_ID);
1498
1499 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1500 let expected_events = vec![
1501 testing_utilities::create_mouse_event(
1502 MouseLocation::Relative(Default::default()),
1503 None, None, None, MousePhase::Down,
1507 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1508 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1509 event_time_u64,
1510 &descriptor,
1511 ),
1512 testing_utilities::create_mouse_event(
1513 MouseLocation::Relative(Default::default()),
1514 wheel_delta_ticks(1),
1515 None,
1516 Some(PrecisionScroll::No),
1517 MousePhase::Wheel,
1518 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1519 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1520 event_time_u64,
1521 &descriptor,
1522 ),
1523 testing_utilities::create_mouse_event(
1524 MouseLocation::Relative(Default::default()),
1525 None, None, None, MousePhase::Up,
1529 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1530 HashSet::new(),
1531 event_time_u64,
1532 &descriptor,
1533 ),
1534 testing_utilities::create_mouse_event(
1535 MouseLocation::Relative(Default::default()),
1536 wheel_delta_ticks(1),
1537 None,
1538 Some(PrecisionScroll::No),
1539 MousePhase::Wheel,
1540 HashSet::new(),
1541 HashSet::new(),
1542 event_time_u64,
1543 &descriptor,
1544 ),
1545 ];
1546
1547 assert_input_report_sequence_generates_events!(
1548 input_reports: input_reports,
1549 expected_events: expected_events,
1550 device_descriptor: descriptor,
1551 device_type: MouseBinding,
1552 );
1553 }
1554
1555 #[fasync::run_singlethreaded(test)]
1557 async fn down_scroll_bundle_up_scroll_bundle() {
1558 const PRIMARY_BUTTON: u8 = 1;
1559
1560 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1561 let first_report = testing_utilities::create_mouse_input_report_relative(
1562 Position::zero(),
1563 Some(1),
1564 None,
1565 vec![PRIMARY_BUTTON],
1566 event_time_i64,
1567 );
1568 let second_report = testing_utilities::create_mouse_input_report_relative(
1569 Position::zero(),
1570 Some(1),
1571 None,
1572 vec![],
1573 event_time_i64,
1574 );
1575 let third_report = testing_utilities::create_mouse_input_report_relative(
1576 Position::zero(),
1577 Some(1),
1578 None,
1579 vec![],
1580 event_time_i64,
1581 );
1582
1583 let descriptor = mouse_device_descriptor(DEVICE_ID);
1584
1585 let input_reports = vec![first_report, second_report, third_report];
1586 let expected_events = vec![
1587 testing_utilities::create_mouse_event(
1588 MouseLocation::Relative(Default::default()),
1589 None, None, None, MousePhase::Down,
1593 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1594 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1595 event_time_u64,
1596 &descriptor,
1597 ),
1598 testing_utilities::create_mouse_event(
1599 MouseLocation::Relative(Default::default()),
1600 wheel_delta_ticks(1),
1601 None,
1602 Some(PrecisionScroll::No),
1603 MousePhase::Wheel,
1604 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1605 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1606 event_time_u64,
1607 &descriptor,
1608 ),
1609 testing_utilities::create_mouse_event(
1610 MouseLocation::Relative(Default::default()),
1611 wheel_delta_ticks(1),
1612 None,
1613 Some(PrecisionScroll::No),
1614 MousePhase::Wheel,
1615 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1616 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1617 event_time_u64,
1618 &descriptor,
1619 ),
1620 testing_utilities::create_mouse_event(
1621 MouseLocation::Relative(Default::default()),
1622 None, None, None, MousePhase::Up,
1626 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1627 HashSet::new(),
1628 event_time_u64,
1629 &descriptor,
1630 ),
1631 testing_utilities::create_mouse_event(
1632 MouseLocation::Relative(Default::default()),
1633 wheel_delta_ticks(1),
1634 None,
1635 Some(PrecisionScroll::No),
1636 MousePhase::Wheel,
1637 HashSet::new(),
1638 HashSet::new(),
1639 event_time_u64,
1640 &descriptor,
1641 ),
1642 ];
1643
1644 assert_input_report_sequence_generates_events!(
1645 input_reports: input_reports,
1646 expected_events: expected_events,
1647 device_descriptor: descriptor,
1648 device_type: MouseBinding,
1649 );
1650 }
1651}