1use crate::input_device::{self, Handled, InputDeviceBinding, InputDeviceStatus, InputEvent};
6use crate::utils::{self, Position};
7use crate::{Transport, metrics, mouse_model_database};
8use anyhow::{Error, format_err};
9use async_trait::async_trait;
10use fidl::HandleBased;
11use fidl_next_fuchsia_input_report::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: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
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: &fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
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_next_fuchsia_input_report::DeviceDescriptor = match device
384 .get_descriptor()
385 .await
386 {
387 Ok(res) => res.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
413 .position_x
414 .as_ref()
415 .map(|axis| utils::range_to_old(&axis.range)),
416 absolute_y_range: mouse_input_descriptor
417 .position_y
418 .as_ref()
419 .map(|axis| utils::range_to_old(&axis.range)),
420 wheel_v_range: utils::axis_to_old(mouse_input_descriptor.scroll_v.as_ref()),
421 wheel_h_range: utils::axis_to_old(mouse_input_descriptor.scroll_h.as_ref()),
422 buttons: mouse_input_descriptor.buttons,
423 counts_per_mm: model.counts_per_mm,
424 };
425
426 Ok((Self { event_sender: input_event_sender, device_descriptor }, input_device_status))
427 }
428
429 fn process_reports(
451 reports: Vec<InputReport>,
452 mut previous_report: Option<InputReport>,
453 device_descriptor: &input_device::InputDeviceDescriptor,
454 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
455 inspect_status: &InputDeviceStatus,
456 metrics_logger: &metrics::MetricsLogger,
457 _feature_flags: &input_device::InputPipelineFeatureFlags,
458 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
459 fuchsia_trace::duration!("input", "mouse-binding-process-reports", "num_reports" => reports.len());
460 for report in reports {
461 previous_report = Self::process_report(
462 report,
463 previous_report,
464 device_descriptor,
465 input_event_sender,
466 inspect_status,
467 metrics_logger,
468 );
469 }
470 (previous_report, None)
471 }
472
473 fn process_report(
474 mut report: InputReport,
475 previous_report: Option<InputReport>,
476 device_descriptor: &input_device::InputDeviceDescriptor,
477 input_event_sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
478 inspect_status: &InputDeviceStatus,
479 metrics_logger: &metrics::MetricsLogger,
480 ) -> Option<InputReport> {
481 if let Some(trace_id) = report.trace_id {
482 fuchsia_trace::flow_end!("input", "input_report", trace_id.into());
483 }
484
485 let wake_lease = report.wake_lease.take();
489
490 inspect_status.count_received_report(&report);
491 let mouse_report: &fidl_next_fuchsia_input_report::MouseInputReport = match &report.mouse {
493 Some(mouse) => mouse,
494 None => {
495 inspect_status.count_filtered_report();
496 return previous_report;
497 }
498 };
499
500 let previous_buttons: HashSet<MouseButton> =
501 buttons_from_optional_report(&previous_report.as_ref());
502 let current_buttons: HashSet<MouseButton> = buttons_from_report(&report);
503
504 send_mouse_event(
510 MouseLocation::Relative(Default::default()),
511 None, None, MousePhase::Down,
514 current_buttons.difference(&previous_buttons).cloned().collect(),
515 current_buttons.clone(),
516 device_descriptor,
517 input_event_sender,
518 inspect_status,
519 metrics_logger,
520 wake_lease.as_ref().map(|lease| {
521 lease
522 .duplicate_handle(zx::Rights::SAME_RIGHTS)
523 .expect("failed to duplicate event pair")
524 }),
525 );
526
527 let counts_per_mm = match device_descriptor {
528 input_device::InputDeviceDescriptor::Mouse(ds) => ds.counts_per_mm,
529 _ => {
530 metrics_logger.log_error(
531 InputPipelineErrorMetricDimensionEvent::MouseDescriptionNotMouse,
532 "mouse_binding::process_reports got device_descriptor not mouse".to_string(),
533 );
534 mouse_model_database::db::DEFAULT_COUNTS_PER_MM
535 }
536 };
537
538 let location = if let (Some(position_x), Some(position_y)) =
540 (mouse_report.position_x, mouse_report.position_y)
541 {
542 MouseLocation::Absolute(Position { x: position_x as f32, y: position_y as f32 })
543 } else {
544 let movement_x = mouse_report.movement_x.unwrap_or_default() as f32;
545 let movement_y = mouse_report.movement_y.unwrap_or_default() as f32;
546 MouseLocation::Relative(RelativeLocation {
547 millimeters: Position {
548 x: movement_x / counts_per_mm as f32,
549 y: movement_y / counts_per_mm as f32,
550 },
551 })
552 };
553
554 send_mouse_event(
558 location,
559 None, None, MousePhase::Move,
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 let wheel_delta_v = match mouse_report.scroll_v {
576 None => None,
577 Some(ticks) => {
578 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
579 }
580 };
581
582 let wheel_delta_h = match mouse_report.scroll_h {
583 None => None,
584 Some(ticks) => {
585 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
586 }
587 };
588
589 send_mouse_event(
591 MouseLocation::Relative(Default::default()),
592 wheel_delta_v,
593 wheel_delta_h,
594 MousePhase::Wheel,
595 current_buttons.union(&previous_buttons).cloned().collect(),
596 current_buttons.union(&previous_buttons).cloned().collect(),
597 device_descriptor,
598 input_event_sender,
599 inspect_status,
600 metrics_logger,
601 wake_lease.as_ref().map(|lease| {
602 lease
603 .duplicate_handle(zx::Rights::SAME_RIGHTS)
604 .expect("failed to duplicate event pair")
605 }),
606 );
607
608 send_mouse_event(
614 MouseLocation::Relative(Default::default()),
615 None, None, MousePhase::Up,
618 previous_buttons.difference(¤t_buttons).cloned().collect(),
619 current_buttons.clone(),
620 device_descriptor,
621 input_event_sender,
622 inspect_status,
623 metrics_logger,
624 wake_lease,
625 );
626
627 Some(report)
628 }
629}
630
631fn send_mouse_event(
646 location: MouseLocation,
647 wheel_delta_v: Option<WheelDelta>,
648 wheel_delta_h: Option<WheelDelta>,
649 phase: MousePhase,
650 affected_buttons: HashSet<MouseButton>,
651 pressed_buttons: HashSet<MouseButton>,
652 device_descriptor: &input_device::InputDeviceDescriptor,
653 sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
654 inspect_status: &InputDeviceStatus,
655 metrics_logger: &metrics::MetricsLogger,
656 wake_lease: Option<zx::EventPair>,
657) {
658 if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
660 return;
661 }
662
663 if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
666 return;
667 }
668
669 if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
671 return;
672 }
673
674 let trace_id = fuchsia_trace::Id::random();
675 fuchsia_trace::duration!("input", "mouse-binding-send-event");
676 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
677
678 let event = input_device::InputEvent {
679 device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
680 location,
681 wheel_delta_v,
682 wheel_delta_h,
683 phase,
684 affected_buttons,
685 pressed_buttons,
686 match phase {
687 MousePhase::Wheel => Some(PrecisionScroll::No),
688 _ => None,
689 },
690 wake_lease,
691 )),
692 device_descriptor: device_descriptor.clone(),
693 event_time: zx::MonotonicInstant::get(),
694 handled: Handled::No,
695 trace_id: Some(trace_id),
696 };
697 let events = vec![event.clone_with_wake_lease()];
698
699 match sender.unbounded_send(events.clone()) {
700 Err(e) => {
701 metrics_logger.log_error(
702 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
703 std::format!("Failed to send MouseEvent with error: {:?}", e),
704 );
705 }
706 _ => inspect_status.count_generated_events(&events),
707 }
708}
709
710pub fn get_u32_from_buttons(buttons: &HashSet<MouseButton>) -> u32 {
724 let mut bits: u32 = 0;
725 for button in buttons {
726 if *button > 0 && *button <= fidl_input_report::MOUSE_MAX_NUM_BUTTONS as u8 {
727 bits = ((1 as u32) << *button - 1) | bits;
728 }
729 }
730
731 bits
732}
733
734fn buttons_from_report(
739 input_report: &fidl_next_fuchsia_input_report::InputReport,
740) -> HashSet<MouseButton> {
741 buttons_from_optional_report(&Some(input_report))
742}
743
744fn buttons_from_optional_report(
749 input_report: &Option<&fidl_next_fuchsia_input_report::InputReport>,
750) -> HashSet<MouseButton> {
751 input_report
752 .as_ref()
753 .and_then(|unwrapped_report| unwrapped_report.mouse.as_ref())
754 .and_then(|mouse_report| match &mouse_report.pressed_buttons {
755 Some(buttons) => Some(HashSet::from_iter(buttons.iter().cloned())),
756 None => None,
757 })
758 .unwrap_or_default()
759}
760
761#[cfg(test)]
762mod tests {
763 use super::*;
764 use crate::testing_utilities;
765 use fuchsia_async as fasync;
766 use futures::StreamExt;
767 use pretty_assertions::assert_eq;
768
769 const DEVICE_ID: u32 = 1;
770 const COUNTS_PER_MM: u32 = 12;
771
772 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
773 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
774 device_id,
775 absolute_x_range: None,
776 absolute_y_range: None,
777 wheel_v_range: Some(fidl_fuchsia_input_report::Axis {
778 range: fidl_input_report::Range { min: -1, max: 1 },
779 unit: fidl_input_report::Unit {
780 type_: fidl_input_report::UnitType::Other,
781 exponent: 1,
782 },
783 }),
784 wheel_h_range: Some(fidl_fuchsia_input_report::Axis {
785 range: fidl_input_report::Range { min: -1, max: 1 },
786 unit: fidl_input_report::Unit {
787 type_: fidl_input_report::UnitType::Other,
788 exponent: 1,
789 },
790 }),
791 buttons: None,
792 counts_per_mm: COUNTS_PER_MM,
793 })
794 }
795
796 fn wheel_delta_ticks(delta: i64) -> Option<WheelDelta> {
797 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(delta), physical_pixel: None })
798 }
799
800 #[test]
802 fn get_u32_from_buttons_test() {
803 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, 5].into_iter()));
804 assert_eq!(bits, 21 )
805 }
806
807 #[test]
809 fn get_u32_with_0_in_vector() {
810 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![0, 1, 3].into_iter()));
811 assert_eq!(bits, 5 )
812 }
813
814 #[test]
816 fn get_u32_with_empty_vector() {
817 let bits = get_u32_from_buttons(&HashSet::new());
818 assert_eq!(bits, 0 )
819 }
820
821 #[test]
823 fn get_u32_with_u8_max_in_vector() {
824 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, std::u8::MAX].into_iter()));
825 assert_eq!(bits, 5 )
826 }
827
828 #[test]
831 fn get_u32_with_max_mouse_buttons() {
832 let bits = get_u32_from_buttons(&HashSet::from_iter(
833 vec![1, 3, fidl_input_report::MOUSE_MAX_NUM_BUTTONS as MouseButton].into_iter(),
834 ));
835 assert_eq!(bits, 2147483653 )
836 }
837
838 #[fasync::run_singlethreaded(test)]
840 async fn movement_without_button() {
841 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
842 let first_report = testing_utilities::create_mouse_input_report_relative(
843 Position { x: 10.0, y: 16.0 },
844 None, None, vec![],
847 event_time_i64,
848 );
849 let descriptor = mouse_device_descriptor(DEVICE_ID);
850
851 let input_reports = vec![first_report];
852 let expected_events = vec![testing_utilities::create_mouse_event(
853 MouseLocation::Relative(RelativeLocation {
854 millimeters: Position {
855 x: 10.0 / COUNTS_PER_MM as f32,
856 y: 16.0 / COUNTS_PER_MM as f32,
857 },
858 }),
859 None, None, None, MousePhase::Move,
863 HashSet::new(),
864 HashSet::new(),
865 event_time_u64,
866 &descriptor,
867 )];
868
869 assert_input_report_sequence_generates_events!(
870 input_reports: input_reports,
871 expected_events: expected_events,
872 device_descriptor: descriptor,
873 device_type: MouseBinding,
874 );
875 }
876
877 #[fasync::run_singlethreaded(test)]
879 async fn down_without_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::zero(),
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![testing_utilities::create_mouse_event(
893 MouseLocation::Relative(Default::default()),
894 None, None, None, MousePhase::Down,
898 HashSet::from_iter(vec![mouse_button].into_iter()),
899 HashSet::from_iter(vec![mouse_button].into_iter()),
900 event_time_u64,
901 &descriptor,
902 )];
903
904 assert_input_report_sequence_generates_events!(
905 input_reports: input_reports,
906 expected_events: expected_events,
907 device_descriptor: descriptor,
908 device_type: MouseBinding,
909 );
910 }
911
912 #[fasync::run_singlethreaded(test)]
915 async fn down_with_movement() {
916 let mouse_button: MouseButton = 3;
917 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
918 let first_report = testing_utilities::create_mouse_input_report_relative(
919 Position { x: 10.0, y: 16.0 },
920 None, None, vec![mouse_button],
923 event_time_i64,
924 );
925 let descriptor = mouse_device_descriptor(DEVICE_ID);
926
927 let input_reports = vec![first_report];
928 let expected_events = vec![
929 testing_utilities::create_mouse_event(
930 MouseLocation::Relative(Default::default()),
931 None, None, None, MousePhase::Down,
935 HashSet::from_iter(vec![mouse_button].into_iter()),
936 HashSet::from_iter(vec![mouse_button].into_iter()),
937 event_time_u64,
938 &descriptor,
939 ),
940 testing_utilities::create_mouse_event(
941 MouseLocation::Relative(RelativeLocation {
942 millimeters: Position {
943 x: 10.0 / COUNTS_PER_MM as f32,
944 y: 16.0 / COUNTS_PER_MM as f32,
945 },
946 }),
947 None, None, None, MousePhase::Move,
951 HashSet::from_iter(vec![mouse_button].into_iter()),
952 HashSet::from_iter(vec![mouse_button].into_iter()),
953 event_time_u64,
954 &descriptor,
955 ),
956 ];
957
958 assert_input_report_sequence_generates_events!(
959 input_reports: input_reports,
960 expected_events: expected_events,
961 device_descriptor: descriptor,
962 device_type: MouseBinding,
963 );
964 }
965
966 #[fasync::run_singlethreaded(test)]
968 async fn down_up() {
969 let button = 1;
970 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
971 let first_report = testing_utilities::create_mouse_input_report_relative(
972 Position::zero(),
973 None, None, vec![button],
976 event_time_i64,
977 );
978 let second_report = testing_utilities::create_mouse_input_report_relative(
979 Position::zero(),
980 None, None, vec![],
983 event_time_i64,
984 );
985 let descriptor = mouse_device_descriptor(DEVICE_ID);
986
987 let input_reports = vec![first_report, second_report];
988 let expected_events = vec![
989 testing_utilities::create_mouse_event(
990 MouseLocation::Relative(Default::default()),
991 None, None, None, MousePhase::Down,
995 HashSet::from_iter(vec![button].into_iter()),
996 HashSet::from_iter(vec![button].into_iter()),
997 event_time_u64,
998 &descriptor,
999 ),
1000 testing_utilities::create_mouse_event(
1001 MouseLocation::Relative(Default::default()),
1002 None, None, None, MousePhase::Up,
1006 HashSet::from_iter(vec![button].into_iter()),
1007 HashSet::new(),
1008 event_time_u64,
1009 &descriptor,
1010 ),
1011 ];
1012
1013 assert_input_report_sequence_generates_events!(
1014 input_reports: input_reports,
1015 expected_events: expected_events,
1016 device_descriptor: descriptor,
1017 device_type: MouseBinding,
1018 );
1019 }
1020
1021 #[fasync::run_singlethreaded(test)]
1023 async fn down_up_with_movement() {
1024 let button = 1;
1025
1026 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1027 let first_report = testing_utilities::create_mouse_input_report_relative(
1028 Position::zero(),
1029 None, None, vec![button],
1032 event_time_i64,
1033 );
1034 let second_report = testing_utilities::create_mouse_input_report_relative(
1035 Position { x: 10.0, y: 16.0 },
1036 None, None, vec![],
1039 event_time_i64,
1040 );
1041 let descriptor = mouse_device_descriptor(DEVICE_ID);
1042
1043 let input_reports = vec![first_report, second_report];
1044 let expected_events = vec![
1045 testing_utilities::create_mouse_event(
1046 MouseLocation::Relative(Default::default()),
1047 None, None, None, MousePhase::Down,
1051 HashSet::from_iter(vec![button].into_iter()),
1052 HashSet::from_iter(vec![button].into_iter()),
1053 event_time_u64,
1054 &descriptor,
1055 ),
1056 testing_utilities::create_mouse_event(
1057 MouseLocation::Relative(RelativeLocation {
1058 millimeters: Position {
1059 x: 10.0 / COUNTS_PER_MM as f32,
1060 y: 16.0 / COUNTS_PER_MM as f32,
1061 },
1062 }),
1063 None, None, None, MousePhase::Move,
1067 HashSet::from_iter(vec![button].into_iter()),
1068 HashSet::from_iter(vec![button].into_iter()),
1069 event_time_u64,
1070 &descriptor,
1071 ),
1072 testing_utilities::create_mouse_event(
1073 MouseLocation::Relative(Default::default()),
1074 None, None, None, MousePhase::Up,
1078 HashSet::from_iter(vec![button].into_iter()),
1079 HashSet::new(),
1080 event_time_u64,
1081 &descriptor,
1082 ),
1083 ];
1084
1085 assert_input_report_sequence_generates_events!(
1086 input_reports: input_reports,
1087 expected_events: expected_events,
1088 device_descriptor: descriptor,
1089 device_type: MouseBinding,
1090 );
1091 }
1092
1093 #[fasync::run_singlethreaded(test)]
1097 async fn down_move_up() {
1098 let button = 1;
1099
1100 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1101 let first_report = testing_utilities::create_mouse_input_report_relative(
1102 Position::zero(),
1103 None, None, vec![button],
1106 event_time_i64,
1107 );
1108 let second_report = testing_utilities::create_mouse_input_report_relative(
1109 Position { x: 10.0, y: 16.0 },
1110 None, None, vec![button],
1113 event_time_i64,
1114 );
1115 let third_report = testing_utilities::create_mouse_input_report_relative(
1116 Position::zero(),
1117 None, None, vec![],
1120 event_time_i64,
1121 );
1122 let descriptor = mouse_device_descriptor(DEVICE_ID);
1123
1124 let input_reports = vec![first_report, second_report, third_report];
1125 let expected_events = vec![
1126 testing_utilities::create_mouse_event(
1127 MouseLocation::Relative(Default::default()),
1128 None, None, None, MousePhase::Down,
1132 HashSet::from_iter(vec![button].into_iter()),
1133 HashSet::from_iter(vec![button].into_iter()),
1134 event_time_u64,
1135 &descriptor,
1136 ),
1137 testing_utilities::create_mouse_event(
1138 MouseLocation::Relative(RelativeLocation {
1139 millimeters: Position {
1140 x: 10.0 / COUNTS_PER_MM as f32,
1141 y: 16.0 / COUNTS_PER_MM as f32,
1142 },
1143 }),
1144 None, None, None, MousePhase::Move,
1148 HashSet::from_iter(vec![button].into_iter()),
1149 HashSet::from_iter(vec![button].into_iter()),
1150 event_time_u64,
1151 &descriptor,
1152 ),
1153 testing_utilities::create_mouse_event(
1154 MouseLocation::Relative(Default::default()),
1155 None, None, None, MousePhase::Up,
1159 HashSet::from_iter(vec![button].into_iter()),
1160 HashSet::new(),
1161 event_time_u64,
1162 &descriptor,
1163 ),
1164 ];
1165
1166 assert_input_report_sequence_generates_events!(
1167 input_reports: input_reports,
1168 expected_events: expected_events,
1169 device_descriptor: descriptor,
1170 device_type: MouseBinding,
1171 );
1172 }
1173
1174 #[fasync::run_until_stalled(test)]
1176 async fn absolute_movement_to_origin() {
1177 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1178 let descriptor = mouse_device_descriptor(DEVICE_ID);
1179
1180 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
1181 Position::zero(),
1182 None, None, vec![],
1185 event_time_i64,
1186 )];
1187 let expected_events = vec![testing_utilities::create_mouse_event(
1188 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1189 None, None, None, MousePhase::Move,
1193 HashSet::new(),
1194 HashSet::new(),
1195 event_time_u64,
1196 &descriptor,
1197 )];
1198
1199 assert_input_report_sequence_generates_events!(
1200 input_reports: input_reports,
1201 expected_events: expected_events,
1202 device_descriptor: descriptor,
1203 device_type: MouseBinding,
1204 );
1205 }
1206
1207 #[fasync::run_until_stalled(test)]
1210 async fn report_with_both_movement_and_position() {
1211 let relative_movement = Position { x: 5.0, y: 5.0 };
1212 let absolute_position = Position { x: 10.0, y: 10.0 };
1213 let expected_location = MouseLocation::Absolute(absolute_position);
1214
1215 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1216 let descriptor = mouse_device_descriptor(DEVICE_ID);
1217
1218 let input_reports = vec![fidl_next_fuchsia_input_report::InputReport {
1219 event_time: Some(event_time_i64),
1220 keyboard: None,
1221 mouse: Some(fidl_next_fuchsia_input_report::MouseInputReport {
1222 movement_x: Some(relative_movement.x as i64),
1223 movement_y: Some(relative_movement.y as i64),
1224 position_x: Some(absolute_position.x as i64),
1225 position_y: Some(absolute_position.y as i64),
1226 scroll_h: None,
1227 scroll_v: None,
1228 pressed_buttons: None,
1229 ..Default::default()
1230 }),
1231 touch: None,
1232 sensor: None,
1233 consumer_control: None,
1234 trace_id: None,
1235 ..Default::default()
1236 }];
1237 let expected_events = vec![testing_utilities::create_mouse_event(
1238 expected_location,
1239 None, None, None, MousePhase::Move,
1243 HashSet::new(),
1244 HashSet::new(),
1245 event_time_u64,
1246 &descriptor,
1247 )];
1248
1249 assert_input_report_sequence_generates_events!(
1250 input_reports: input_reports,
1251 expected_events: expected_events,
1252 device_descriptor: descriptor,
1253 device_type: MouseBinding,
1254 );
1255 }
1256
1257 #[fasync::run_singlethreaded(test)]
1260 async fn down_down() {
1261 const PRIMARY_BUTTON: u8 = 1;
1262 const SECONDARY_BUTTON: u8 = 2;
1263
1264 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1265 let first_report = testing_utilities::create_mouse_input_report_relative(
1266 Position::zero(),
1267 None, None, vec![PRIMARY_BUTTON],
1270 event_time_i64,
1271 );
1272 let second_report = testing_utilities::create_mouse_input_report_relative(
1273 Position::zero(),
1274 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1277 event_time_i64,
1278 );
1279 let descriptor = mouse_device_descriptor(DEVICE_ID);
1280
1281 let input_reports = vec![first_report, second_report];
1282 let expected_events = vec![
1283 testing_utilities::create_mouse_event(
1284 MouseLocation::Relative(Default::default()),
1285 None, None, None, MousePhase::Down,
1289 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1290 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1291 event_time_u64,
1292 &descriptor,
1293 ),
1294 testing_utilities::create_mouse_event(
1295 MouseLocation::Relative(Default::default()),
1296 None, None, None, MousePhase::Down,
1300 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1301 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1302 event_time_u64,
1303 &descriptor,
1304 ),
1305 ];
1306
1307 assert_input_report_sequence_generates_events!(
1308 input_reports: input_reports,
1309 expected_events: expected_events,
1310 device_descriptor: descriptor,
1311 device_type: MouseBinding,
1312 );
1313 }
1314
1315 #[fasync::run_singlethreaded(test)]
1325 async fn down_down_up_up() {
1326 const PRIMARY_BUTTON: u8 = 1;
1327 const SECONDARY_BUTTON: u8 = 2;
1328
1329 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1330 let first_report = testing_utilities::create_mouse_input_report_relative(
1331 Position::zero(),
1332 None, None, vec![PRIMARY_BUTTON],
1335 event_time_i64,
1336 );
1337 let second_report = testing_utilities::create_mouse_input_report_relative(
1338 Position::zero(),
1339 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1342 event_time_i64,
1343 );
1344 let third_report = testing_utilities::create_mouse_input_report_relative(
1345 Position::zero(),
1346 None, None, vec![SECONDARY_BUTTON],
1349 event_time_i64,
1350 );
1351 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1352 Position::zero(),
1353 None, None, vec![],
1356 event_time_i64,
1357 );
1358 let descriptor = mouse_device_descriptor(DEVICE_ID);
1359
1360 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1361 let expected_events = vec![
1362 testing_utilities::create_mouse_event(
1363 MouseLocation::Relative(Default::default()),
1364 None, None, None, MousePhase::Down,
1368 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1369 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1370 event_time_u64,
1371 &descriptor,
1372 ),
1373 testing_utilities::create_mouse_event(
1374 MouseLocation::Relative(Default::default()),
1375 None, None, None, MousePhase::Down,
1379 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1380 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1381 event_time_u64,
1382 &descriptor,
1383 ),
1384 testing_utilities::create_mouse_event(
1385 MouseLocation::Relative(Default::default()),
1386 None, None, None, MousePhase::Up,
1390 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1391 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1392 event_time_u64,
1393 &descriptor,
1394 ),
1395 testing_utilities::create_mouse_event(
1396 MouseLocation::Relative(Default::default()),
1397 None, None, None, MousePhase::Up,
1401 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1402 HashSet::new(),
1403 event_time_u64,
1404 &descriptor,
1405 ),
1406 ];
1407
1408 assert_input_report_sequence_generates_events!(
1409 input_reports: input_reports,
1410 expected_events: expected_events,
1411 device_descriptor: descriptor,
1412 device_type: MouseBinding,
1413 );
1414 }
1415
1416 #[fasync::run_singlethreaded(test)]
1418 async fn scroll() {
1419 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1420 let first_report = testing_utilities::create_mouse_input_report_relative(
1421 Position::zero(),
1422 Some(1),
1423 None,
1424 vec![],
1425 event_time_i64,
1426 );
1427 let second_report = testing_utilities::create_mouse_input_report_relative(
1428 Position::zero(),
1429 None,
1430 Some(1),
1431 vec![],
1432 event_time_i64,
1433 );
1434
1435 let descriptor = mouse_device_descriptor(DEVICE_ID);
1436
1437 let input_reports = vec![first_report, second_report];
1438 let expected_events = vec![
1439 testing_utilities::create_mouse_event(
1440 MouseLocation::Relative(Default::default()),
1441 wheel_delta_ticks(1),
1442 None,
1443 Some(PrecisionScroll::No),
1444 MousePhase::Wheel,
1445 HashSet::new(),
1446 HashSet::new(),
1447 event_time_u64,
1448 &descriptor,
1449 ),
1450 testing_utilities::create_mouse_event(
1451 MouseLocation::Relative(Default::default()),
1452 None,
1453 wheel_delta_ticks(1),
1454 Some(PrecisionScroll::No),
1455 MousePhase::Wheel,
1456 HashSet::new(),
1457 HashSet::new(),
1458 event_time_u64,
1459 &descriptor,
1460 ),
1461 ];
1462
1463 assert_input_report_sequence_generates_events!(
1464 input_reports: input_reports,
1465 expected_events: expected_events,
1466 device_descriptor: descriptor,
1467 device_type: MouseBinding,
1468 );
1469 }
1470
1471 #[fasync::run_singlethreaded(test)]
1473 async fn down_scroll_up_scroll() {
1474 const PRIMARY_BUTTON: u8 = 1;
1475
1476 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1477 let first_report = testing_utilities::create_mouse_input_report_relative(
1478 Position::zero(),
1479 None, None, vec![PRIMARY_BUTTON],
1482 event_time_i64,
1483 );
1484 let second_report = testing_utilities::create_mouse_input_report_relative(
1485 Position::zero(),
1486 Some(1),
1487 None,
1488 vec![PRIMARY_BUTTON],
1489 event_time_i64,
1490 );
1491 let third_report = testing_utilities::create_mouse_input_report_relative(
1492 Position::zero(),
1493 None, None, vec![],
1496 event_time_i64,
1497 );
1498 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1499 Position::zero(),
1500 Some(1),
1501 None,
1502 vec![],
1503 event_time_i64,
1504 );
1505
1506 let descriptor = mouse_device_descriptor(DEVICE_ID);
1507
1508 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1509 let expected_events = vec![
1510 testing_utilities::create_mouse_event(
1511 MouseLocation::Relative(Default::default()),
1512 None, None, None, MousePhase::Down,
1516 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1517 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1518 event_time_u64,
1519 &descriptor,
1520 ),
1521 testing_utilities::create_mouse_event(
1522 MouseLocation::Relative(Default::default()),
1523 wheel_delta_ticks(1),
1524 None,
1525 Some(PrecisionScroll::No),
1526 MousePhase::Wheel,
1527 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1528 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1529 event_time_u64,
1530 &descriptor,
1531 ),
1532 testing_utilities::create_mouse_event(
1533 MouseLocation::Relative(Default::default()),
1534 None, None, None, MousePhase::Up,
1538 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1539 HashSet::new(),
1540 event_time_u64,
1541 &descriptor,
1542 ),
1543 testing_utilities::create_mouse_event(
1544 MouseLocation::Relative(Default::default()),
1545 wheel_delta_ticks(1),
1546 None,
1547 Some(PrecisionScroll::No),
1548 MousePhase::Wheel,
1549 HashSet::new(),
1550 HashSet::new(),
1551 event_time_u64,
1552 &descriptor,
1553 ),
1554 ];
1555
1556 assert_input_report_sequence_generates_events!(
1557 input_reports: input_reports,
1558 expected_events: expected_events,
1559 device_descriptor: descriptor,
1560 device_type: MouseBinding,
1561 );
1562 }
1563
1564 #[fasync::run_singlethreaded(test)]
1566 async fn down_scroll_bundle_up_scroll_bundle() {
1567 const PRIMARY_BUTTON: u8 = 1;
1568
1569 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1570 let first_report = testing_utilities::create_mouse_input_report_relative(
1571 Position::zero(),
1572 Some(1),
1573 None,
1574 vec![PRIMARY_BUTTON],
1575 event_time_i64,
1576 );
1577 let second_report = testing_utilities::create_mouse_input_report_relative(
1578 Position::zero(),
1579 Some(1),
1580 None,
1581 vec![],
1582 event_time_i64,
1583 );
1584 let third_report = testing_utilities::create_mouse_input_report_relative(
1585 Position::zero(),
1586 Some(1),
1587 None,
1588 vec![],
1589 event_time_i64,
1590 );
1591
1592 let descriptor = mouse_device_descriptor(DEVICE_ID);
1593
1594 let input_reports = vec![first_report, second_report, third_report];
1595 let expected_events = vec![
1596 testing_utilities::create_mouse_event(
1597 MouseLocation::Relative(Default::default()),
1598 None, None, None, MousePhase::Down,
1602 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1603 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1604 event_time_u64,
1605 &descriptor,
1606 ),
1607 testing_utilities::create_mouse_event(
1608 MouseLocation::Relative(Default::default()),
1609 wheel_delta_ticks(1),
1610 None,
1611 Some(PrecisionScroll::No),
1612 MousePhase::Wheel,
1613 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1614 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1615 event_time_u64,
1616 &descriptor,
1617 ),
1618 testing_utilities::create_mouse_event(
1619 MouseLocation::Relative(Default::default()),
1620 wheel_delta_ticks(1),
1621 None,
1622 Some(PrecisionScroll::No),
1623 MousePhase::Wheel,
1624 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1625 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1626 event_time_u64,
1627 &descriptor,
1628 ),
1629 testing_utilities::create_mouse_event(
1630 MouseLocation::Relative(Default::default()),
1631 None, None, None, MousePhase::Up,
1635 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1636 HashSet::new(),
1637 event_time_u64,
1638 &descriptor,
1639 ),
1640 testing_utilities::create_mouse_event(
1641 MouseLocation::Relative(Default::default()),
1642 wheel_delta_ticks(1),
1643 None,
1644 Some(PrecisionScroll::No),
1645 MousePhase::Wheel,
1646 HashSet::new(),
1647 HashSet::new(),
1648 event_time_u64,
1649 &descriptor,
1650 ),
1651 ];
1652
1653 assert_input_report_sequence_generates_events!(
1654 input_reports: input_reports,
1655 expected_events: expected_events,
1656 device_descriptor: descriptor,
1657 device_type: MouseBinding,
1658 );
1659 }
1660}