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 reports: Vec<InputReport>,
445 mut 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!("input", "mouse-binding-process-reports", "num_reports" => reports.len());
452 for report in reports {
453 previous_report = Self::process_report(
454 report,
455 previous_report,
456 device_descriptor,
457 input_event_sender,
458 inspect_status,
459 metrics_logger,
460 );
461 }
462 (previous_report, None)
463 }
464
465 fn process_report(
466 mut report: InputReport,
467 previous_report: Option<InputReport>,
468 device_descriptor: &input_device::InputDeviceDescriptor,
469 input_event_sender: &mut UnboundedSender<input_device::InputEvent>,
470 inspect_status: &InputDeviceStatus,
471 metrics_logger: &metrics::MetricsLogger,
472 ) -> Option<InputReport> {
473 if let Some(trace_id) = report.trace_id {
474 fuchsia_trace::flow_end!("input", "input_report", trace_id.into());
475 }
476
477 inspect_status.count_received_report(&report);
478 let mouse_report: &fidl_input_report::MouseInputReport = match &report.mouse {
480 Some(mouse) => mouse,
481 None => {
482 inspect_status.count_filtered_report();
483 return previous_report;
484 }
485 };
486
487 let previous_buttons: HashSet<MouseButton> =
488 buttons_from_optional_report(&previous_report.as_ref());
489 let current_buttons: HashSet<MouseButton> = buttons_from_report(&report);
490 let wake_lease = report.wake_lease.take();
491
492 send_mouse_event(
498 MouseLocation::Relative(Default::default()),
499 None, None, MousePhase::Down,
502 current_buttons.difference(&previous_buttons).cloned().collect(),
503 current_buttons.clone(),
504 device_descriptor,
505 input_event_sender,
506 inspect_status,
507 metrics_logger,
508 wake_lease.as_ref().map(|lease| {
509 lease
510 .duplicate_handle(zx::Rights::SAME_RIGHTS)
511 .expect("failed to duplicate event pair")
512 }),
513 );
514
515 let counts_per_mm = match device_descriptor {
516 input_device::InputDeviceDescriptor::Mouse(ds) => ds.counts_per_mm,
517 _ => {
518 metrics_logger.log_error(
519 InputPipelineErrorMetricDimensionEvent::MouseDescriptionNotMouse,
520 "mouse_binding::process_reports got device_descriptor not mouse".to_string(),
521 );
522 mouse_model_database::db::DEFAULT_COUNTS_PER_MM
523 }
524 };
525
526 let location = if let (Some(position_x), Some(position_y)) =
528 (mouse_report.position_x, mouse_report.position_y)
529 {
530 MouseLocation::Absolute(Position { x: position_x as f32, y: position_y as f32 })
531 } else {
532 let movement_x = mouse_report.movement_x.unwrap_or_default() as f32;
533 let movement_y = mouse_report.movement_y.unwrap_or_default() as f32;
534 MouseLocation::Relative(RelativeLocation {
535 millimeters: Position {
536 x: movement_x / counts_per_mm as f32,
537 y: movement_y / counts_per_mm as f32,
538 },
539 })
540 };
541
542 send_mouse_event(
546 location,
547 None, None, MousePhase::Move,
550 current_buttons.union(&previous_buttons).cloned().collect(),
551 current_buttons.union(&previous_buttons).cloned().collect(),
552 device_descriptor,
553 input_event_sender,
554 inspect_status,
555 metrics_logger,
556 wake_lease.as_ref().map(|lease| {
557 lease
558 .duplicate_handle(zx::Rights::SAME_RIGHTS)
559 .expect("failed to duplicate event pair")
560 }),
561 );
562
563 let wheel_delta_v = match mouse_report.scroll_v {
564 None => None,
565 Some(ticks) => {
566 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
567 }
568 };
569
570 let wheel_delta_h = match mouse_report.scroll_h {
571 None => None,
572 Some(ticks) => {
573 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
574 }
575 };
576
577 send_mouse_event(
579 MouseLocation::Relative(Default::default()),
580 wheel_delta_v,
581 wheel_delta_h,
582 MousePhase::Wheel,
583 current_buttons.union(&previous_buttons).cloned().collect(),
584 current_buttons.union(&previous_buttons).cloned().collect(),
585 device_descriptor,
586 input_event_sender,
587 inspect_status,
588 metrics_logger,
589 wake_lease.as_ref().map(|lease| {
590 lease
591 .duplicate_handle(zx::Rights::SAME_RIGHTS)
592 .expect("failed to duplicate event pair")
593 }),
594 );
595
596 send_mouse_event(
602 MouseLocation::Relative(Default::default()),
603 None, None, MousePhase::Up,
606 previous_buttons.difference(¤t_buttons).cloned().collect(),
607 current_buttons.clone(),
608 device_descriptor,
609 input_event_sender,
610 inspect_status,
611 metrics_logger,
612 wake_lease,
613 );
614
615 Some(report)
616 }
617}
618
619fn send_mouse_event(
634 location: MouseLocation,
635 wheel_delta_v: Option<WheelDelta>,
636 wheel_delta_h: Option<WheelDelta>,
637 phase: MousePhase,
638 affected_buttons: HashSet<MouseButton>,
639 pressed_buttons: HashSet<MouseButton>,
640 device_descriptor: &input_device::InputDeviceDescriptor,
641 sender: &mut UnboundedSender<input_device::InputEvent>,
642 inspect_status: &InputDeviceStatus,
643 metrics_logger: &metrics::MetricsLogger,
644 wake_lease: Option<zx::EventPair>,
645) {
646 if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
648 return;
649 }
650
651 if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
654 return;
655 }
656
657 if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
659 return;
660 }
661
662 let trace_id = fuchsia_trace::Id::random();
663 fuchsia_trace::duration!("input", "mouse-binding-send-event");
664 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
665
666 let event = input_device::InputEvent {
667 device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
668 location,
669 wheel_delta_v,
670 wheel_delta_h,
671 phase,
672 affected_buttons,
673 pressed_buttons,
674 match phase {
675 MousePhase::Wheel => Some(PrecisionScroll::No),
676 _ => None,
677 },
678 wake_lease,
679 )),
680 device_descriptor: device_descriptor.clone(),
681 event_time: zx::MonotonicInstant::get(),
682 handled: Handled::No,
683 trace_id: Some(trace_id),
684 };
685
686 match sender.unbounded_send(event.clone_with_wake_lease()) {
687 Err(e) => {
688 metrics_logger.log_error(
689 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
690 std::format!("Failed to send MouseEvent with error: {:?}", e),
691 );
692 }
693 _ => inspect_status.count_generated_event(event),
694 }
695}
696
697pub fn get_u32_from_buttons(buttons: &HashSet<MouseButton>) -> u32 {
711 let mut bits: u32 = 0;
712 for button in buttons {
713 if *button > 0 && *button <= fidl_input_report::MOUSE_MAX_NUM_BUTTONS as u8 {
714 bits = ((1 as u32) << *button - 1) | bits;
715 }
716 }
717
718 bits
719}
720
721fn buttons_from_report(input_report: &fidl_input_report::InputReport) -> HashSet<MouseButton> {
726 buttons_from_optional_report(&Some(input_report))
727}
728
729fn buttons_from_optional_report(
734 input_report: &Option<&fidl_input_report::InputReport>,
735) -> HashSet<MouseButton> {
736 input_report
737 .as_ref()
738 .and_then(|unwrapped_report| unwrapped_report.mouse.as_ref())
739 .and_then(|mouse_report| match &mouse_report.pressed_buttons {
740 Some(buttons) => Some(HashSet::from_iter(buttons.iter().cloned())),
741 None => None,
742 })
743 .unwrap_or_default()
744}
745
746#[cfg(test)]
747mod tests {
748 use super::*;
749 use crate::testing_utilities;
750 use fuchsia_async as fasync;
751 use futures::StreamExt;
752 use pretty_assertions::assert_eq;
753
754 const DEVICE_ID: u32 = 1;
755 const COUNTS_PER_MM: u32 = 12;
756
757 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
758 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
759 device_id,
760 absolute_x_range: None,
761 absolute_y_range: None,
762 wheel_v_range: Some(fidl_fuchsia_input_report::Axis {
763 range: fidl_input_report::Range { min: -1, max: 1 },
764 unit: fidl_input_report::Unit {
765 type_: fidl_input_report::UnitType::Other,
766 exponent: 1,
767 },
768 }),
769 wheel_h_range: Some(fidl_fuchsia_input_report::Axis {
770 range: fidl_input_report::Range { min: -1, max: 1 },
771 unit: fidl_input_report::Unit {
772 type_: fidl_input_report::UnitType::Other,
773 exponent: 1,
774 },
775 }),
776 buttons: None,
777 counts_per_mm: COUNTS_PER_MM,
778 })
779 }
780
781 fn wheel_delta_ticks(delta: i64) -> Option<WheelDelta> {
782 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(delta), physical_pixel: None })
783 }
784
785 #[test]
787 fn get_u32_from_buttons_test() {
788 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, 5].into_iter()));
789 assert_eq!(bits, 21 )
790 }
791
792 #[test]
794 fn get_u32_with_0_in_vector() {
795 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![0, 1, 3].into_iter()));
796 assert_eq!(bits, 5 )
797 }
798
799 #[test]
801 fn get_u32_with_empty_vector() {
802 let bits = get_u32_from_buttons(&HashSet::new());
803 assert_eq!(bits, 0 )
804 }
805
806 #[test]
808 fn get_u32_with_u8_max_in_vector() {
809 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, std::u8::MAX].into_iter()));
810 assert_eq!(bits, 5 )
811 }
812
813 #[test]
816 fn get_u32_with_max_mouse_buttons() {
817 let bits = get_u32_from_buttons(&HashSet::from_iter(
818 vec![1, 3, fidl_input_report::MOUSE_MAX_NUM_BUTTONS as MouseButton].into_iter(),
819 ));
820 assert_eq!(bits, 2147483653 )
821 }
822
823 #[fasync::run_singlethreaded(test)]
825 async fn movement_without_button() {
826 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
827 let first_report = testing_utilities::create_mouse_input_report_relative(
828 Position { x: 10.0, y: 16.0 },
829 None, None, vec![],
832 event_time_i64,
833 );
834 let descriptor = mouse_device_descriptor(DEVICE_ID);
835
836 let input_reports = vec![first_report];
837 let expected_events = vec![testing_utilities::create_mouse_event(
838 MouseLocation::Relative(RelativeLocation {
839 millimeters: Position {
840 x: 10.0 / COUNTS_PER_MM as f32,
841 y: 16.0 / COUNTS_PER_MM as f32,
842 },
843 }),
844 None, None, None, MousePhase::Move,
848 HashSet::new(),
849 HashSet::new(),
850 event_time_u64,
851 &descriptor,
852 )];
853
854 assert_input_report_sequence_generates_events!(
855 input_reports: input_reports,
856 expected_events: expected_events,
857 device_descriptor: descriptor,
858 device_type: MouseBinding,
859 );
860 }
861
862 #[fasync::run_singlethreaded(test)]
864 async fn down_without_movement() {
865 let mouse_button: MouseButton = 3;
866 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
867 let first_report = testing_utilities::create_mouse_input_report_relative(
868 Position::zero(),
869 None, None, vec![mouse_button],
872 event_time_i64,
873 );
874 let descriptor = mouse_device_descriptor(DEVICE_ID);
875
876 let input_reports = vec![first_report];
877 let expected_events = vec![testing_utilities::create_mouse_event(
878 MouseLocation::Relative(Default::default()),
879 None, None, None, MousePhase::Down,
883 HashSet::from_iter(vec![mouse_button].into_iter()),
884 HashSet::from_iter(vec![mouse_button].into_iter()),
885 event_time_u64,
886 &descriptor,
887 )];
888
889 assert_input_report_sequence_generates_events!(
890 input_reports: input_reports,
891 expected_events: expected_events,
892 device_descriptor: descriptor,
893 device_type: MouseBinding,
894 );
895 }
896
897 #[fasync::run_singlethreaded(test)]
900 async fn down_with_movement() {
901 let mouse_button: MouseButton = 3;
902 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
903 let first_report = testing_utilities::create_mouse_input_report_relative(
904 Position { x: 10.0, y: 16.0 },
905 None, None, vec![mouse_button],
908 event_time_i64,
909 );
910 let descriptor = mouse_device_descriptor(DEVICE_ID);
911
912 let input_reports = vec![first_report];
913 let expected_events = vec![
914 testing_utilities::create_mouse_event(
915 MouseLocation::Relative(Default::default()),
916 None, None, None, MousePhase::Down,
920 HashSet::from_iter(vec![mouse_button].into_iter()),
921 HashSet::from_iter(vec![mouse_button].into_iter()),
922 event_time_u64,
923 &descriptor,
924 ),
925 testing_utilities::create_mouse_event(
926 MouseLocation::Relative(RelativeLocation {
927 millimeters: Position {
928 x: 10.0 / COUNTS_PER_MM as f32,
929 y: 16.0 / COUNTS_PER_MM as f32,
930 },
931 }),
932 None, None, None, MousePhase::Move,
936 HashSet::from_iter(vec![mouse_button].into_iter()),
937 HashSet::from_iter(vec![mouse_button].into_iter()),
938 event_time_u64,
939 &descriptor,
940 ),
941 ];
942
943 assert_input_report_sequence_generates_events!(
944 input_reports: input_reports,
945 expected_events: expected_events,
946 device_descriptor: descriptor,
947 device_type: MouseBinding,
948 );
949 }
950
951 #[fasync::run_singlethreaded(test)]
953 async fn down_up() {
954 let button = 1;
955 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
956 let first_report = testing_utilities::create_mouse_input_report_relative(
957 Position::zero(),
958 None, None, vec![button],
961 event_time_i64,
962 );
963 let second_report = testing_utilities::create_mouse_input_report_relative(
964 Position::zero(),
965 None, None, vec![],
968 event_time_i64,
969 );
970 let descriptor = mouse_device_descriptor(DEVICE_ID);
971
972 let input_reports = vec![first_report, second_report];
973 let expected_events = vec![
974 testing_utilities::create_mouse_event(
975 MouseLocation::Relative(Default::default()),
976 None, None, None, MousePhase::Down,
980 HashSet::from_iter(vec![button].into_iter()),
981 HashSet::from_iter(vec![button].into_iter()),
982 event_time_u64,
983 &descriptor,
984 ),
985 testing_utilities::create_mouse_event(
986 MouseLocation::Relative(Default::default()),
987 None, None, None, MousePhase::Up,
991 HashSet::from_iter(vec![button].into_iter()),
992 HashSet::new(),
993 event_time_u64,
994 &descriptor,
995 ),
996 ];
997
998 assert_input_report_sequence_generates_events!(
999 input_reports: input_reports,
1000 expected_events: expected_events,
1001 device_descriptor: descriptor,
1002 device_type: MouseBinding,
1003 );
1004 }
1005
1006 #[fasync::run_singlethreaded(test)]
1008 async fn down_up_with_movement() {
1009 let button = 1;
1010
1011 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1012 let first_report = testing_utilities::create_mouse_input_report_relative(
1013 Position::zero(),
1014 None, None, vec![button],
1017 event_time_i64,
1018 );
1019 let second_report = testing_utilities::create_mouse_input_report_relative(
1020 Position { x: 10.0, y: 16.0 },
1021 None, None, vec![],
1024 event_time_i64,
1025 );
1026 let descriptor = mouse_device_descriptor(DEVICE_ID);
1027
1028 let input_reports = vec![first_report, second_report];
1029 let expected_events = vec![
1030 testing_utilities::create_mouse_event(
1031 MouseLocation::Relative(Default::default()),
1032 None, None, None, MousePhase::Down,
1036 HashSet::from_iter(vec![button].into_iter()),
1037 HashSet::from_iter(vec![button].into_iter()),
1038 event_time_u64,
1039 &descriptor,
1040 ),
1041 testing_utilities::create_mouse_event(
1042 MouseLocation::Relative(RelativeLocation {
1043 millimeters: Position {
1044 x: 10.0 / COUNTS_PER_MM as f32,
1045 y: 16.0 / COUNTS_PER_MM as f32,
1046 },
1047 }),
1048 None, None, None, MousePhase::Move,
1052 HashSet::from_iter(vec![button].into_iter()),
1053 HashSet::from_iter(vec![button].into_iter()),
1054 event_time_u64,
1055 &descriptor,
1056 ),
1057 testing_utilities::create_mouse_event(
1058 MouseLocation::Relative(Default::default()),
1059 None, None, None, MousePhase::Up,
1063 HashSet::from_iter(vec![button].into_iter()),
1064 HashSet::new(),
1065 event_time_u64,
1066 &descriptor,
1067 ),
1068 ];
1069
1070 assert_input_report_sequence_generates_events!(
1071 input_reports: input_reports,
1072 expected_events: expected_events,
1073 device_descriptor: descriptor,
1074 device_type: MouseBinding,
1075 );
1076 }
1077
1078 #[fasync::run_singlethreaded(test)]
1082 async fn down_move_up() {
1083 let button = 1;
1084
1085 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1086 let first_report = testing_utilities::create_mouse_input_report_relative(
1087 Position::zero(),
1088 None, None, vec![button],
1091 event_time_i64,
1092 );
1093 let second_report = testing_utilities::create_mouse_input_report_relative(
1094 Position { x: 10.0, y: 16.0 },
1095 None, None, vec![button],
1098 event_time_i64,
1099 );
1100 let third_report = testing_utilities::create_mouse_input_report_relative(
1101 Position::zero(),
1102 None, None, vec![],
1105 event_time_i64,
1106 );
1107 let descriptor = mouse_device_descriptor(DEVICE_ID);
1108
1109 let input_reports = vec![first_report, second_report, third_report];
1110 let expected_events = vec![
1111 testing_utilities::create_mouse_event(
1112 MouseLocation::Relative(Default::default()),
1113 None, None, None, MousePhase::Down,
1117 HashSet::from_iter(vec![button].into_iter()),
1118 HashSet::from_iter(vec![button].into_iter()),
1119 event_time_u64,
1120 &descriptor,
1121 ),
1122 testing_utilities::create_mouse_event(
1123 MouseLocation::Relative(RelativeLocation {
1124 millimeters: Position {
1125 x: 10.0 / COUNTS_PER_MM as f32,
1126 y: 16.0 / COUNTS_PER_MM as f32,
1127 },
1128 }),
1129 None, None, None, MousePhase::Move,
1133 HashSet::from_iter(vec![button].into_iter()),
1134 HashSet::from_iter(vec![button].into_iter()),
1135 event_time_u64,
1136 &descriptor,
1137 ),
1138 testing_utilities::create_mouse_event(
1139 MouseLocation::Relative(Default::default()),
1140 None, None, None, MousePhase::Up,
1144 HashSet::from_iter(vec![button].into_iter()),
1145 HashSet::new(),
1146 event_time_u64,
1147 &descriptor,
1148 ),
1149 ];
1150
1151 assert_input_report_sequence_generates_events!(
1152 input_reports: input_reports,
1153 expected_events: expected_events,
1154 device_descriptor: descriptor,
1155 device_type: MouseBinding,
1156 );
1157 }
1158
1159 #[fasync::run_until_stalled(test)]
1161 async fn absolute_movement_to_origin() {
1162 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1163 let descriptor = mouse_device_descriptor(DEVICE_ID);
1164
1165 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
1166 Position::zero(),
1167 None, None, vec![],
1170 event_time_i64,
1171 )];
1172 let expected_events = vec![testing_utilities::create_mouse_event(
1173 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1174 None, None, None, MousePhase::Move,
1178 HashSet::new(),
1179 HashSet::new(),
1180 event_time_u64,
1181 &descriptor,
1182 )];
1183
1184 assert_input_report_sequence_generates_events!(
1185 input_reports: input_reports,
1186 expected_events: expected_events,
1187 device_descriptor: descriptor,
1188 device_type: MouseBinding,
1189 );
1190 }
1191
1192 #[fasync::run_until_stalled(test)]
1195 async fn report_with_both_movement_and_position() {
1196 let relative_movement = Position { x: 5.0, y: 5.0 };
1197 let absolute_position = Position { x: 10.0, y: 10.0 };
1198 let expected_location = MouseLocation::Absolute(absolute_position);
1199
1200 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1201 let descriptor = mouse_device_descriptor(DEVICE_ID);
1202
1203 let input_reports = vec![fidl_input_report::InputReport {
1204 event_time: Some(event_time_i64),
1205 keyboard: None,
1206 mouse: Some(fidl_input_report::MouseInputReport {
1207 movement_x: Some(relative_movement.x as i64),
1208 movement_y: Some(relative_movement.y as i64),
1209 position_x: Some(absolute_position.x as i64),
1210 position_y: Some(absolute_position.y as i64),
1211 scroll_h: None,
1212 scroll_v: None,
1213 pressed_buttons: None,
1214 ..Default::default()
1215 }),
1216 touch: None,
1217 sensor: None,
1218 consumer_control: None,
1219 trace_id: None,
1220 ..Default::default()
1221 }];
1222 let expected_events = vec![testing_utilities::create_mouse_event(
1223 expected_location,
1224 None, None, None, MousePhase::Move,
1228 HashSet::new(),
1229 HashSet::new(),
1230 event_time_u64,
1231 &descriptor,
1232 )];
1233
1234 assert_input_report_sequence_generates_events!(
1235 input_reports: input_reports,
1236 expected_events: expected_events,
1237 device_descriptor: descriptor,
1238 device_type: MouseBinding,
1239 );
1240 }
1241
1242 #[fasync::run_singlethreaded(test)]
1245 async fn down_down() {
1246 const PRIMARY_BUTTON: u8 = 1;
1247 const SECONDARY_BUTTON: u8 = 2;
1248
1249 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1250 let first_report = testing_utilities::create_mouse_input_report_relative(
1251 Position::zero(),
1252 None, None, vec![PRIMARY_BUTTON],
1255 event_time_i64,
1256 );
1257 let second_report = testing_utilities::create_mouse_input_report_relative(
1258 Position::zero(),
1259 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1262 event_time_i64,
1263 );
1264 let descriptor = mouse_device_descriptor(DEVICE_ID);
1265
1266 let input_reports = vec![first_report, second_report];
1267 let expected_events = vec![
1268 testing_utilities::create_mouse_event(
1269 MouseLocation::Relative(Default::default()),
1270 None, None, None, MousePhase::Down,
1274 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1275 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1276 event_time_u64,
1277 &descriptor,
1278 ),
1279 testing_utilities::create_mouse_event(
1280 MouseLocation::Relative(Default::default()),
1281 None, None, None, MousePhase::Down,
1285 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1286 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1287 event_time_u64,
1288 &descriptor,
1289 ),
1290 ];
1291
1292 assert_input_report_sequence_generates_events!(
1293 input_reports: input_reports,
1294 expected_events: expected_events,
1295 device_descriptor: descriptor,
1296 device_type: MouseBinding,
1297 );
1298 }
1299
1300 #[fasync::run_singlethreaded(test)]
1310 async fn down_down_up_up() {
1311 const PRIMARY_BUTTON: u8 = 1;
1312 const SECONDARY_BUTTON: u8 = 2;
1313
1314 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1315 let first_report = testing_utilities::create_mouse_input_report_relative(
1316 Position::zero(),
1317 None, None, vec![PRIMARY_BUTTON],
1320 event_time_i64,
1321 );
1322 let second_report = testing_utilities::create_mouse_input_report_relative(
1323 Position::zero(),
1324 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1327 event_time_i64,
1328 );
1329 let third_report = testing_utilities::create_mouse_input_report_relative(
1330 Position::zero(),
1331 None, None, vec![SECONDARY_BUTTON],
1334 event_time_i64,
1335 );
1336 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1337 Position::zero(),
1338 None, None, vec![],
1341 event_time_i64,
1342 );
1343 let descriptor = mouse_device_descriptor(DEVICE_ID);
1344
1345 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1346 let expected_events = vec![
1347 testing_utilities::create_mouse_event(
1348 MouseLocation::Relative(Default::default()),
1349 None, None, None, MousePhase::Down,
1353 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1354 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1355 event_time_u64,
1356 &descriptor,
1357 ),
1358 testing_utilities::create_mouse_event(
1359 MouseLocation::Relative(Default::default()),
1360 None, None, None, MousePhase::Down,
1364 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1365 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1366 event_time_u64,
1367 &descriptor,
1368 ),
1369 testing_utilities::create_mouse_event(
1370 MouseLocation::Relative(Default::default()),
1371 None, None, None, MousePhase::Up,
1375 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1376 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1377 event_time_u64,
1378 &descriptor,
1379 ),
1380 testing_utilities::create_mouse_event(
1381 MouseLocation::Relative(Default::default()),
1382 None, None, None, MousePhase::Up,
1386 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1387 HashSet::new(),
1388 event_time_u64,
1389 &descriptor,
1390 ),
1391 ];
1392
1393 assert_input_report_sequence_generates_events!(
1394 input_reports: input_reports,
1395 expected_events: expected_events,
1396 device_descriptor: descriptor,
1397 device_type: MouseBinding,
1398 );
1399 }
1400
1401 #[fasync::run_singlethreaded(test)]
1403 async fn scroll() {
1404 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1405 let first_report = testing_utilities::create_mouse_input_report_relative(
1406 Position::zero(),
1407 Some(1),
1408 None,
1409 vec![],
1410 event_time_i64,
1411 );
1412 let second_report = testing_utilities::create_mouse_input_report_relative(
1413 Position::zero(),
1414 None,
1415 Some(1),
1416 vec![],
1417 event_time_i64,
1418 );
1419
1420 let descriptor = mouse_device_descriptor(DEVICE_ID);
1421
1422 let input_reports = vec![first_report, second_report];
1423 let expected_events = vec![
1424 testing_utilities::create_mouse_event(
1425 MouseLocation::Relative(Default::default()),
1426 wheel_delta_ticks(1),
1427 None,
1428 Some(PrecisionScroll::No),
1429 MousePhase::Wheel,
1430 HashSet::new(),
1431 HashSet::new(),
1432 event_time_u64,
1433 &descriptor,
1434 ),
1435 testing_utilities::create_mouse_event(
1436 MouseLocation::Relative(Default::default()),
1437 None,
1438 wheel_delta_ticks(1),
1439 Some(PrecisionScroll::No),
1440 MousePhase::Wheel,
1441 HashSet::new(),
1442 HashSet::new(),
1443 event_time_u64,
1444 &descriptor,
1445 ),
1446 ];
1447
1448 assert_input_report_sequence_generates_events!(
1449 input_reports: input_reports,
1450 expected_events: expected_events,
1451 device_descriptor: descriptor,
1452 device_type: MouseBinding,
1453 );
1454 }
1455
1456 #[fasync::run_singlethreaded(test)]
1458 async fn down_scroll_up_scroll() {
1459 const PRIMARY_BUTTON: u8 = 1;
1460
1461 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1462 let first_report = testing_utilities::create_mouse_input_report_relative(
1463 Position::zero(),
1464 None, None, vec![PRIMARY_BUTTON],
1467 event_time_i64,
1468 );
1469 let second_report = testing_utilities::create_mouse_input_report_relative(
1470 Position::zero(),
1471 Some(1),
1472 None,
1473 vec![PRIMARY_BUTTON],
1474 event_time_i64,
1475 );
1476 let third_report = testing_utilities::create_mouse_input_report_relative(
1477 Position::zero(),
1478 None, None, vec![],
1481 event_time_i64,
1482 );
1483 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1484 Position::zero(),
1485 Some(1),
1486 None,
1487 vec![],
1488 event_time_i64,
1489 );
1490
1491 let descriptor = mouse_device_descriptor(DEVICE_ID);
1492
1493 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1494 let expected_events = vec![
1495 testing_utilities::create_mouse_event(
1496 MouseLocation::Relative(Default::default()),
1497 None, None, None, MousePhase::Down,
1501 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1502 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1503 event_time_u64,
1504 &descriptor,
1505 ),
1506 testing_utilities::create_mouse_event(
1507 MouseLocation::Relative(Default::default()),
1508 wheel_delta_ticks(1),
1509 None,
1510 Some(PrecisionScroll::No),
1511 MousePhase::Wheel,
1512 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1513 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1514 event_time_u64,
1515 &descriptor,
1516 ),
1517 testing_utilities::create_mouse_event(
1518 MouseLocation::Relative(Default::default()),
1519 None, None, None, MousePhase::Up,
1523 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1524 HashSet::new(),
1525 event_time_u64,
1526 &descriptor,
1527 ),
1528 testing_utilities::create_mouse_event(
1529 MouseLocation::Relative(Default::default()),
1530 wheel_delta_ticks(1),
1531 None,
1532 Some(PrecisionScroll::No),
1533 MousePhase::Wheel,
1534 HashSet::new(),
1535 HashSet::new(),
1536 event_time_u64,
1537 &descriptor,
1538 ),
1539 ];
1540
1541 assert_input_report_sequence_generates_events!(
1542 input_reports: input_reports,
1543 expected_events: expected_events,
1544 device_descriptor: descriptor,
1545 device_type: MouseBinding,
1546 );
1547 }
1548
1549 #[fasync::run_singlethreaded(test)]
1551 async fn down_scroll_bundle_up_scroll_bundle() {
1552 const PRIMARY_BUTTON: u8 = 1;
1553
1554 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1555 let first_report = testing_utilities::create_mouse_input_report_relative(
1556 Position::zero(),
1557 Some(1),
1558 None,
1559 vec![PRIMARY_BUTTON],
1560 event_time_i64,
1561 );
1562 let second_report = testing_utilities::create_mouse_input_report_relative(
1563 Position::zero(),
1564 Some(1),
1565 None,
1566 vec![],
1567 event_time_i64,
1568 );
1569 let third_report = testing_utilities::create_mouse_input_report_relative(
1570 Position::zero(),
1571 Some(1),
1572 None,
1573 vec![],
1574 event_time_i64,
1575 );
1576
1577 let descriptor = mouse_device_descriptor(DEVICE_ID);
1578
1579 let input_reports = vec![first_report, second_report, third_report];
1580 let expected_events = vec![
1581 testing_utilities::create_mouse_event(
1582 MouseLocation::Relative(Default::default()),
1583 None, None, None, MousePhase::Down,
1587 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1588 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1589 event_time_u64,
1590 &descriptor,
1591 ),
1592 testing_utilities::create_mouse_event(
1593 MouseLocation::Relative(Default::default()),
1594 wheel_delta_ticks(1),
1595 None,
1596 Some(PrecisionScroll::No),
1597 MousePhase::Wheel,
1598 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1599 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1600 event_time_u64,
1601 &descriptor,
1602 ),
1603 testing_utilities::create_mouse_event(
1604 MouseLocation::Relative(Default::default()),
1605 wheel_delta_ticks(1),
1606 None,
1607 Some(PrecisionScroll::No),
1608 MousePhase::Wheel,
1609 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1610 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1611 event_time_u64,
1612 &descriptor,
1613 ),
1614 testing_utilities::create_mouse_event(
1615 MouseLocation::Relative(Default::default()),
1616 None, None, None, MousePhase::Up,
1620 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1621 HashSet::new(),
1622 event_time_u64,
1623 &descriptor,
1624 ),
1625 testing_utilities::create_mouse_event(
1626 MouseLocation::Relative(Default::default()),
1627 wheel_delta_ticks(1),
1628 None,
1629 Some(PrecisionScroll::No),
1630 MousePhase::Wheel,
1631 HashSet::new(),
1632 HashSet::new(),
1633 event_time_u64,
1634 &descriptor,
1635 ),
1636 ];
1637
1638 assert_input_report_sequence_generates_events!(
1639 input_reports: input_reports,
1640 expected_events: expected_events,
1641 device_descriptor: descriptor,
1642 device_type: MouseBinding,
1643 );
1644 }
1645}