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 futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
15use metrics_registry::*;
16use std::collections::HashSet;
17use std::sync::Mutex;
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 Self {
130 location: self.location,
131 wheel_delta_v: self.wheel_delta_v.clone(),
132 wheel_delta_h: self.wheel_delta_h.clone(),
133 is_precision_scroll: self.is_precision_scroll,
134 phase: self.phase,
135 affected_buttons: self.affected_buttons.clone(),
136 pressed_buttons: self.pressed_buttons.clone(),
137 wake_lease: Mutex::new(self.wake_lease.lock().unwrap().as_ref().map(|lease| {
138 lease
139 .duplicate_handle(zx::Rights::SAME_RIGHTS)
140 .expect("failed to duplicate event pair")
141 })),
142 }
143 }
144}
145
146impl PartialEq for MouseEvent {
147 fn eq(&self, other: &Self) -> bool {
148 self.location == other.location
149 && self.wheel_delta_v == other.wheel_delta_v
150 && self.wheel_delta_h == other.wheel_delta_h
151 && self.is_precision_scroll == other.is_precision_scroll
152 && self.phase == other.phase
153 && self.affected_buttons == other.affected_buttons
154 && self.pressed_buttons == other.pressed_buttons
155 }
156}
157
158impl MouseEvent {
159 pub fn new(
167 location: MouseLocation,
168 wheel_delta_v: Option<WheelDelta>,
169 wheel_delta_h: Option<WheelDelta>,
170 phase: MousePhase,
171 affected_buttons: HashSet<MouseButton>,
172 pressed_buttons: HashSet<MouseButton>,
173 is_precision_scroll: Option<PrecisionScroll>,
174 wake_lease: Option<zx::EventPair>,
175 ) -> MouseEvent {
176 MouseEvent {
177 location,
178 wheel_delta_v,
179 wheel_delta_h,
180 phase,
181 affected_buttons,
182 pressed_buttons,
183 is_precision_scroll,
184 wake_lease: Mutex::new(wake_lease),
185 }
186 }
187
188 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
189 match self.location {
190 MouseLocation::Relative(pos) => {
191 node.record_child("location_relative", move |location_node| {
192 location_node.record_double("x", f64::from(pos.millimeters.x));
193 location_node.record_double("y", f64::from(pos.millimeters.y));
194 })
195 }
196 MouseLocation::Absolute(pos) => {
197 node.record_child("location_absolute", move |location_node| {
198 location_node.record_double("x", f64::from(pos.x));
199 location_node.record_double("y", f64::from(pos.y));
200 })
201 }
202 };
203
204 if let Some(wheel_delta_v) = &self.wheel_delta_v {
205 node.record_child("wheel_delta_v", move |wheel_delta_v_node| {
206 match wheel_delta_v.raw_data {
207 RawWheelDelta::Ticks(ticks) => wheel_delta_v_node.record_int("ticks", ticks),
208 RawWheelDelta::Millimeters(mm) => {
209 wheel_delta_v_node.record_double("millimeters", f64::from(mm))
210 }
211 }
212 if let Some(physical_pixel) = wheel_delta_v.physical_pixel {
213 wheel_delta_v_node.record_double("physical_pixel", f64::from(physical_pixel));
214 }
215 });
216 }
217
218 if let Some(wheel_delta_h) = &self.wheel_delta_h {
219 node.record_child("wheel_delta_h", move |wheel_delta_h_node| {
220 match wheel_delta_h.raw_data {
221 RawWheelDelta::Ticks(ticks) => wheel_delta_h_node.record_int("ticks", ticks),
222 RawWheelDelta::Millimeters(mm) => {
223 wheel_delta_h_node.record_double("millimeters", f64::from(mm))
224 }
225 }
226 if let Some(physical_pixel) = wheel_delta_h.physical_pixel {
227 wheel_delta_h_node.record_double("physical_pixel", f64::from(physical_pixel));
228 }
229 });
230 }
231
232 if let Some(is_precision_scroll) = self.is_precision_scroll {
233 match is_precision_scroll {
234 PrecisionScroll::Yes => node.record_string("is_precision_scroll", "yes"),
235 PrecisionScroll::No => node.record_string("is_precision_scroll", "no"),
236 }
237 }
238
239 match self.phase {
240 MousePhase::Down => node.record_string("phase", "down"),
241 MousePhase::Move => node.record_string("phase", "move"),
242 MousePhase::Up => node.record_string("phase", "up"),
243 MousePhase::Wheel => node.record_string("phase", "wheel"),
244 }
245
246 let affected_buttons_node =
247 node.create_uint_array("affected_buttons", self.affected_buttons.len());
248 self.affected_buttons.iter().enumerate().for_each(|(i, button)| {
249 affected_buttons_node.set(i, *button);
250 });
251 node.record(affected_buttons_node);
252
253 let pressed_buttons_node =
254 node.create_uint_array("pressed_buttons", self.pressed_buttons.len());
255 self.pressed_buttons.iter().enumerate().for_each(|(i, button)| {
256 pressed_buttons_node.set(i, *button);
257 });
258 node.record(pressed_buttons_node);
259 }
260}
261
262pub struct MouseBinding {
268 event_sender: UnboundedSender<input_device::InputEvent>,
270
271 device_descriptor: MouseDeviceDescriptor,
273}
274
275#[derive(Clone, Debug, Eq, PartialEq)]
276pub struct MouseDeviceDescriptor {
277 pub device_id: u32,
279
280 pub absolute_x_range: Option<fidl_input_report::Range>,
282
283 pub absolute_y_range: Option<fidl_input_report::Range>,
285
286 pub wheel_v_range: Option<fidl_input_report::Axis>,
288
289 pub wheel_h_range: Option<fidl_input_report::Axis>,
291
292 pub buttons: Option<Vec<MouseButton>>,
294
295 pub counts_per_mm: u32,
298}
299
300#[async_trait]
301impl input_device::InputDeviceBinding for MouseBinding {
302 fn input_event_sender(&self) -> UnboundedSender<input_device::InputEvent> {
303 self.event_sender.clone()
304 }
305
306 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
307 input_device::InputDeviceDescriptor::Mouse(self.device_descriptor.clone())
308 }
309}
310
311impl MouseBinding {
312 pub async fn new(
327 device_proxy: InputDeviceProxy,
328 device_id: u32,
329 input_event_sender: UnboundedSender<input_device::InputEvent>,
330 device_node: fuchsia_inspect::Node,
331 metrics_logger: metrics::MetricsLogger,
332 ) -> Result<Self, Error> {
333 let (device_binding, mut inspect_status) =
334 Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
335 inspect_status.health_node.set_ok();
336 input_device::initialize_report_stream(
337 device_proxy,
338 device_binding.get_device_descriptor(),
339 device_binding.input_event_sender(),
340 inspect_status,
341 metrics_logger,
342 Self::process_reports,
343 );
344
345 Ok(device_binding)
346 }
347
348 async fn bind_device(
360 device: &InputDeviceProxy,
361 device_id: u32,
362 input_event_sender: UnboundedSender<input_device::InputEvent>,
363 device_node: fuchsia_inspect::Node,
364 ) -> Result<(Self, InputDeviceStatus), Error> {
365 let mut input_device_status = InputDeviceStatus::new(device_node);
366 let device_descriptor: fidl_input_report::DeviceDescriptor = match device
367 .get_descriptor()
368 .await
369 {
370 Ok(descriptor) => descriptor,
371 Err(_) => {
372 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
373 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
374 }
375 };
376
377 let mouse_descriptor = device_descriptor.mouse.ok_or_else(|| {
378 input_device_status
379 .health_node
380 .set_unhealthy("DeviceDescriptor does not have a MouseDescriptor.");
381 format_err!("DeviceDescriptor does not have a MouseDescriptor")
382 })?;
383
384 let mouse_input_descriptor = mouse_descriptor.input.ok_or_else(|| {
385 input_device_status
386 .health_node
387 .set_unhealthy("MouseDescriptor does not have a MouseInputDescriptor.");
388 format_err!("MouseDescriptor does not have a MouseInputDescriptor")
389 })?;
390
391 let model = mouse_model_database::db::get_mouse_model(device_descriptor.device_information);
392
393 let device_descriptor: MouseDeviceDescriptor = MouseDeviceDescriptor {
394 device_id,
395 absolute_x_range: mouse_input_descriptor.position_x.map(|axis| axis.range),
396 absolute_y_range: mouse_input_descriptor.position_y.map(|axis| axis.range),
397 wheel_v_range: mouse_input_descriptor.scroll_v,
398 wheel_h_range: mouse_input_descriptor.scroll_h,
399 buttons: mouse_input_descriptor.buttons,
400 counts_per_mm: model.counts_per_mm,
401 };
402
403 Ok((
404 MouseBinding { event_sender: input_event_sender, device_descriptor },
405 input_device_status,
406 ))
407 }
408
409 fn process_reports(
429 mut report: InputReport,
430 previous_report: Option<InputReport>,
431 device_descriptor: &input_device::InputDeviceDescriptor,
432 input_event_sender: &mut UnboundedSender<input_device::InputEvent>,
433 inspect_status: &InputDeviceStatus,
434 metrics_logger: &metrics::MetricsLogger,
435 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
436 fuchsia_trace::duration!(c"input", c"mouse-binding-process-report");
437 if let Some(trace_id) = report.trace_id {
438 fuchsia_trace::flow_end!(c"input", c"input_report", trace_id.into());
439 }
440
441 inspect_status.count_received_report(&report);
442 let mouse_report: &fidl_input_report::MouseInputReport = match &report.mouse {
444 Some(mouse) => mouse,
445 None => {
446 inspect_status.count_filtered_report();
447 return (previous_report, None);
448 }
449 };
450
451 let previous_buttons: HashSet<MouseButton> =
452 buttons_from_optional_report(&previous_report.as_ref());
453 let current_buttons: HashSet<MouseButton> = buttons_from_report(&report);
454 let wake_lease = report.wake_lease.take();
455
456 send_mouse_event(
462 MouseLocation::Relative(Default::default()),
463 None, None, MousePhase::Down,
466 current_buttons.difference(&previous_buttons).cloned().collect(),
467 current_buttons.clone(),
468 device_descriptor,
469 input_event_sender,
470 inspect_status,
471 metrics_logger,
472 wake_lease.as_ref().map(|lease| {
473 lease
474 .duplicate_handle(zx::Rights::SAME_RIGHTS)
475 .expect("failed to duplicate event pair")
476 }),
477 );
478
479 let counts_per_mm = match device_descriptor {
480 input_device::InputDeviceDescriptor::Mouse(ds) => ds.counts_per_mm,
481 _ => {
482 metrics_logger.log_error(
483 InputPipelineErrorMetricDimensionEvent::MouseDescriptionNotMouse,
484 "mouse_binding::process_reports got device_descriptor not mouse".to_string(),
485 );
486 mouse_model_database::db::DEFAULT_COUNTS_PER_MM
487 }
488 };
489
490 let location = if let (Some(position_x), Some(position_y)) =
492 (mouse_report.position_x, mouse_report.position_y)
493 {
494 MouseLocation::Absolute(Position { x: position_x as f32, y: position_y as f32 })
495 } else {
496 let movement_x = mouse_report.movement_x.unwrap_or_default() as f32;
497 let movement_y = mouse_report.movement_y.unwrap_or_default() as f32;
498 MouseLocation::Relative(RelativeLocation {
499 millimeters: Position {
500 x: movement_x / counts_per_mm as f32,
501 y: movement_y / counts_per_mm as f32,
502 },
503 })
504 };
505
506 send_mouse_event(
510 location,
511 None, None, MousePhase::Move,
514 current_buttons.union(&previous_buttons).cloned().collect(),
515 current_buttons.union(&previous_buttons).cloned().collect(),
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 wheel_delta_v = match mouse_report.scroll_v {
528 None => None,
529 Some(ticks) => {
530 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
531 }
532 };
533
534 let wheel_delta_h = match mouse_report.scroll_h {
535 None => None,
536 Some(ticks) => {
537 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
538 }
539 };
540
541 send_mouse_event(
543 MouseLocation::Relative(Default::default()),
544 wheel_delta_v,
545 wheel_delta_h,
546 MousePhase::Wheel,
547 current_buttons.union(&previous_buttons).cloned().collect(),
548 current_buttons.union(&previous_buttons).cloned().collect(),
549 device_descriptor,
550 input_event_sender,
551 inspect_status,
552 metrics_logger,
553 wake_lease.as_ref().map(|lease| {
554 lease
555 .duplicate_handle(zx::Rights::SAME_RIGHTS)
556 .expect("failed to duplicate event pair")
557 }),
558 );
559
560 send_mouse_event(
566 MouseLocation::Relative(Default::default()),
567 None, None, MousePhase::Up,
570 previous_buttons.difference(¤t_buttons).cloned().collect(),
571 current_buttons.clone(),
572 device_descriptor,
573 input_event_sender,
574 inspect_status,
575 metrics_logger,
576 wake_lease,
577 );
578
579 (Some(report), None)
580 }
581}
582
583fn send_mouse_event(
598 location: MouseLocation,
599 wheel_delta_v: Option<WheelDelta>,
600 wheel_delta_h: Option<WheelDelta>,
601 phase: MousePhase,
602 affected_buttons: HashSet<MouseButton>,
603 pressed_buttons: HashSet<MouseButton>,
604 device_descriptor: &input_device::InputDeviceDescriptor,
605 sender: &mut UnboundedSender<input_device::InputEvent>,
606 inspect_status: &InputDeviceStatus,
607 metrics_logger: &metrics::MetricsLogger,
608 wake_lease: Option<zx::EventPair>,
609) {
610 if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
612 return;
613 }
614
615 if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
618 return;
619 }
620
621 if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
623 return;
624 }
625
626 let trace_id = fuchsia_trace::Id::random();
627 fuchsia_trace::duration!(c"input", c"mouse-binding-send-event");
628 fuchsia_trace::flow_begin!(c"input", c"event_in_input_pipeline", trace_id);
629
630 let event = input_device::InputEvent {
631 device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
632 location,
633 wheel_delta_v,
634 wheel_delta_h,
635 phase,
636 affected_buttons,
637 pressed_buttons,
638 match phase {
639 MousePhase::Wheel => Some(PrecisionScroll::No),
640 _ => None,
641 },
642 wake_lease,
643 )),
644 device_descriptor: device_descriptor.clone(),
645 event_time: zx::MonotonicInstant::get(),
646 handled: Handled::No,
647 trace_id: Some(trace_id),
648 };
649
650 match sender.unbounded_send(event.clone()) {
651 Err(e) => {
652 metrics_logger.log_error(
653 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
654 std::format!("Failed to send MouseEvent with error: {:?}", e),
655 );
656 }
657 _ => inspect_status.count_generated_event(event),
658 }
659}
660
661pub fn get_u32_from_buttons(buttons: &HashSet<MouseButton>) -> u32 {
675 let mut bits: u32 = 0;
676 for button in buttons {
677 if *button > 0 && *button <= fidl_input_report::MOUSE_MAX_NUM_BUTTONS as u8 {
678 bits = ((1 as u32) << *button - 1) | bits;
679 }
680 }
681
682 bits
683}
684
685fn buttons_from_report(input_report: &fidl_input_report::InputReport) -> HashSet<MouseButton> {
690 buttons_from_optional_report(&Some(input_report))
691}
692
693fn buttons_from_optional_report(
698 input_report: &Option<&fidl_input_report::InputReport>,
699) -> HashSet<MouseButton> {
700 input_report
701 .as_ref()
702 .and_then(|unwrapped_report| unwrapped_report.mouse.as_ref())
703 .and_then(|mouse_report| match &mouse_report.pressed_buttons {
704 Some(buttons) => Some(HashSet::from_iter(buttons.iter().cloned())),
705 None => None,
706 })
707 .unwrap_or_default()
708}
709
710#[cfg(test)]
711mod tests {
712 use super::*;
713 use crate::testing_utilities;
714 use fuchsia_async as fasync;
715 use futures::StreamExt;
716 use pretty_assertions::assert_eq;
717
718 const DEVICE_ID: u32 = 1;
719 const COUNTS_PER_MM: u32 = 12;
720
721 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
722 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
723 device_id,
724 absolute_x_range: None,
725 absolute_y_range: None,
726 wheel_v_range: Some(fidl_fuchsia_input_report::Axis {
727 range: fidl_input_report::Range { min: -1, max: 1 },
728 unit: fidl_input_report::Unit {
729 type_: fidl_input_report::UnitType::Other,
730 exponent: 1,
731 },
732 }),
733 wheel_h_range: Some(fidl_fuchsia_input_report::Axis {
734 range: fidl_input_report::Range { min: -1, max: 1 },
735 unit: fidl_input_report::Unit {
736 type_: fidl_input_report::UnitType::Other,
737 exponent: 1,
738 },
739 }),
740 buttons: None,
741 counts_per_mm: COUNTS_PER_MM,
742 })
743 }
744
745 fn wheel_delta_ticks(delta: i64) -> Option<WheelDelta> {
746 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(delta), physical_pixel: None })
747 }
748
749 #[test]
751 fn get_u32_from_buttons_test() {
752 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, 5].into_iter()));
753 assert_eq!(bits, 21 )
754 }
755
756 #[test]
758 fn get_u32_with_0_in_vector() {
759 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![0, 1, 3].into_iter()));
760 assert_eq!(bits, 5 )
761 }
762
763 #[test]
765 fn get_u32_with_empty_vector() {
766 let bits = get_u32_from_buttons(&HashSet::new());
767 assert_eq!(bits, 0 )
768 }
769
770 #[test]
772 fn get_u32_with_u8_max_in_vector() {
773 let bits = get_u32_from_buttons(&HashSet::from_iter(vec![1, 3, std::u8::MAX].into_iter()));
774 assert_eq!(bits, 5 )
775 }
776
777 #[test]
780 fn get_u32_with_max_mouse_buttons() {
781 let bits = get_u32_from_buttons(&HashSet::from_iter(
782 vec![1, 3, fidl_input_report::MOUSE_MAX_NUM_BUTTONS as MouseButton].into_iter(),
783 ));
784 assert_eq!(bits, 2147483653 )
785 }
786
787 #[fasync::run_singlethreaded(test)]
789 async fn movement_without_button() {
790 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
791 let first_report = testing_utilities::create_mouse_input_report_relative(
792 Position { x: 10.0, y: 16.0 },
793 None, None, vec![],
796 event_time_i64,
797 );
798 let descriptor = mouse_device_descriptor(DEVICE_ID);
799
800 let input_reports = vec![first_report];
801 let expected_events = vec![testing_utilities::create_mouse_event(
802 MouseLocation::Relative(RelativeLocation {
803 millimeters: Position {
804 x: 10.0 / COUNTS_PER_MM as f32,
805 y: 16.0 / COUNTS_PER_MM as f32,
806 },
807 }),
808 None, None, None, MousePhase::Move,
812 HashSet::new(),
813 HashSet::new(),
814 event_time_u64,
815 &descriptor,
816 )];
817
818 assert_input_report_sequence_generates_events!(
819 input_reports: input_reports,
820 expected_events: expected_events,
821 device_descriptor: descriptor,
822 device_type: MouseBinding,
823 );
824 }
825
826 #[fasync::run_singlethreaded(test)]
828 async fn down_without_movement() {
829 let mouse_button: MouseButton = 3;
830 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
831 let first_report = testing_utilities::create_mouse_input_report_relative(
832 Position::zero(),
833 None, None, vec![mouse_button],
836 event_time_i64,
837 );
838 let descriptor = mouse_device_descriptor(DEVICE_ID);
839
840 let input_reports = vec![first_report];
841 let expected_events = vec![testing_utilities::create_mouse_event(
842 MouseLocation::Relative(Default::default()),
843 None, None, None, MousePhase::Down,
847 HashSet::from_iter(vec![mouse_button].into_iter()),
848 HashSet::from_iter(vec![mouse_button].into_iter()),
849 event_time_u64,
850 &descriptor,
851 )];
852
853 assert_input_report_sequence_generates_events!(
854 input_reports: input_reports,
855 expected_events: expected_events,
856 device_descriptor: descriptor,
857 device_type: MouseBinding,
858 );
859 }
860
861 #[fasync::run_singlethreaded(test)]
864 async fn down_with_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 { x: 10.0, y: 16.0 },
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![
878 testing_utilities::create_mouse_event(
879 MouseLocation::Relative(Default::default()),
880 None, None, None, MousePhase::Down,
884 HashSet::from_iter(vec![mouse_button].into_iter()),
885 HashSet::from_iter(vec![mouse_button].into_iter()),
886 event_time_u64,
887 &descriptor,
888 ),
889 testing_utilities::create_mouse_event(
890 MouseLocation::Relative(RelativeLocation {
891 millimeters: Position {
892 x: 10.0 / COUNTS_PER_MM as f32,
893 y: 16.0 / COUNTS_PER_MM as f32,
894 },
895 }),
896 None, None, None, MousePhase::Move,
900 HashSet::from_iter(vec![mouse_button].into_iter()),
901 HashSet::from_iter(vec![mouse_button].into_iter()),
902 event_time_u64,
903 &descriptor,
904 ),
905 ];
906
907 assert_input_report_sequence_generates_events!(
908 input_reports: input_reports,
909 expected_events: expected_events,
910 device_descriptor: descriptor,
911 device_type: MouseBinding,
912 );
913 }
914
915 #[fasync::run_singlethreaded(test)]
917 async fn down_up() {
918 let button = 1;
919 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
920 let first_report = testing_utilities::create_mouse_input_report_relative(
921 Position::zero(),
922 None, None, vec![button],
925 event_time_i64,
926 );
927 let second_report = testing_utilities::create_mouse_input_report_relative(
928 Position::zero(),
929 None, None, vec![],
932 event_time_i64,
933 );
934 let descriptor = mouse_device_descriptor(DEVICE_ID);
935
936 let input_reports = vec![first_report, second_report];
937 let expected_events = vec![
938 testing_utilities::create_mouse_event(
939 MouseLocation::Relative(Default::default()),
940 None, None, None, MousePhase::Down,
944 HashSet::from_iter(vec![button].into_iter()),
945 HashSet::from_iter(vec![button].into_iter()),
946 event_time_u64,
947 &descriptor,
948 ),
949 testing_utilities::create_mouse_event(
950 MouseLocation::Relative(Default::default()),
951 None, None, None, MousePhase::Up,
955 HashSet::from_iter(vec![button].into_iter()),
956 HashSet::new(),
957 event_time_u64,
958 &descriptor,
959 ),
960 ];
961
962 assert_input_report_sequence_generates_events!(
963 input_reports: input_reports,
964 expected_events: expected_events,
965 device_descriptor: descriptor,
966 device_type: MouseBinding,
967 );
968 }
969
970 #[fasync::run_singlethreaded(test)]
972 async fn down_up_with_movement() {
973 let button = 1;
974
975 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
976 let first_report = testing_utilities::create_mouse_input_report_relative(
977 Position::zero(),
978 None, None, vec![button],
981 event_time_i64,
982 );
983 let second_report = testing_utilities::create_mouse_input_report_relative(
984 Position { x: 10.0, y: 16.0 },
985 None, None, vec![],
988 event_time_i64,
989 );
990 let descriptor = mouse_device_descriptor(DEVICE_ID);
991
992 let input_reports = vec![first_report, second_report];
993 let expected_events = vec![
994 testing_utilities::create_mouse_event(
995 MouseLocation::Relative(Default::default()),
996 None, None, None, MousePhase::Down,
1000 HashSet::from_iter(vec![button].into_iter()),
1001 HashSet::from_iter(vec![button].into_iter()),
1002 event_time_u64,
1003 &descriptor,
1004 ),
1005 testing_utilities::create_mouse_event(
1006 MouseLocation::Relative(RelativeLocation {
1007 millimeters: Position {
1008 x: 10.0 / COUNTS_PER_MM as f32,
1009 y: 16.0 / COUNTS_PER_MM as f32,
1010 },
1011 }),
1012 None, None, None, MousePhase::Move,
1016 HashSet::from_iter(vec![button].into_iter()),
1017 HashSet::from_iter(vec![button].into_iter()),
1018 event_time_u64,
1019 &descriptor,
1020 ),
1021 testing_utilities::create_mouse_event(
1022 MouseLocation::Relative(Default::default()),
1023 None, None, None, MousePhase::Up,
1027 HashSet::from_iter(vec![button].into_iter()),
1028 HashSet::new(),
1029 event_time_u64,
1030 &descriptor,
1031 ),
1032 ];
1033
1034 assert_input_report_sequence_generates_events!(
1035 input_reports: input_reports,
1036 expected_events: expected_events,
1037 device_descriptor: descriptor,
1038 device_type: MouseBinding,
1039 );
1040 }
1041
1042 #[fasync::run_singlethreaded(test)]
1046 async fn down_move_up() {
1047 let button = 1;
1048
1049 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1050 let first_report = testing_utilities::create_mouse_input_report_relative(
1051 Position::zero(),
1052 None, None, vec![button],
1055 event_time_i64,
1056 );
1057 let second_report = testing_utilities::create_mouse_input_report_relative(
1058 Position { x: 10.0, y: 16.0 },
1059 None, None, vec![button],
1062 event_time_i64,
1063 );
1064 let third_report = testing_utilities::create_mouse_input_report_relative(
1065 Position::zero(),
1066 None, None, vec![],
1069 event_time_i64,
1070 );
1071 let descriptor = mouse_device_descriptor(DEVICE_ID);
1072
1073 let input_reports = vec![first_report, second_report, third_report];
1074 let expected_events = vec![
1075 testing_utilities::create_mouse_event(
1076 MouseLocation::Relative(Default::default()),
1077 None, None, None, MousePhase::Down,
1081 HashSet::from_iter(vec![button].into_iter()),
1082 HashSet::from_iter(vec![button].into_iter()),
1083 event_time_u64,
1084 &descriptor,
1085 ),
1086 testing_utilities::create_mouse_event(
1087 MouseLocation::Relative(RelativeLocation {
1088 millimeters: Position {
1089 x: 10.0 / COUNTS_PER_MM as f32,
1090 y: 16.0 / COUNTS_PER_MM as f32,
1091 },
1092 }),
1093 None, None, None, MousePhase::Move,
1097 HashSet::from_iter(vec![button].into_iter()),
1098 HashSet::from_iter(vec![button].into_iter()),
1099 event_time_u64,
1100 &descriptor,
1101 ),
1102 testing_utilities::create_mouse_event(
1103 MouseLocation::Relative(Default::default()),
1104 None, None, None, MousePhase::Up,
1108 HashSet::from_iter(vec![button].into_iter()),
1109 HashSet::new(),
1110 event_time_u64,
1111 &descriptor,
1112 ),
1113 ];
1114
1115 assert_input_report_sequence_generates_events!(
1116 input_reports: input_reports,
1117 expected_events: expected_events,
1118 device_descriptor: descriptor,
1119 device_type: MouseBinding,
1120 );
1121 }
1122
1123 #[fasync::run_until_stalled(test)]
1125 async fn absolute_movement_to_origin() {
1126 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1127 let descriptor = mouse_device_descriptor(DEVICE_ID);
1128
1129 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
1130 Position::zero(),
1131 None, None, vec![],
1134 event_time_i64,
1135 )];
1136 let expected_events = vec![testing_utilities::create_mouse_event(
1137 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1138 None, None, None, MousePhase::Move,
1142 HashSet::new(),
1143 HashSet::new(),
1144 event_time_u64,
1145 &descriptor,
1146 )];
1147
1148 assert_input_report_sequence_generates_events!(
1149 input_reports: input_reports,
1150 expected_events: expected_events,
1151 device_descriptor: descriptor,
1152 device_type: MouseBinding,
1153 );
1154 }
1155
1156 #[fasync::run_until_stalled(test)]
1159 async fn report_with_both_movement_and_position() {
1160 let relative_movement = Position { x: 5.0, y: 5.0 };
1161 let absolute_position = Position { x: 10.0, y: 10.0 };
1162 let expected_location = MouseLocation::Absolute(absolute_position);
1163
1164 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1165 let descriptor = mouse_device_descriptor(DEVICE_ID);
1166
1167 let input_reports = vec![fidl_input_report::InputReport {
1168 event_time: Some(event_time_i64),
1169 keyboard: None,
1170 mouse: Some(fidl_input_report::MouseInputReport {
1171 movement_x: Some(relative_movement.x as i64),
1172 movement_y: Some(relative_movement.y as i64),
1173 position_x: Some(absolute_position.x as i64),
1174 position_y: Some(absolute_position.y as i64),
1175 scroll_h: None,
1176 scroll_v: None,
1177 pressed_buttons: None,
1178 ..Default::default()
1179 }),
1180 touch: None,
1181 sensor: None,
1182 consumer_control: None,
1183 trace_id: None,
1184 ..Default::default()
1185 }];
1186 let expected_events = vec![testing_utilities::create_mouse_event(
1187 expected_location,
1188 None, None, None, MousePhase::Move,
1192 HashSet::new(),
1193 HashSet::new(),
1194 event_time_u64,
1195 &descriptor,
1196 )];
1197
1198 assert_input_report_sequence_generates_events!(
1199 input_reports: input_reports,
1200 expected_events: expected_events,
1201 device_descriptor: descriptor,
1202 device_type: MouseBinding,
1203 );
1204 }
1205
1206 #[fasync::run_singlethreaded(test)]
1209 async fn down_down() {
1210 const PRIMARY_BUTTON: u8 = 1;
1211 const SECONDARY_BUTTON: u8 = 2;
1212
1213 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1214 let first_report = testing_utilities::create_mouse_input_report_relative(
1215 Position::zero(),
1216 None, None, vec![PRIMARY_BUTTON],
1219 event_time_i64,
1220 );
1221 let second_report = testing_utilities::create_mouse_input_report_relative(
1222 Position::zero(),
1223 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1226 event_time_i64,
1227 );
1228 let descriptor = mouse_device_descriptor(DEVICE_ID);
1229
1230 let input_reports = vec![first_report, second_report];
1231 let expected_events = vec![
1232 testing_utilities::create_mouse_event(
1233 MouseLocation::Relative(Default::default()),
1234 None, None, None, MousePhase::Down,
1238 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1239 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1240 event_time_u64,
1241 &descriptor,
1242 ),
1243 testing_utilities::create_mouse_event(
1244 MouseLocation::Relative(Default::default()),
1245 None, None, None, MousePhase::Down,
1249 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1250 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1251 event_time_u64,
1252 &descriptor,
1253 ),
1254 ];
1255
1256 assert_input_report_sequence_generates_events!(
1257 input_reports: input_reports,
1258 expected_events: expected_events,
1259 device_descriptor: descriptor,
1260 device_type: MouseBinding,
1261 );
1262 }
1263
1264 #[fasync::run_singlethreaded(test)]
1274 async fn down_down_up_up() {
1275 const PRIMARY_BUTTON: u8 = 1;
1276 const SECONDARY_BUTTON: u8 = 2;
1277
1278 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1279 let first_report = testing_utilities::create_mouse_input_report_relative(
1280 Position::zero(),
1281 None, None, vec![PRIMARY_BUTTON],
1284 event_time_i64,
1285 );
1286 let second_report = testing_utilities::create_mouse_input_report_relative(
1287 Position::zero(),
1288 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1291 event_time_i64,
1292 );
1293 let third_report = testing_utilities::create_mouse_input_report_relative(
1294 Position::zero(),
1295 None, None, vec![SECONDARY_BUTTON],
1298 event_time_i64,
1299 );
1300 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1301 Position::zero(),
1302 None, None, vec![],
1305 event_time_i64,
1306 );
1307 let descriptor = mouse_device_descriptor(DEVICE_ID);
1308
1309 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1310 let expected_events = vec![
1311 testing_utilities::create_mouse_event(
1312 MouseLocation::Relative(Default::default()),
1313 None, None, None, MousePhase::Down,
1317 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1318 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1319 event_time_u64,
1320 &descriptor,
1321 ),
1322 testing_utilities::create_mouse_event(
1323 MouseLocation::Relative(Default::default()),
1324 None, None, None, MousePhase::Down,
1328 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1329 HashSet::from_iter(vec![PRIMARY_BUTTON, SECONDARY_BUTTON].into_iter()),
1330 event_time_u64,
1331 &descriptor,
1332 ),
1333 testing_utilities::create_mouse_event(
1334 MouseLocation::Relative(Default::default()),
1335 None, None, None, MousePhase::Up,
1339 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1340 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1341 event_time_u64,
1342 &descriptor,
1343 ),
1344 testing_utilities::create_mouse_event(
1345 MouseLocation::Relative(Default::default()),
1346 None, None, None, MousePhase::Up,
1350 HashSet::from_iter(vec![SECONDARY_BUTTON].into_iter()),
1351 HashSet::new(),
1352 event_time_u64,
1353 &descriptor,
1354 ),
1355 ];
1356
1357 assert_input_report_sequence_generates_events!(
1358 input_reports: input_reports,
1359 expected_events: expected_events,
1360 device_descriptor: descriptor,
1361 device_type: MouseBinding,
1362 );
1363 }
1364
1365 #[fasync::run_singlethreaded(test)]
1367 async fn scroll() {
1368 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1369 let first_report = testing_utilities::create_mouse_input_report_relative(
1370 Position::zero(),
1371 Some(1),
1372 None,
1373 vec![],
1374 event_time_i64,
1375 );
1376 let second_report = testing_utilities::create_mouse_input_report_relative(
1377 Position::zero(),
1378 None,
1379 Some(1),
1380 vec![],
1381 event_time_i64,
1382 );
1383
1384 let descriptor = mouse_device_descriptor(DEVICE_ID);
1385
1386 let input_reports = vec![first_report, second_report];
1387 let expected_events = vec![
1388 testing_utilities::create_mouse_event(
1389 MouseLocation::Relative(Default::default()),
1390 wheel_delta_ticks(1),
1391 None,
1392 Some(PrecisionScroll::No),
1393 MousePhase::Wheel,
1394 HashSet::new(),
1395 HashSet::new(),
1396 event_time_u64,
1397 &descriptor,
1398 ),
1399 testing_utilities::create_mouse_event(
1400 MouseLocation::Relative(Default::default()),
1401 None,
1402 wheel_delta_ticks(1),
1403 Some(PrecisionScroll::No),
1404 MousePhase::Wheel,
1405 HashSet::new(),
1406 HashSet::new(),
1407 event_time_u64,
1408 &descriptor,
1409 ),
1410 ];
1411
1412 assert_input_report_sequence_generates_events!(
1413 input_reports: input_reports,
1414 expected_events: expected_events,
1415 device_descriptor: descriptor,
1416 device_type: MouseBinding,
1417 );
1418 }
1419
1420 #[fasync::run_singlethreaded(test)]
1422 async fn down_scroll_up_scroll() {
1423 const PRIMARY_BUTTON: u8 = 1;
1424
1425 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1426 let first_report = testing_utilities::create_mouse_input_report_relative(
1427 Position::zero(),
1428 None, None, vec![PRIMARY_BUTTON],
1431 event_time_i64,
1432 );
1433 let second_report = testing_utilities::create_mouse_input_report_relative(
1434 Position::zero(),
1435 Some(1),
1436 None,
1437 vec![PRIMARY_BUTTON],
1438 event_time_i64,
1439 );
1440 let third_report = testing_utilities::create_mouse_input_report_relative(
1441 Position::zero(),
1442 None, None, vec![],
1445 event_time_i64,
1446 );
1447 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1448 Position::zero(),
1449 Some(1),
1450 None,
1451 vec![],
1452 event_time_i64,
1453 );
1454
1455 let descriptor = mouse_device_descriptor(DEVICE_ID);
1456
1457 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1458 let expected_events = vec![
1459 testing_utilities::create_mouse_event(
1460 MouseLocation::Relative(Default::default()),
1461 None, None, None, MousePhase::Down,
1465 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1466 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1467 event_time_u64,
1468 &descriptor,
1469 ),
1470 testing_utilities::create_mouse_event(
1471 MouseLocation::Relative(Default::default()),
1472 wheel_delta_ticks(1),
1473 None,
1474 Some(PrecisionScroll::No),
1475 MousePhase::Wheel,
1476 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1477 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1478 event_time_u64,
1479 &descriptor,
1480 ),
1481 testing_utilities::create_mouse_event(
1482 MouseLocation::Relative(Default::default()),
1483 None, None, None, MousePhase::Up,
1487 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1488 HashSet::new(),
1489 event_time_u64,
1490 &descriptor,
1491 ),
1492 testing_utilities::create_mouse_event(
1493 MouseLocation::Relative(Default::default()),
1494 wheel_delta_ticks(1),
1495 None,
1496 Some(PrecisionScroll::No),
1497 MousePhase::Wheel,
1498 HashSet::new(),
1499 HashSet::new(),
1500 event_time_u64,
1501 &descriptor,
1502 ),
1503 ];
1504
1505 assert_input_report_sequence_generates_events!(
1506 input_reports: input_reports,
1507 expected_events: expected_events,
1508 device_descriptor: descriptor,
1509 device_type: MouseBinding,
1510 );
1511 }
1512
1513 #[fasync::run_singlethreaded(test)]
1515 async fn down_scroll_bundle_up_scroll_bundle() {
1516 const PRIMARY_BUTTON: u8 = 1;
1517
1518 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1519 let first_report = testing_utilities::create_mouse_input_report_relative(
1520 Position::zero(),
1521 Some(1),
1522 None,
1523 vec![PRIMARY_BUTTON],
1524 event_time_i64,
1525 );
1526 let second_report = testing_utilities::create_mouse_input_report_relative(
1527 Position::zero(),
1528 Some(1),
1529 None,
1530 vec![],
1531 event_time_i64,
1532 );
1533 let third_report = testing_utilities::create_mouse_input_report_relative(
1534 Position::zero(),
1535 Some(1),
1536 None,
1537 vec![],
1538 event_time_i64,
1539 );
1540
1541 let descriptor = mouse_device_descriptor(DEVICE_ID);
1542
1543 let input_reports = vec![first_report, second_report, third_report];
1544 let expected_events = vec![
1545 testing_utilities::create_mouse_event(
1546 MouseLocation::Relative(Default::default()),
1547 None, None, None, MousePhase::Down,
1551 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1552 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1553 event_time_u64,
1554 &descriptor,
1555 ),
1556 testing_utilities::create_mouse_event(
1557 MouseLocation::Relative(Default::default()),
1558 wheel_delta_ticks(1),
1559 None,
1560 Some(PrecisionScroll::No),
1561 MousePhase::Wheel,
1562 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1563 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1564 event_time_u64,
1565 &descriptor,
1566 ),
1567 testing_utilities::create_mouse_event(
1568 MouseLocation::Relative(Default::default()),
1569 wheel_delta_ticks(1),
1570 None,
1571 Some(PrecisionScroll::No),
1572 MousePhase::Wheel,
1573 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1574 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1575 event_time_u64,
1576 &descriptor,
1577 ),
1578 testing_utilities::create_mouse_event(
1579 MouseLocation::Relative(Default::default()),
1580 None, None, None, MousePhase::Up,
1584 HashSet::from_iter(vec![PRIMARY_BUTTON].into_iter()),
1585 HashSet::new(),
1586 event_time_u64,
1587 &descriptor,
1588 ),
1589 testing_utilities::create_mouse_event(
1590 MouseLocation::Relative(Default::default()),
1591 wheel_delta_ticks(1),
1592 None,
1593 Some(PrecisionScroll::No),
1594 MousePhase::Wheel,
1595 HashSet::new(),
1596 HashSet::new(),
1597 event_time_u64,
1598 &descriptor,
1599 ),
1600 ];
1601
1602 assert_input_report_sequence_generates_events!(
1603 input_reports: input_reports,
1604 expected_events: expected_events,
1605 device_descriptor: descriptor,
1606 device_type: MouseBinding,
1607 );
1608 }
1609}