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_fuchsia_input_report as fidl_input_report;
12use fidl_next_fuchsia_input_report::InputReport;
13use fuchsia_inspect::ArrayProperty;
14use fuchsia_inspect::health::Reporter;
15use fuchsia_sync::Mutex;
16use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
17use metrics_registry::*;
18use sorted_vec_map_rs::SortedVecSet;
19use zx;
20
21pub type MouseButton = u8;
22
23#[derive(Copy, Clone, Debug, PartialEq)]
25pub enum PrecisionScroll {
26 Yes,
28 No,
30}
31
32#[derive(Copy, Clone, Debug, PartialEq)]
34pub enum MouseLocation {
35 Relative(RelativeLocation),
37
38 Absolute(Position),
40}
41
42#[derive(Copy, Clone, Debug, PartialEq)]
43pub enum MousePhase {
44 Down, Move, Up, Wheel, }
49
50#[derive(Copy, Clone, Debug, PartialEq)]
52pub struct RelativeLocation {
53 pub millimeters: Position,
55}
56
57impl Default for RelativeLocation {
58 fn default() -> Self {
59 RelativeLocation { millimeters: Position::zero() }
60 }
61}
62
63#[derive(Clone, Debug, PartialEq)]
65pub enum RawWheelDelta {
66 Ticks(i64),
68 Millimeters(f32),
70}
71
72#[derive(Clone, Debug, PartialEq)]
75
76pub struct WheelDelta {
77 pub raw_data: RawWheelDelta,
78 pub physical_pixel: Option<f32>,
79}
80
81#[derive(Debug)]
102pub struct MouseEvent {
103 pub location: MouseLocation,
105
106 pub wheel_delta_v: Option<WheelDelta>,
108
109 pub wheel_delta_h: Option<WheelDelta>,
111
112 pub is_precision_scroll: Option<PrecisionScroll>,
114
115 pub phase: MousePhase,
117
118 pub affected_buttons: SortedVecSet<MouseButton>,
120
121 pub pressed_buttons: SortedVecSet<MouseButton>,
123
124 pub wake_lease: Mutex<Option<zx::EventPair>>,
126}
127
128impl Clone for MouseEvent {
129 fn clone(&self) -> Self {
130 log::debug!("MouseEvent cloned without wake lease.");
131 Self {
132 location: self.location,
133 wheel_delta_v: self.wheel_delta_v.clone(),
134 wheel_delta_h: self.wheel_delta_h.clone(),
135 is_precision_scroll: self.is_precision_scroll,
136 phase: self.phase,
137 affected_buttons: self.affected_buttons.clone(),
138 pressed_buttons: self.pressed_buttons.clone(),
139 wake_lease: None.into(),
140 }
141 }
142}
143
144impl PartialEq for MouseEvent {
145 fn eq(&self, other: &Self) -> bool {
146 self.location == other.location
147 && self.wheel_delta_v == other.wheel_delta_v
148 && self.wheel_delta_h == other.wheel_delta_h
149 && self.is_precision_scroll == other.is_precision_scroll
150 && self.phase == other.phase
151 && self.affected_buttons == other.affected_buttons
152 && self.pressed_buttons == other.pressed_buttons
153 }
154}
155
156impl MouseEvent {
157 pub fn new(
165 location: MouseLocation,
166 wheel_delta_v: Option<WheelDelta>,
167 wheel_delta_h: Option<WheelDelta>,
168 phase: MousePhase,
169 affected_buttons: SortedVecSet<MouseButton>,
170 pressed_buttons: SortedVecSet<MouseButton>,
171 is_precision_scroll: Option<PrecisionScroll>,
172 wake_lease: Option<zx::EventPair>,
173 ) -> MouseEvent {
174 MouseEvent {
175 location,
176 wheel_delta_v,
177 wheel_delta_h,
178 phase,
179 affected_buttons,
180 pressed_buttons,
181 is_precision_scroll,
182 wake_lease: Mutex::new(wake_lease),
183 }
184 }
185
186 pub fn clone_with_wake_lease(&self) -> Self {
187 log::debug!("MouseEvent cloned with wake lease: {:?}", self.wake_lease);
188 Self {
189 location: self.location,
190 wheel_delta_v: self.wheel_delta_v.clone(),
191 wheel_delta_h: self.wheel_delta_h.clone(),
192 is_precision_scroll: self.is_precision_scroll,
193 phase: self.phase,
194 affected_buttons: self.affected_buttons.clone(),
195 pressed_buttons: self.pressed_buttons.clone(),
196 wake_lease: Mutex::new(self.wake_lease.lock().as_ref().map(|lease| {
197 lease
198 .duplicate_handle(zx::Rights::SAME_RIGHTS)
199 .expect("failed to duplicate event pair")
200 })),
201 }
202 }
203
204 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
205 match self.location {
206 MouseLocation::Relative(pos) => {
207 node.record_child("location_relative", move |location_node| {
208 location_node.record_double("x", f64::from(pos.millimeters.x));
209 location_node.record_double("y", f64::from(pos.millimeters.y));
210 })
211 }
212 MouseLocation::Absolute(pos) => {
213 node.record_child("location_absolute", move |location_node| {
214 location_node.record_double("x", f64::from(pos.x));
215 location_node.record_double("y", f64::from(pos.y));
216 })
217 }
218 };
219
220 if let Some(wheel_delta_v) = &self.wheel_delta_v {
221 node.record_child("wheel_delta_v", move |wheel_delta_v_node| {
222 match wheel_delta_v.raw_data {
223 RawWheelDelta::Ticks(ticks) => wheel_delta_v_node.record_int("ticks", ticks),
224 RawWheelDelta::Millimeters(mm) => {
225 wheel_delta_v_node.record_double("millimeters", f64::from(mm))
226 }
227 }
228 if let Some(physical_pixel) = wheel_delta_v.physical_pixel {
229 wheel_delta_v_node.record_double("physical_pixel", f64::from(physical_pixel));
230 }
231 });
232 }
233
234 if let Some(wheel_delta_h) = &self.wheel_delta_h {
235 node.record_child("wheel_delta_h", move |wheel_delta_h_node| {
236 match wheel_delta_h.raw_data {
237 RawWheelDelta::Ticks(ticks) => wheel_delta_h_node.record_int("ticks", ticks),
238 RawWheelDelta::Millimeters(mm) => {
239 wheel_delta_h_node.record_double("millimeters", f64::from(mm))
240 }
241 }
242 if let Some(physical_pixel) = wheel_delta_h.physical_pixel {
243 wheel_delta_h_node.record_double("physical_pixel", f64::from(physical_pixel));
244 }
245 });
246 }
247
248 if let Some(is_precision_scroll) = self.is_precision_scroll {
249 match is_precision_scroll {
250 PrecisionScroll::Yes => node.record_string("is_precision_scroll", "yes"),
251 PrecisionScroll::No => node.record_string("is_precision_scroll", "no"),
252 }
253 }
254
255 match self.phase {
256 MousePhase::Down => node.record_string("phase", "down"),
257 MousePhase::Move => node.record_string("phase", "move"),
258 MousePhase::Up => node.record_string("phase", "up"),
259 MousePhase::Wheel => node.record_string("phase", "wheel"),
260 }
261
262 let affected_buttons_node =
263 node.create_uint_array("affected_buttons", self.affected_buttons.len());
264 self.affected_buttons.iter().enumerate().for_each(|(i, button)| {
265 affected_buttons_node.set(i, *button);
266 });
267 node.record(affected_buttons_node);
268
269 let pressed_buttons_node =
270 node.create_uint_array("pressed_buttons", self.pressed_buttons.len());
271 self.pressed_buttons.iter().enumerate().for_each(|(i, button)| {
272 pressed_buttons_node.set(i, *button);
273 });
274 node.record(pressed_buttons_node);
275 }
276}
277
278pub struct MouseBinding {
284 event_sender: UnboundedSender<Vec<InputEvent>>,
286
287 device_descriptor: MouseDeviceDescriptor,
289}
290
291#[derive(Clone, Debug, Eq, PartialEq)]
292pub struct MouseDeviceDescriptor {
293 pub device_id: u32,
295
296 pub absolute_x_range: Option<fidl_input_report::Range>,
298
299 pub absolute_y_range: Option<fidl_input_report::Range>,
301
302 pub wheel_v_range: Option<fidl_input_report::Axis>,
304
305 pub wheel_h_range: Option<fidl_input_report::Axis>,
307
308 pub buttons: Option<Vec<MouseButton>>,
310
311 pub counts_per_mm: u32,
314}
315
316#[async_trait]
317impl input_device::InputDeviceBinding for MouseBinding {
318 fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>> {
319 self.event_sender.clone()
320 }
321
322 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
323 input_device::InputDeviceDescriptor::Mouse(self.device_descriptor.clone())
324 }
325}
326
327impl MouseBinding {
328 pub async fn new(
343 device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
344 device_id: u32,
345 input_event_sender: UnboundedSender<Vec<InputEvent>>,
346 device_node: fuchsia_inspect::Node,
347 _feature_flags: input_device::InputPipelineFeatureFlags,
348 metrics_logger: metrics::MetricsLogger,
349 ) -> Result<Self, Error> {
350 let (device_binding, mut inspect_status) =
351 Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
352 inspect_status.health_node.set_ok();
353 input_device::initialize_report_stream(
354 device_proxy,
355 device_binding.get_device_descriptor(),
356 device_binding.input_event_sender(),
357 inspect_status,
358 metrics_logger,
359 _feature_flags,
360 Self::process_reports,
361 );
362
363 Ok(device_binding)
364 }
365
366 async fn bind_device(
378 device: &fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
379 device_id: u32,
380 input_event_sender: UnboundedSender<Vec<InputEvent>>,
381 device_node: fuchsia_inspect::Node,
382 ) -> Result<(Self, InputDeviceStatus), Error> {
383 let mut input_device_status = InputDeviceStatus::new(device_node);
384 let device_descriptor: fidl_next_fuchsia_input_report::DeviceDescriptor = match device
385 .get_descriptor()
386 .await
387 {
388 Ok(res) => res.descriptor,
389 Err(_) => {
390 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
391 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
392 }
393 };
394
395 let mouse_descriptor = device_descriptor.mouse.ok_or_else(|| {
396 input_device_status
397 .health_node
398 .set_unhealthy("DeviceDescriptor does not have a MouseDescriptor.");
399 format_err!("DeviceDescriptor does not have a MouseDescriptor")
400 })?;
401
402 let mouse_input_descriptor = mouse_descriptor.input.ok_or_else(|| {
403 input_device_status
404 .health_node
405 .set_unhealthy("MouseDescriptor does not have a MouseInputDescriptor.");
406 format_err!("MouseDescriptor does not have a MouseInputDescriptor")
407 })?;
408
409 let model = mouse_model_database::db::get_mouse_model(device_descriptor.device_information);
410
411 let device_descriptor: MouseDeviceDescriptor = MouseDeviceDescriptor {
412 device_id,
413 absolute_x_range: mouse_input_descriptor
414 .position_x
415 .as_ref()
416 .map(|axis| utils::range_to_old(&axis.range)),
417 absolute_y_range: mouse_input_descriptor
418 .position_y
419 .as_ref()
420 .map(|axis| utils::range_to_old(&axis.range)),
421 wheel_v_range: utils::axis_to_old(mouse_input_descriptor.scroll_v.as_ref()),
422 wheel_h_range: utils::axis_to_old(mouse_input_descriptor.scroll_h.as_ref()),
423 buttons: mouse_input_descriptor.buttons,
424 counts_per_mm: model.counts_per_mm,
425 };
426
427 Ok((Self { event_sender: input_event_sender, device_descriptor }, input_device_status))
428 }
429
430 fn process_reports(
452 reports: Vec<InputReport>,
453 mut previous_report: Option<InputReport>,
454 device_descriptor: &input_device::InputDeviceDescriptor,
455 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
456 inspect_status: &InputDeviceStatus,
457 metrics_logger: &metrics::MetricsLogger,
458 _feature_flags: &input_device::InputPipelineFeatureFlags,
459 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
460 fuchsia_trace::duration!("input", "mouse-binding-process-reports", "num_reports" => reports.len());
461 for report in reports {
462 previous_report = Self::process_report(
463 report,
464 previous_report,
465 device_descriptor,
466 input_event_sender,
467 inspect_status,
468 metrics_logger,
469 );
470 }
471 (previous_report, None)
472 }
473
474 fn process_report(
475 mut report: InputReport,
476 previous_report: Option<InputReport>,
477 device_descriptor: &input_device::InputDeviceDescriptor,
478 input_event_sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
479 inspect_status: &InputDeviceStatus,
480 metrics_logger: &metrics::MetricsLogger,
481 ) -> Option<InputReport> {
482 if let Some(trace_id) = report.trace_id {
483 fuchsia_trace::flow_end!("input", "input_report", trace_id.into());
484 }
485
486 let wake_lease = report.wake_lease.take();
490
491 inspect_status.count_received_report(&report);
492 let mouse_report: &fidl_next_fuchsia_input_report::MouseInputReport = match &report.mouse {
494 Some(mouse) => mouse,
495 None => {
496 inspect_status.count_filtered_report();
497 return previous_report;
498 }
499 };
500
501 let previous_buttons: SortedVecSet<MouseButton> =
502 buttons_from_optional_report(&previous_report.as_ref());
503 let current_buttons: SortedVecSet<MouseButton> = buttons_from_report(&report);
504
505 send_mouse_event(
511 MouseLocation::Relative(Default::default()),
512 None, None, MousePhase::Down,
515 current_buttons.difference(&previous_buttons).cloned().collect(),
516 current_buttons.clone(),
517 device_descriptor,
518 input_event_sender,
519 inspect_status,
520 metrics_logger,
521 wake_lease.as_ref().map(|lease| {
522 lease
523 .duplicate_handle(zx::Rights::SAME_RIGHTS)
524 .expect("failed to duplicate event pair")
525 }),
526 );
527
528 let counts_per_mm = match device_descriptor {
529 input_device::InputDeviceDescriptor::Mouse(ds) => ds.counts_per_mm,
530 _ => {
531 metrics_logger.log_error(
532 InputPipelineErrorMetricDimensionEvent::MouseDescriptionNotMouse,
533 "mouse_binding::process_reports got device_descriptor not mouse".to_string(),
534 );
535 mouse_model_database::db::DEFAULT_COUNTS_PER_MM
536 }
537 };
538
539 let location = if let (Some(position_x), Some(position_y)) =
541 (mouse_report.position_x, mouse_report.position_y)
542 {
543 MouseLocation::Absolute(Position { x: position_x as f32, y: position_y as f32 })
544 } else {
545 let movement_x = mouse_report.movement_x.unwrap_or_default() as f32;
546 let movement_y = mouse_report.movement_y.unwrap_or_default() as f32;
547 MouseLocation::Relative(RelativeLocation {
548 millimeters: Position {
549 x: movement_x / counts_per_mm as f32,
550 y: movement_y / counts_per_mm as f32,
551 },
552 })
553 };
554
555 send_mouse_event(
559 location,
560 None, None, MousePhase::Move,
563 current_buttons.union(&previous_buttons).cloned().collect(),
564 current_buttons.union(&previous_buttons).cloned().collect(),
565 device_descriptor,
566 input_event_sender,
567 inspect_status,
568 metrics_logger,
569 wake_lease.as_ref().map(|lease| {
570 lease
571 .duplicate_handle(zx::Rights::SAME_RIGHTS)
572 .expect("failed to duplicate event pair")
573 }),
574 );
575
576 let wheel_delta_v = match mouse_report.scroll_v {
577 None => None,
578 Some(ticks) => {
579 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
580 }
581 };
582
583 let wheel_delta_h = match mouse_report.scroll_h {
584 None => None,
585 Some(ticks) => {
586 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(ticks), physical_pixel: None })
587 }
588 };
589
590 send_mouse_event(
592 MouseLocation::Relative(Default::default()),
593 wheel_delta_v,
594 wheel_delta_h,
595 MousePhase::Wheel,
596 current_buttons.union(&previous_buttons).cloned().collect(),
597 current_buttons.union(&previous_buttons).cloned().collect(),
598 device_descriptor,
599 input_event_sender,
600 inspect_status,
601 metrics_logger,
602 wake_lease.as_ref().map(|lease| {
603 lease
604 .duplicate_handle(zx::Rights::SAME_RIGHTS)
605 .expect("failed to duplicate event pair")
606 }),
607 );
608
609 send_mouse_event(
615 MouseLocation::Relative(Default::default()),
616 None, None, MousePhase::Up,
619 previous_buttons.difference(¤t_buttons).cloned().collect(),
620 current_buttons.clone(),
621 device_descriptor,
622 input_event_sender,
623 inspect_status,
624 metrics_logger,
625 wake_lease,
626 );
627
628 Some(report)
629 }
630}
631
632fn send_mouse_event(
647 location: MouseLocation,
648 wheel_delta_v: Option<WheelDelta>,
649 wheel_delta_h: Option<WheelDelta>,
650 phase: MousePhase,
651 affected_buttons: SortedVecSet<MouseButton>,
652 pressed_buttons: SortedVecSet<MouseButton>,
653 device_descriptor: &input_device::InputDeviceDescriptor,
654 sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
655 inspect_status: &InputDeviceStatus,
656 metrics_logger: &metrics::MetricsLogger,
657 wake_lease: Option<zx::EventPair>,
658) {
659 if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
661 return;
662 }
663
664 if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
667 return;
668 }
669
670 if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
672 return;
673 }
674
675 let trace_id = fuchsia_trace::Id::random();
676 fuchsia_trace::duration!("input", "mouse-binding-send-event");
677 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
678
679 let event = input_device::InputEvent {
680 device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
681 location,
682 wheel_delta_v,
683 wheel_delta_h,
684 phase,
685 affected_buttons,
686 pressed_buttons,
687 match phase {
688 MousePhase::Wheel => Some(PrecisionScroll::No),
689 _ => None,
690 },
691 wake_lease,
692 )),
693 device_descriptor: device_descriptor.clone(),
694 event_time: zx::MonotonicInstant::get(),
695 handled: Handled::No,
696 trace_id: Some(trace_id),
697 };
698 let events = vec![event.clone_with_wake_lease()];
699
700 match sender.unbounded_send(events.clone()) {
701 Err(e) => {
702 metrics_logger.log_error(
703 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
704 std::format!("Failed to send MouseEvent with error: {:?}", e),
705 );
706 }
707 _ => inspect_status.count_generated_events(&events),
708 }
709}
710
711fn buttons_from_report(
716 input_report: &fidl_next_fuchsia_input_report::InputReport,
717) -> SortedVecSet<MouseButton> {
718 buttons_from_optional_report(&Some(input_report))
719}
720
721fn buttons_from_optional_report(
726 input_report: &Option<&fidl_next_fuchsia_input_report::InputReport>,
727) -> SortedVecSet<MouseButton> {
728 input_report
729 .as_ref()
730 .and_then(|unwrapped_report| unwrapped_report.mouse.as_ref())
731 .and_then(|mouse_report| match &mouse_report.pressed_buttons {
732 Some(buttons) => Some(SortedVecSet::from(buttons.clone())),
733 None => None,
734 })
735 .unwrap_or_default()
736}
737
738#[cfg(test)]
739mod tests {
740 use super::*;
741 use crate::testing_utilities;
742 use fuchsia_async as fasync;
743 use futures::StreamExt;
744 use sorted_vec_map_rs::SortedVecSet;
745
746 const DEVICE_ID: u32 = 1;
747 const COUNTS_PER_MM: u32 = 12;
748
749 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
750 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
751 device_id,
752 absolute_x_range: None,
753 absolute_y_range: None,
754 wheel_v_range: Some(fidl_fuchsia_input_report::Axis {
755 range: fidl_input_report::Range { min: -1, max: 1 },
756 unit: fidl_input_report::Unit {
757 type_: fidl_input_report::UnitType::Other,
758 exponent: 1,
759 },
760 }),
761 wheel_h_range: Some(fidl_fuchsia_input_report::Axis {
762 range: fidl_input_report::Range { min: -1, max: 1 },
763 unit: fidl_input_report::Unit {
764 type_: fidl_input_report::UnitType::Other,
765 exponent: 1,
766 },
767 }),
768 buttons: None,
769 counts_per_mm: COUNTS_PER_MM,
770 })
771 }
772
773 fn wheel_delta_ticks(delta: i64) -> Option<WheelDelta> {
774 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(delta), physical_pixel: None })
775 }
776
777 #[fasync::run_singlethreaded(test)]
779 async fn movement_without_button() {
780 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
781 let first_report = testing_utilities::create_mouse_input_report_relative(
782 Position { x: 10.0, y: 16.0 },
783 None, None, vec![],
786 event_time_i64,
787 );
788 let descriptor = mouse_device_descriptor(DEVICE_ID);
789
790 let input_reports = vec![first_report];
791 let expected_events = vec![testing_utilities::create_mouse_event(
792 MouseLocation::Relative(RelativeLocation {
793 millimeters: Position {
794 x: 10.0 / COUNTS_PER_MM as f32,
795 y: 16.0 / COUNTS_PER_MM as f32,
796 },
797 }),
798 None, None, None, MousePhase::Move,
802 SortedVecSet::new(),
803 SortedVecSet::new(),
804 event_time_u64,
805 &descriptor,
806 )];
807
808 assert_input_report_sequence_generates_events!(
809 input_reports: input_reports,
810 expected_events: expected_events,
811 device_descriptor: descriptor,
812 device_type: MouseBinding,
813 );
814 }
815
816 #[fasync::run_singlethreaded(test)]
818 async fn down_without_movement() {
819 let mouse_button: MouseButton = 3;
820 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
821 let first_report = testing_utilities::create_mouse_input_report_relative(
822 Position::zero(),
823 None, None, vec![mouse_button],
826 event_time_i64,
827 );
828 let descriptor = mouse_device_descriptor(DEVICE_ID);
829
830 let input_reports = vec![first_report];
831 let expected_events = vec![testing_utilities::create_mouse_event(
832 MouseLocation::Relative(Default::default()),
833 None, None, None, MousePhase::Down,
837 SortedVecSet::from(vec![mouse_button]),
838 SortedVecSet::from(vec![mouse_button]),
839 event_time_u64,
840 &descriptor,
841 )];
842
843 assert_input_report_sequence_generates_events!(
844 input_reports: input_reports,
845 expected_events: expected_events,
846 device_descriptor: descriptor,
847 device_type: MouseBinding,
848 );
849 }
850
851 #[fasync::run_singlethreaded(test)]
854 async fn down_with_movement() {
855 let mouse_button: MouseButton = 3;
856 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
857 let first_report = testing_utilities::create_mouse_input_report_relative(
858 Position { x: 10.0, y: 16.0 },
859 None, None, vec![mouse_button],
862 event_time_i64,
863 );
864 let descriptor = mouse_device_descriptor(DEVICE_ID);
865
866 let input_reports = vec![first_report];
867 let expected_events = vec![
868 testing_utilities::create_mouse_event(
869 MouseLocation::Relative(Default::default()),
870 None, None, None, MousePhase::Down,
874 SortedVecSet::from(vec![mouse_button]),
875 SortedVecSet::from(vec![mouse_button]),
876 event_time_u64,
877 &descriptor,
878 ),
879 testing_utilities::create_mouse_event(
880 MouseLocation::Relative(RelativeLocation {
881 millimeters: Position {
882 x: 10.0 / COUNTS_PER_MM as f32,
883 y: 16.0 / COUNTS_PER_MM as f32,
884 },
885 }),
886 None, None, None, MousePhase::Move,
890 SortedVecSet::from(vec![mouse_button]),
891 SortedVecSet::from(vec![mouse_button]),
892 event_time_u64,
893 &descriptor,
894 ),
895 ];
896
897 assert_input_report_sequence_generates_events!(
898 input_reports: input_reports,
899 expected_events: expected_events,
900 device_descriptor: descriptor,
901 device_type: MouseBinding,
902 );
903 }
904
905 #[fasync::run_singlethreaded(test)]
907 async fn down_up() {
908 let button = 1;
909 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
910 let first_report = testing_utilities::create_mouse_input_report_relative(
911 Position::zero(),
912 None, None, vec![button],
915 event_time_i64,
916 );
917 let second_report = testing_utilities::create_mouse_input_report_relative(
918 Position::zero(),
919 None, None, vec![],
922 event_time_i64,
923 );
924 let descriptor = mouse_device_descriptor(DEVICE_ID);
925
926 let input_reports = vec![first_report, second_report];
927 let expected_events = vec![
928 testing_utilities::create_mouse_event(
929 MouseLocation::Relative(Default::default()),
930 None, None, None, MousePhase::Down,
934 SortedVecSet::from(vec![button]),
935 SortedVecSet::from(vec![button]),
936 event_time_u64,
937 &descriptor,
938 ),
939 testing_utilities::create_mouse_event(
940 MouseLocation::Relative(Default::default()),
941 None, None, None, MousePhase::Up,
945 SortedVecSet::from(vec![button]),
946 SortedVecSet::new(),
947 event_time_u64,
948 &descriptor,
949 ),
950 ];
951
952 assert_input_report_sequence_generates_events!(
953 input_reports: input_reports,
954 expected_events: expected_events,
955 device_descriptor: descriptor,
956 device_type: MouseBinding,
957 );
958 }
959
960 #[fasync::run_singlethreaded(test)]
962 async fn down_up_with_movement() {
963 let button = 1;
964
965 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
966 let first_report = testing_utilities::create_mouse_input_report_relative(
967 Position::zero(),
968 None, None, vec![button],
971 event_time_i64,
972 );
973 let second_report = testing_utilities::create_mouse_input_report_relative(
974 Position { x: 10.0, y: 16.0 },
975 None, None, vec![],
978 event_time_i64,
979 );
980 let descriptor = mouse_device_descriptor(DEVICE_ID);
981
982 let input_reports = vec![first_report, second_report];
983 let expected_events = vec![
984 testing_utilities::create_mouse_event(
985 MouseLocation::Relative(Default::default()),
986 None, None, None, MousePhase::Down,
990 SortedVecSet::from(vec![button]),
991 SortedVecSet::from(vec![button]),
992 event_time_u64,
993 &descriptor,
994 ),
995 testing_utilities::create_mouse_event(
996 MouseLocation::Relative(RelativeLocation {
997 millimeters: Position {
998 x: 10.0 / COUNTS_PER_MM as f32,
999 y: 16.0 / COUNTS_PER_MM as f32,
1000 },
1001 }),
1002 None, None, None, MousePhase::Move,
1006 SortedVecSet::from(vec![button]),
1007 SortedVecSet::from(vec![button]),
1008 event_time_u64,
1009 &descriptor,
1010 ),
1011 testing_utilities::create_mouse_event(
1012 MouseLocation::Relative(Default::default()),
1013 None, None, None, MousePhase::Up,
1017 SortedVecSet::from(vec![button]),
1018 SortedVecSet::new(),
1019 event_time_u64,
1020 &descriptor,
1021 ),
1022 ];
1023
1024 assert_input_report_sequence_generates_events!(
1025 input_reports: input_reports,
1026 expected_events: expected_events,
1027 device_descriptor: descriptor,
1028 device_type: MouseBinding,
1029 );
1030 }
1031
1032 #[fasync::run_singlethreaded(test)]
1036 async fn down_move_up() {
1037 let button = 1;
1038
1039 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1040 let first_report = testing_utilities::create_mouse_input_report_relative(
1041 Position::zero(),
1042 None, None, vec![button],
1045 event_time_i64,
1046 );
1047 let second_report = testing_utilities::create_mouse_input_report_relative(
1048 Position { x: 10.0, y: 16.0 },
1049 None, None, vec![button],
1052 event_time_i64,
1053 );
1054 let third_report = testing_utilities::create_mouse_input_report_relative(
1055 Position::zero(),
1056 None, None, vec![],
1059 event_time_i64,
1060 );
1061 let descriptor = mouse_device_descriptor(DEVICE_ID);
1062
1063 let input_reports = vec![first_report, second_report, third_report];
1064 let expected_events = vec![
1065 testing_utilities::create_mouse_event(
1066 MouseLocation::Relative(Default::default()),
1067 None, None, None, MousePhase::Down,
1071 SortedVecSet::from(vec![button]),
1072 SortedVecSet::from(vec![button]),
1073 event_time_u64,
1074 &descriptor,
1075 ),
1076 testing_utilities::create_mouse_event(
1077 MouseLocation::Relative(RelativeLocation {
1078 millimeters: Position {
1079 x: 10.0 / COUNTS_PER_MM as f32,
1080 y: 16.0 / COUNTS_PER_MM as f32,
1081 },
1082 }),
1083 None, None, None, MousePhase::Move,
1087 SortedVecSet::from(vec![button]),
1088 SortedVecSet::from(vec![button]),
1089 event_time_u64,
1090 &descriptor,
1091 ),
1092 testing_utilities::create_mouse_event(
1093 MouseLocation::Relative(Default::default()),
1094 None, None, None, MousePhase::Up,
1098 SortedVecSet::from(vec![button]),
1099 SortedVecSet::new(),
1100 event_time_u64,
1101 &descriptor,
1102 ),
1103 ];
1104
1105 assert_input_report_sequence_generates_events!(
1106 input_reports: input_reports,
1107 expected_events: expected_events,
1108 device_descriptor: descriptor,
1109 device_type: MouseBinding,
1110 );
1111 }
1112
1113 #[fasync::run_until_stalled(test)]
1115 async fn absolute_movement_to_origin() {
1116 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1117 let descriptor = mouse_device_descriptor(DEVICE_ID);
1118
1119 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
1120 Position::zero(),
1121 None, None, vec![],
1124 event_time_i64,
1125 )];
1126 let expected_events = vec![testing_utilities::create_mouse_event(
1127 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1128 None, None, None, MousePhase::Move,
1132 SortedVecSet::new(),
1133 SortedVecSet::new(),
1134 event_time_u64,
1135 &descriptor,
1136 )];
1137
1138 assert_input_report_sequence_generates_events!(
1139 input_reports: input_reports,
1140 expected_events: expected_events,
1141 device_descriptor: descriptor,
1142 device_type: MouseBinding,
1143 );
1144 }
1145
1146 #[fasync::run_until_stalled(test)]
1149 async fn report_with_both_movement_and_position() {
1150 let relative_movement = Position { x: 5.0, y: 5.0 };
1151 let absolute_position = Position { x: 10.0, y: 10.0 };
1152 let expected_location = MouseLocation::Absolute(absolute_position);
1153
1154 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1155 let descriptor = mouse_device_descriptor(DEVICE_ID);
1156
1157 let input_reports = vec![fidl_next_fuchsia_input_report::InputReport {
1158 event_time: Some(event_time_i64),
1159 keyboard: None,
1160 mouse: Some(fidl_next_fuchsia_input_report::MouseInputReport {
1161 movement_x: Some(relative_movement.x as i64),
1162 movement_y: Some(relative_movement.y as i64),
1163 position_x: Some(absolute_position.x as i64),
1164 position_y: Some(absolute_position.y as i64),
1165 scroll_h: None,
1166 scroll_v: None,
1167 pressed_buttons: None,
1168 ..Default::default()
1169 }),
1170 touch: None,
1171 sensor: None,
1172 consumer_control: None,
1173 trace_id: None,
1174 ..Default::default()
1175 }];
1176 let expected_events = vec![testing_utilities::create_mouse_event(
1177 expected_location,
1178 None, None, None, MousePhase::Move,
1182 SortedVecSet::new(),
1183 SortedVecSet::new(),
1184 event_time_u64,
1185 &descriptor,
1186 )];
1187
1188 assert_input_report_sequence_generates_events!(
1189 input_reports: input_reports,
1190 expected_events: expected_events,
1191 device_descriptor: descriptor,
1192 device_type: MouseBinding,
1193 );
1194 }
1195
1196 #[fasync::run_singlethreaded(test)]
1199 async fn down_down() {
1200 const PRIMARY_BUTTON: u8 = 1;
1201 const SECONDARY_BUTTON: u8 = 2;
1202
1203 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1204 let first_report = testing_utilities::create_mouse_input_report_relative(
1205 Position::zero(),
1206 None, None, vec![PRIMARY_BUTTON],
1209 event_time_i64,
1210 );
1211 let second_report = testing_utilities::create_mouse_input_report_relative(
1212 Position::zero(),
1213 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1216 event_time_i64,
1217 );
1218 let descriptor = mouse_device_descriptor(DEVICE_ID);
1219
1220 let input_reports = vec![first_report, second_report];
1221 let expected_events = vec![
1222 testing_utilities::create_mouse_event(
1223 MouseLocation::Relative(Default::default()),
1224 None, None, None, MousePhase::Down,
1228 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1229 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1230 event_time_u64,
1231 &descriptor,
1232 ),
1233 testing_utilities::create_mouse_event(
1234 MouseLocation::Relative(Default::default()),
1235 None, None, None, MousePhase::Down,
1239 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1240 SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1241 event_time_u64,
1242 &descriptor,
1243 ),
1244 ];
1245
1246 assert_input_report_sequence_generates_events!(
1247 input_reports: input_reports,
1248 expected_events: expected_events,
1249 device_descriptor: descriptor,
1250 device_type: MouseBinding,
1251 );
1252 }
1253
1254 #[fasync::run_singlethreaded(test)]
1264 async fn down_down_up_up() {
1265 const PRIMARY_BUTTON: u8 = 1;
1266 const SECONDARY_BUTTON: u8 = 2;
1267
1268 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1269 let first_report = testing_utilities::create_mouse_input_report_relative(
1270 Position::zero(),
1271 None, None, vec![PRIMARY_BUTTON],
1274 event_time_i64,
1275 );
1276 let second_report = testing_utilities::create_mouse_input_report_relative(
1277 Position::zero(),
1278 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1281 event_time_i64,
1282 );
1283 let third_report = testing_utilities::create_mouse_input_report_relative(
1284 Position::zero(),
1285 None, None, vec![SECONDARY_BUTTON],
1288 event_time_i64,
1289 );
1290 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1291 Position::zero(),
1292 None, None, vec![],
1295 event_time_i64,
1296 );
1297 let descriptor = mouse_device_descriptor(DEVICE_ID);
1298
1299 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1300 let expected_events = vec![
1301 testing_utilities::create_mouse_event(
1302 MouseLocation::Relative(Default::default()),
1303 None, None, None, MousePhase::Down,
1307 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1308 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1309 event_time_u64,
1310 &descriptor,
1311 ),
1312 testing_utilities::create_mouse_event(
1313 MouseLocation::Relative(Default::default()),
1314 None, None, None, MousePhase::Down,
1318 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1319 SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1320 event_time_u64,
1321 &descriptor,
1322 ),
1323 testing_utilities::create_mouse_event(
1324 MouseLocation::Relative(Default::default()),
1325 None, None, None, MousePhase::Up,
1329 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1330 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1331 event_time_u64,
1332 &descriptor,
1333 ),
1334 testing_utilities::create_mouse_event(
1335 MouseLocation::Relative(Default::default()),
1336 None, None, None, MousePhase::Up,
1340 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1341 SortedVecSet::new(),
1342 event_time_u64,
1343 &descriptor,
1344 ),
1345 ];
1346
1347 assert_input_report_sequence_generates_events!(
1348 input_reports: input_reports,
1349 expected_events: expected_events,
1350 device_descriptor: descriptor,
1351 device_type: MouseBinding,
1352 );
1353 }
1354
1355 #[fasync::run_singlethreaded(test)]
1357 async fn scroll() {
1358 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1359 let first_report = testing_utilities::create_mouse_input_report_relative(
1360 Position::zero(),
1361 Some(1),
1362 None,
1363 vec![],
1364 event_time_i64,
1365 );
1366 let second_report = testing_utilities::create_mouse_input_report_relative(
1367 Position::zero(),
1368 None,
1369 Some(1),
1370 vec![],
1371 event_time_i64,
1372 );
1373
1374 let descriptor = mouse_device_descriptor(DEVICE_ID);
1375
1376 let input_reports = vec![first_report, second_report];
1377 let expected_events = vec![
1378 testing_utilities::create_mouse_event(
1379 MouseLocation::Relative(Default::default()),
1380 wheel_delta_ticks(1),
1381 None,
1382 Some(PrecisionScroll::No),
1383 MousePhase::Wheel,
1384 SortedVecSet::new(),
1385 SortedVecSet::new(),
1386 event_time_u64,
1387 &descriptor,
1388 ),
1389 testing_utilities::create_mouse_event(
1390 MouseLocation::Relative(Default::default()),
1391 None,
1392 wheel_delta_ticks(1),
1393 Some(PrecisionScroll::No),
1394 MousePhase::Wheel,
1395 SortedVecSet::new(),
1396 SortedVecSet::new(),
1397 event_time_u64,
1398 &descriptor,
1399 ),
1400 ];
1401
1402 assert_input_report_sequence_generates_events!(
1403 input_reports: input_reports,
1404 expected_events: expected_events,
1405 device_descriptor: descriptor,
1406 device_type: MouseBinding,
1407 );
1408 }
1409
1410 #[fasync::run_singlethreaded(test)]
1412 async fn down_scroll_up_scroll() {
1413 const PRIMARY_BUTTON: u8 = 1;
1414
1415 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1416 let first_report = testing_utilities::create_mouse_input_report_relative(
1417 Position::zero(),
1418 None, None, vec![PRIMARY_BUTTON],
1421 event_time_i64,
1422 );
1423 let second_report = testing_utilities::create_mouse_input_report_relative(
1424 Position::zero(),
1425 Some(1),
1426 None,
1427 vec![PRIMARY_BUTTON],
1428 event_time_i64,
1429 );
1430 let third_report = testing_utilities::create_mouse_input_report_relative(
1431 Position::zero(),
1432 None, None, vec![],
1435 event_time_i64,
1436 );
1437 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1438 Position::zero(),
1439 Some(1),
1440 None,
1441 vec![],
1442 event_time_i64,
1443 );
1444
1445 let descriptor = mouse_device_descriptor(DEVICE_ID);
1446
1447 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1448 let expected_events = vec![
1449 testing_utilities::create_mouse_event(
1450 MouseLocation::Relative(Default::default()),
1451 None, None, None, MousePhase::Down,
1455 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1456 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1457 event_time_u64,
1458 &descriptor,
1459 ),
1460 testing_utilities::create_mouse_event(
1461 MouseLocation::Relative(Default::default()),
1462 wheel_delta_ticks(1),
1463 None,
1464 Some(PrecisionScroll::No),
1465 MousePhase::Wheel,
1466 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1467 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1468 event_time_u64,
1469 &descriptor,
1470 ),
1471 testing_utilities::create_mouse_event(
1472 MouseLocation::Relative(Default::default()),
1473 None, None, None, MousePhase::Up,
1477 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1478 SortedVecSet::new(),
1479 event_time_u64,
1480 &descriptor,
1481 ),
1482 testing_utilities::create_mouse_event(
1483 MouseLocation::Relative(Default::default()),
1484 wheel_delta_ticks(1),
1485 None,
1486 Some(PrecisionScroll::No),
1487 MousePhase::Wheel,
1488 SortedVecSet::new(),
1489 SortedVecSet::new(),
1490 event_time_u64,
1491 &descriptor,
1492 ),
1493 ];
1494
1495 assert_input_report_sequence_generates_events!(
1496 input_reports: input_reports,
1497 expected_events: expected_events,
1498 device_descriptor: descriptor,
1499 device_type: MouseBinding,
1500 );
1501 }
1502
1503 #[fasync::run_singlethreaded(test)]
1505 async fn down_scroll_bundle_up_scroll_bundle() {
1506 const PRIMARY_BUTTON: u8 = 1;
1507
1508 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1509 let first_report = testing_utilities::create_mouse_input_report_relative(
1510 Position::zero(),
1511 Some(1),
1512 None,
1513 vec![PRIMARY_BUTTON],
1514 event_time_i64,
1515 );
1516 let second_report = testing_utilities::create_mouse_input_report_relative(
1517 Position::zero(),
1518 Some(1),
1519 None,
1520 vec![],
1521 event_time_i64,
1522 );
1523 let third_report = testing_utilities::create_mouse_input_report_relative(
1524 Position::zero(),
1525 Some(1),
1526 None,
1527 vec![],
1528 event_time_i64,
1529 );
1530
1531 let descriptor = mouse_device_descriptor(DEVICE_ID);
1532
1533 let input_reports = vec![first_report, second_report, third_report];
1534 let expected_events = vec![
1535 testing_utilities::create_mouse_event(
1536 MouseLocation::Relative(Default::default()),
1537 None, None, None, MousePhase::Down,
1541 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1542 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1543 event_time_u64,
1544 &descriptor,
1545 ),
1546 testing_utilities::create_mouse_event(
1547 MouseLocation::Relative(Default::default()),
1548 wheel_delta_ticks(1),
1549 None,
1550 Some(PrecisionScroll::No),
1551 MousePhase::Wheel,
1552 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1553 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1554 event_time_u64,
1555 &descriptor,
1556 ),
1557 testing_utilities::create_mouse_event(
1558 MouseLocation::Relative(Default::default()),
1559 wheel_delta_ticks(1),
1560 None,
1561 Some(PrecisionScroll::No),
1562 MousePhase::Wheel,
1563 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1564 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1565 event_time_u64,
1566 &descriptor,
1567 ),
1568 testing_utilities::create_mouse_event(
1569 MouseLocation::Relative(Default::default()),
1570 None, None, None, MousePhase::Up,
1574 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1575 SortedVecSet::new(),
1576 event_time_u64,
1577 &descriptor,
1578 ),
1579 testing_utilities::create_mouse_event(
1580 MouseLocation::Relative(Default::default()),
1581 wheel_delta_ticks(1),
1582 None,
1583 Some(PrecisionScroll::No),
1584 MousePhase::Wheel,
1585 SortedVecSet::new(),
1586 SortedVecSet::new(),
1587 event_time_u64,
1588 &descriptor,
1589 ),
1590 ];
1591
1592 assert_input_report_sequence_generates_events!(
1593 input_reports: input_reports,
1594 expected_events: expected_events,
1595 device_descriptor: descriptor,
1596 device_type: MouseBinding,
1597 );
1598 }
1599}