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::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];
699 inspect_status.count_generated_events(&events);
700
701 if let Err(e) = sender.unbounded_send(events) {
702 metrics_logger.log_error(
703 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
704 std::format!("Failed to send MouseEvent with error: {:?}", e),
705 );
706 }
707}
708
709fn buttons_from_report(
714 input_report: &fidl_next_fuchsia_input_report::InputReport,
715) -> SortedVecSet<MouseButton> {
716 buttons_from_optional_report(&Some(input_report))
717}
718
719fn buttons_from_optional_report(
724 input_report: &Option<&fidl_next_fuchsia_input_report::InputReport>,
725) -> SortedVecSet<MouseButton> {
726 input_report
727 .as_ref()
728 .and_then(|unwrapped_report| unwrapped_report.mouse.as_ref())
729 .and_then(|mouse_report| match &mouse_report.pressed_buttons {
730 Some(buttons) => Some(SortedVecSet::from(buttons.clone())),
731 None => None,
732 })
733 .unwrap_or_default()
734}
735
736#[cfg(test)]
737mod tests {
738 use super::*;
739 use crate::testing_utilities;
740 use fuchsia_async as fasync;
741 use futures::StreamExt;
742 use sorted_vec_map::SortedVecSet;
743
744 const DEVICE_ID: u32 = 1;
745 const COUNTS_PER_MM: u32 = 12;
746
747 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
748 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
749 device_id,
750 absolute_x_range: None,
751 absolute_y_range: None,
752 wheel_v_range: Some(fidl_fuchsia_input_report::Axis {
753 range: fidl_input_report::Range { min: -1, max: 1 },
754 unit: fidl_input_report::Unit {
755 type_: fidl_input_report::UnitType::Other,
756 exponent: 1,
757 },
758 }),
759 wheel_h_range: Some(fidl_fuchsia_input_report::Axis {
760 range: fidl_input_report::Range { min: -1, max: 1 },
761 unit: fidl_input_report::Unit {
762 type_: fidl_input_report::UnitType::Other,
763 exponent: 1,
764 },
765 }),
766 buttons: None,
767 counts_per_mm: COUNTS_PER_MM,
768 })
769 }
770
771 fn wheel_delta_ticks(delta: i64) -> Option<WheelDelta> {
772 Some(WheelDelta { raw_data: RawWheelDelta::Ticks(delta), physical_pixel: None })
773 }
774
775 #[fasync::run_singlethreaded(test)]
777 async fn movement_without_button() {
778 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
779 let first_report = testing_utilities::create_mouse_input_report_relative(
780 Position { x: 10.0, y: 16.0 },
781 None, None, vec![],
784 event_time_i64,
785 );
786 let descriptor = mouse_device_descriptor(DEVICE_ID);
787
788 let input_reports = vec![first_report];
789 let expected_events = vec![testing_utilities::create_mouse_event(
790 MouseLocation::Relative(RelativeLocation {
791 millimeters: Position {
792 x: 10.0 / COUNTS_PER_MM as f32,
793 y: 16.0 / COUNTS_PER_MM as f32,
794 },
795 }),
796 None, None, None, MousePhase::Move,
800 SortedVecSet::new(),
801 SortedVecSet::new(),
802 event_time_u64,
803 &descriptor,
804 )];
805
806 assert_input_report_sequence_generates_events!(
807 input_reports: input_reports,
808 expected_events: expected_events,
809 device_descriptor: descriptor,
810 device_type: MouseBinding,
811 );
812 }
813
814 #[fasync::run_singlethreaded(test)]
816 async fn down_without_movement() {
817 let mouse_button: MouseButton = 3;
818 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
819 let first_report = testing_utilities::create_mouse_input_report_relative(
820 Position::zero(),
821 None, None, vec![mouse_button],
824 event_time_i64,
825 );
826 let descriptor = mouse_device_descriptor(DEVICE_ID);
827
828 let input_reports = vec![first_report];
829 let expected_events = vec![testing_utilities::create_mouse_event(
830 MouseLocation::Relative(Default::default()),
831 None, None, None, MousePhase::Down,
835 SortedVecSet::from(vec![mouse_button]),
836 SortedVecSet::from(vec![mouse_button]),
837 event_time_u64,
838 &descriptor,
839 )];
840
841 assert_input_report_sequence_generates_events!(
842 input_reports: input_reports,
843 expected_events: expected_events,
844 device_descriptor: descriptor,
845 device_type: MouseBinding,
846 );
847 }
848
849 #[fasync::run_singlethreaded(test)]
852 async fn down_with_movement() {
853 let mouse_button: MouseButton = 3;
854 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
855 let first_report = testing_utilities::create_mouse_input_report_relative(
856 Position { x: 10.0, y: 16.0 },
857 None, None, vec![mouse_button],
860 event_time_i64,
861 );
862 let descriptor = mouse_device_descriptor(DEVICE_ID);
863
864 let input_reports = vec![first_report];
865 let expected_events = vec![
866 testing_utilities::create_mouse_event(
867 MouseLocation::Relative(Default::default()),
868 None, None, None, MousePhase::Down,
872 SortedVecSet::from(vec![mouse_button]),
873 SortedVecSet::from(vec![mouse_button]),
874 event_time_u64,
875 &descriptor,
876 ),
877 testing_utilities::create_mouse_event(
878 MouseLocation::Relative(RelativeLocation {
879 millimeters: Position {
880 x: 10.0 / COUNTS_PER_MM as f32,
881 y: 16.0 / COUNTS_PER_MM as f32,
882 },
883 }),
884 None, None, None, MousePhase::Move,
888 SortedVecSet::from(vec![mouse_button]),
889 SortedVecSet::from(vec![mouse_button]),
890 event_time_u64,
891 &descriptor,
892 ),
893 ];
894
895 assert_input_report_sequence_generates_events!(
896 input_reports: input_reports,
897 expected_events: expected_events,
898 device_descriptor: descriptor,
899 device_type: MouseBinding,
900 );
901 }
902
903 #[fasync::run_singlethreaded(test)]
905 async fn down_up() {
906 let button = 1;
907 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
908 let first_report = testing_utilities::create_mouse_input_report_relative(
909 Position::zero(),
910 None, None, vec![button],
913 event_time_i64,
914 );
915 let second_report = testing_utilities::create_mouse_input_report_relative(
916 Position::zero(),
917 None, None, vec![],
920 event_time_i64,
921 );
922 let descriptor = mouse_device_descriptor(DEVICE_ID);
923
924 let input_reports = vec![first_report, second_report];
925 let expected_events = vec![
926 testing_utilities::create_mouse_event(
927 MouseLocation::Relative(Default::default()),
928 None, None, None, MousePhase::Down,
932 SortedVecSet::from(vec![button]),
933 SortedVecSet::from(vec![button]),
934 event_time_u64,
935 &descriptor,
936 ),
937 testing_utilities::create_mouse_event(
938 MouseLocation::Relative(Default::default()),
939 None, None, None, MousePhase::Up,
943 SortedVecSet::from(vec![button]),
944 SortedVecSet::new(),
945 event_time_u64,
946 &descriptor,
947 ),
948 ];
949
950 assert_input_report_sequence_generates_events!(
951 input_reports: input_reports,
952 expected_events: expected_events,
953 device_descriptor: descriptor,
954 device_type: MouseBinding,
955 );
956 }
957
958 #[fasync::run_singlethreaded(test)]
960 async fn down_up_with_movement() {
961 let button = 1;
962
963 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
964 let first_report = testing_utilities::create_mouse_input_report_relative(
965 Position::zero(),
966 None, None, vec![button],
969 event_time_i64,
970 );
971 let second_report = testing_utilities::create_mouse_input_report_relative(
972 Position { x: 10.0, y: 16.0 },
973 None, None, vec![],
976 event_time_i64,
977 );
978 let descriptor = mouse_device_descriptor(DEVICE_ID);
979
980 let input_reports = vec![first_report, second_report];
981 let expected_events = vec![
982 testing_utilities::create_mouse_event(
983 MouseLocation::Relative(Default::default()),
984 None, None, None, MousePhase::Down,
988 SortedVecSet::from(vec![button]),
989 SortedVecSet::from(vec![button]),
990 event_time_u64,
991 &descriptor,
992 ),
993 testing_utilities::create_mouse_event(
994 MouseLocation::Relative(RelativeLocation {
995 millimeters: Position {
996 x: 10.0 / COUNTS_PER_MM as f32,
997 y: 16.0 / COUNTS_PER_MM as f32,
998 },
999 }),
1000 None, None, None, MousePhase::Move,
1004 SortedVecSet::from(vec![button]),
1005 SortedVecSet::from(vec![button]),
1006 event_time_u64,
1007 &descriptor,
1008 ),
1009 testing_utilities::create_mouse_event(
1010 MouseLocation::Relative(Default::default()),
1011 None, None, None, MousePhase::Up,
1015 SortedVecSet::from(vec![button]),
1016 SortedVecSet::new(),
1017 event_time_u64,
1018 &descriptor,
1019 ),
1020 ];
1021
1022 assert_input_report_sequence_generates_events!(
1023 input_reports: input_reports,
1024 expected_events: expected_events,
1025 device_descriptor: descriptor,
1026 device_type: MouseBinding,
1027 );
1028 }
1029
1030 #[fasync::run_singlethreaded(test)]
1034 async fn down_move_up() {
1035 let button = 1;
1036
1037 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1038 let first_report = testing_utilities::create_mouse_input_report_relative(
1039 Position::zero(),
1040 None, None, vec![button],
1043 event_time_i64,
1044 );
1045 let second_report = testing_utilities::create_mouse_input_report_relative(
1046 Position { x: 10.0, y: 16.0 },
1047 None, None, vec![button],
1050 event_time_i64,
1051 );
1052 let third_report = testing_utilities::create_mouse_input_report_relative(
1053 Position::zero(),
1054 None, None, vec![],
1057 event_time_i64,
1058 );
1059 let descriptor = mouse_device_descriptor(DEVICE_ID);
1060
1061 let input_reports = vec![first_report, second_report, third_report];
1062 let expected_events = vec![
1063 testing_utilities::create_mouse_event(
1064 MouseLocation::Relative(Default::default()),
1065 None, None, None, MousePhase::Down,
1069 SortedVecSet::from(vec![button]),
1070 SortedVecSet::from(vec![button]),
1071 event_time_u64,
1072 &descriptor,
1073 ),
1074 testing_utilities::create_mouse_event(
1075 MouseLocation::Relative(RelativeLocation {
1076 millimeters: Position {
1077 x: 10.0 / COUNTS_PER_MM as f32,
1078 y: 16.0 / COUNTS_PER_MM as f32,
1079 },
1080 }),
1081 None, None, None, MousePhase::Move,
1085 SortedVecSet::from(vec![button]),
1086 SortedVecSet::from(vec![button]),
1087 event_time_u64,
1088 &descriptor,
1089 ),
1090 testing_utilities::create_mouse_event(
1091 MouseLocation::Relative(Default::default()),
1092 None, None, None, MousePhase::Up,
1096 SortedVecSet::from(vec![button]),
1097 SortedVecSet::new(),
1098 event_time_u64,
1099 &descriptor,
1100 ),
1101 ];
1102
1103 assert_input_report_sequence_generates_events!(
1104 input_reports: input_reports,
1105 expected_events: expected_events,
1106 device_descriptor: descriptor,
1107 device_type: MouseBinding,
1108 );
1109 }
1110
1111 #[fasync::run_until_stalled(test)]
1113 async fn absolute_movement_to_origin() {
1114 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1115 let descriptor = mouse_device_descriptor(DEVICE_ID);
1116
1117 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
1118 Position::zero(),
1119 None, None, vec![],
1122 event_time_i64,
1123 )];
1124 let expected_events = vec![testing_utilities::create_mouse_event(
1125 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1126 None, None, None, MousePhase::Move,
1130 SortedVecSet::new(),
1131 SortedVecSet::new(),
1132 event_time_u64,
1133 &descriptor,
1134 )];
1135
1136 assert_input_report_sequence_generates_events!(
1137 input_reports: input_reports,
1138 expected_events: expected_events,
1139 device_descriptor: descriptor,
1140 device_type: MouseBinding,
1141 );
1142 }
1143
1144 #[fasync::run_until_stalled(test)]
1147 async fn report_with_both_movement_and_position() {
1148 let relative_movement = Position { x: 5.0, y: 5.0 };
1149 let absolute_position = Position { x: 10.0, y: 10.0 };
1150 let expected_location = MouseLocation::Absolute(absolute_position);
1151
1152 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1153 let descriptor = mouse_device_descriptor(DEVICE_ID);
1154
1155 let input_reports = vec![fidl_next_fuchsia_input_report::InputReport {
1156 event_time: Some(event_time_i64),
1157 keyboard: None,
1158 mouse: Some(fidl_next_fuchsia_input_report::MouseInputReport {
1159 movement_x: Some(relative_movement.x as i64),
1160 movement_y: Some(relative_movement.y as i64),
1161 position_x: Some(absolute_position.x as i64),
1162 position_y: Some(absolute_position.y as i64),
1163 scroll_h: None,
1164 scroll_v: None,
1165 pressed_buttons: None,
1166 ..Default::default()
1167 }),
1168 touch: None,
1169 sensor: None,
1170 consumer_control: None,
1171 trace_id: None,
1172 ..Default::default()
1173 }];
1174 let expected_events = vec![testing_utilities::create_mouse_event(
1175 expected_location,
1176 None, None, None, MousePhase::Move,
1180 SortedVecSet::new(),
1181 SortedVecSet::new(),
1182 event_time_u64,
1183 &descriptor,
1184 )];
1185
1186 assert_input_report_sequence_generates_events!(
1187 input_reports: input_reports,
1188 expected_events: expected_events,
1189 device_descriptor: descriptor,
1190 device_type: MouseBinding,
1191 );
1192 }
1193
1194 #[fasync::run_singlethreaded(test)]
1197 async fn down_down() {
1198 const PRIMARY_BUTTON: u8 = 1;
1199 const SECONDARY_BUTTON: u8 = 2;
1200
1201 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1202 let first_report = testing_utilities::create_mouse_input_report_relative(
1203 Position::zero(),
1204 None, None, vec![PRIMARY_BUTTON],
1207 event_time_i64,
1208 );
1209 let second_report = testing_utilities::create_mouse_input_report_relative(
1210 Position::zero(),
1211 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1214 event_time_i64,
1215 );
1216 let descriptor = mouse_device_descriptor(DEVICE_ID);
1217
1218 let input_reports = vec![first_report, second_report];
1219 let expected_events = vec![
1220 testing_utilities::create_mouse_event(
1221 MouseLocation::Relative(Default::default()),
1222 None, None, None, MousePhase::Down,
1226 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1227 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1228 event_time_u64,
1229 &descriptor,
1230 ),
1231 testing_utilities::create_mouse_event(
1232 MouseLocation::Relative(Default::default()),
1233 None, None, None, MousePhase::Down,
1237 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1238 SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1239 event_time_u64,
1240 &descriptor,
1241 ),
1242 ];
1243
1244 assert_input_report_sequence_generates_events!(
1245 input_reports: input_reports,
1246 expected_events: expected_events,
1247 device_descriptor: descriptor,
1248 device_type: MouseBinding,
1249 );
1250 }
1251
1252 #[fasync::run_singlethreaded(test)]
1262 async fn down_down_up_up() {
1263 const PRIMARY_BUTTON: u8 = 1;
1264 const SECONDARY_BUTTON: u8 = 2;
1265
1266 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1267 let first_report = testing_utilities::create_mouse_input_report_relative(
1268 Position::zero(),
1269 None, None, vec![PRIMARY_BUTTON],
1272 event_time_i64,
1273 );
1274 let second_report = testing_utilities::create_mouse_input_report_relative(
1275 Position::zero(),
1276 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1279 event_time_i64,
1280 );
1281 let third_report = testing_utilities::create_mouse_input_report_relative(
1282 Position::zero(),
1283 None, None, vec![SECONDARY_BUTTON],
1286 event_time_i64,
1287 );
1288 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1289 Position::zero(),
1290 None, None, vec![],
1293 event_time_i64,
1294 );
1295 let descriptor = mouse_device_descriptor(DEVICE_ID);
1296
1297 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1298 let expected_events = vec![
1299 testing_utilities::create_mouse_event(
1300 MouseLocation::Relative(Default::default()),
1301 None, None, None, MousePhase::Down,
1305 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1306 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1307 event_time_u64,
1308 &descriptor,
1309 ),
1310 testing_utilities::create_mouse_event(
1311 MouseLocation::Relative(Default::default()),
1312 None, None, None, MousePhase::Down,
1316 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1317 SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1318 event_time_u64,
1319 &descriptor,
1320 ),
1321 testing_utilities::create_mouse_event(
1322 MouseLocation::Relative(Default::default()),
1323 None, None, None, MousePhase::Up,
1327 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1328 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1329 event_time_u64,
1330 &descriptor,
1331 ),
1332 testing_utilities::create_mouse_event(
1333 MouseLocation::Relative(Default::default()),
1334 None, None, None, MousePhase::Up,
1338 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1339 SortedVecSet::new(),
1340 event_time_u64,
1341 &descriptor,
1342 ),
1343 ];
1344
1345 assert_input_report_sequence_generates_events!(
1346 input_reports: input_reports,
1347 expected_events: expected_events,
1348 device_descriptor: descriptor,
1349 device_type: MouseBinding,
1350 );
1351 }
1352
1353 #[fasync::run_singlethreaded(test)]
1355 async fn scroll() {
1356 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1357 let first_report = testing_utilities::create_mouse_input_report_relative(
1358 Position::zero(),
1359 Some(1),
1360 None,
1361 vec![],
1362 event_time_i64,
1363 );
1364 let second_report = testing_utilities::create_mouse_input_report_relative(
1365 Position::zero(),
1366 None,
1367 Some(1),
1368 vec![],
1369 event_time_i64,
1370 );
1371
1372 let descriptor = mouse_device_descriptor(DEVICE_ID);
1373
1374 let input_reports = vec![first_report, second_report];
1375 let expected_events = vec![
1376 testing_utilities::create_mouse_event(
1377 MouseLocation::Relative(Default::default()),
1378 wheel_delta_ticks(1),
1379 None,
1380 Some(PrecisionScroll::No),
1381 MousePhase::Wheel,
1382 SortedVecSet::new(),
1383 SortedVecSet::new(),
1384 event_time_u64,
1385 &descriptor,
1386 ),
1387 testing_utilities::create_mouse_event(
1388 MouseLocation::Relative(Default::default()),
1389 None,
1390 wheel_delta_ticks(1),
1391 Some(PrecisionScroll::No),
1392 MousePhase::Wheel,
1393 SortedVecSet::new(),
1394 SortedVecSet::new(),
1395 event_time_u64,
1396 &descriptor,
1397 ),
1398 ];
1399
1400 assert_input_report_sequence_generates_events!(
1401 input_reports: input_reports,
1402 expected_events: expected_events,
1403 device_descriptor: descriptor,
1404 device_type: MouseBinding,
1405 );
1406 }
1407
1408 #[fasync::run_singlethreaded(test)]
1410 async fn down_scroll_up_scroll() {
1411 const PRIMARY_BUTTON: u8 = 1;
1412
1413 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1414 let first_report = testing_utilities::create_mouse_input_report_relative(
1415 Position::zero(),
1416 None, None, vec![PRIMARY_BUTTON],
1419 event_time_i64,
1420 );
1421 let second_report = testing_utilities::create_mouse_input_report_relative(
1422 Position::zero(),
1423 Some(1),
1424 None,
1425 vec![PRIMARY_BUTTON],
1426 event_time_i64,
1427 );
1428 let third_report = testing_utilities::create_mouse_input_report_relative(
1429 Position::zero(),
1430 None, None, vec![],
1433 event_time_i64,
1434 );
1435 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1436 Position::zero(),
1437 Some(1),
1438 None,
1439 vec![],
1440 event_time_i64,
1441 );
1442
1443 let descriptor = mouse_device_descriptor(DEVICE_ID);
1444
1445 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1446 let expected_events = vec![
1447 testing_utilities::create_mouse_event(
1448 MouseLocation::Relative(Default::default()),
1449 None, None, None, MousePhase::Down,
1453 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1454 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1455 event_time_u64,
1456 &descriptor,
1457 ),
1458 testing_utilities::create_mouse_event(
1459 MouseLocation::Relative(Default::default()),
1460 wheel_delta_ticks(1),
1461 None,
1462 Some(PrecisionScroll::No),
1463 MousePhase::Wheel,
1464 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1465 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1466 event_time_u64,
1467 &descriptor,
1468 ),
1469 testing_utilities::create_mouse_event(
1470 MouseLocation::Relative(Default::default()),
1471 None, None, None, MousePhase::Up,
1475 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1476 SortedVecSet::new(),
1477 event_time_u64,
1478 &descriptor,
1479 ),
1480 testing_utilities::create_mouse_event(
1481 MouseLocation::Relative(Default::default()),
1482 wheel_delta_ticks(1),
1483 None,
1484 Some(PrecisionScroll::No),
1485 MousePhase::Wheel,
1486 SortedVecSet::new(),
1487 SortedVecSet::new(),
1488 event_time_u64,
1489 &descriptor,
1490 ),
1491 ];
1492
1493 assert_input_report_sequence_generates_events!(
1494 input_reports: input_reports,
1495 expected_events: expected_events,
1496 device_descriptor: descriptor,
1497 device_type: MouseBinding,
1498 );
1499 }
1500
1501 #[fasync::run_singlethreaded(test)]
1503 async fn down_scroll_bundle_up_scroll_bundle() {
1504 const PRIMARY_BUTTON: u8 = 1;
1505
1506 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1507 let first_report = testing_utilities::create_mouse_input_report_relative(
1508 Position::zero(),
1509 Some(1),
1510 None,
1511 vec![PRIMARY_BUTTON],
1512 event_time_i64,
1513 );
1514 let second_report = testing_utilities::create_mouse_input_report_relative(
1515 Position::zero(),
1516 Some(1),
1517 None,
1518 vec![],
1519 event_time_i64,
1520 );
1521 let third_report = testing_utilities::create_mouse_input_report_relative(
1522 Position::zero(),
1523 Some(1),
1524 None,
1525 vec![],
1526 event_time_i64,
1527 );
1528
1529 let descriptor = mouse_device_descriptor(DEVICE_ID);
1530
1531 let input_reports = vec![first_report, second_report, third_report];
1532 let expected_events = vec![
1533 testing_utilities::create_mouse_event(
1534 MouseLocation::Relative(Default::default()),
1535 None, None, None, MousePhase::Down,
1539 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1540 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1541 event_time_u64,
1542 &descriptor,
1543 ),
1544 testing_utilities::create_mouse_event(
1545 MouseLocation::Relative(Default::default()),
1546 wheel_delta_ticks(1),
1547 None,
1548 Some(PrecisionScroll::No),
1549 MousePhase::Wheel,
1550 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1551 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1552 event_time_u64,
1553 &descriptor,
1554 ),
1555 testing_utilities::create_mouse_event(
1556 MouseLocation::Relative(Default::default()),
1557 wheel_delta_ticks(1),
1558 None,
1559 Some(PrecisionScroll::No),
1560 MousePhase::Wheel,
1561 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1562 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1563 event_time_u64,
1564 &descriptor,
1565 ),
1566 testing_utilities::create_mouse_event(
1567 MouseLocation::Relative(Default::default()),
1568 None, None, None, MousePhase::Up,
1572 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1573 SortedVecSet::new(),
1574 event_time_u64,
1575 &descriptor,
1576 ),
1577 testing_utilities::create_mouse_event(
1578 MouseLocation::Relative(Default::default()),
1579 wheel_delta_ticks(1),
1580 None,
1581 Some(PrecisionScroll::No),
1582 MousePhase::Wheel,
1583 SortedVecSet::new(),
1584 SortedVecSet::new(),
1585 event_time_u64,
1586 &descriptor,
1587 ),
1588 ];
1589
1590 assert_input_report_sequence_generates_events!(
1591 input_reports: input_reports,
1592 expected_events: expected_events,
1593 device_descriptor: descriptor,
1594 device_type: MouseBinding,
1595 );
1596 }
1597}