1use crate::input_device::{self, Handled, InputDeviceBinding, InputDeviceStatus, InputEvent};
6use crate::utils::{self, Position};
7use crate::{Transport, metrics};
8use anyhow::{Error, format_err};
9use async_trait::async_trait;
10use fuchsia_inspect::ArrayProperty;
11use fuchsia_inspect::health::Reporter;
12use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
13use metrics_registry::*;
14use sorted_vec_map::SortedVecSet;
15use zx;
16
17pub type MouseButton = u8;
18
19#[derive(Copy, Clone, Debug, PartialEq)]
21pub enum PrecisionScroll {
22 Yes,
24 No,
26}
27
28#[derive(Copy, Clone, Debug, PartialEq)]
30pub enum MouseLocation {
31 Relative(RelativeLocation),
33
34 Absolute(Position),
36}
37
38#[derive(Copy, Clone, Debug, PartialEq)]
39pub enum MousePhase {
40 Down, Move, Up, Wheel, }
45
46#[derive(Copy, Clone, Debug, PartialEq)]
48pub struct RelativeLocation {
49 pub counts: Position,
51}
52
53impl Default for RelativeLocation {
54 fn default() -> Self {
55 RelativeLocation { counts: Position::zero() }
56 }
57}
58
59#[derive(Clone, Debug, PartialEq)]
62pub struct WheelDelta {
63 pub ticks: i64,
64 pub physical_pixel: Option<f32>,
65}
66
67#[derive(Debug)]
89pub struct MouseEvent {
90 pub location: MouseLocation,
92
93 pub wheel_delta_v: Option<WheelDelta>,
95
96 pub wheel_delta_h: Option<WheelDelta>,
98
99 pub is_precision_scroll: Option<PrecisionScroll>,
101
102 pub phase: MousePhase,
104
105 pub affected_buttons: SortedVecSet<MouseButton>,
107
108 pub pressed_buttons: SortedVecSet<MouseButton>,
110
111 pub wake_lease: Option<zx::EventPair>,
113}
114
115impl Clone for MouseEvent {
116 fn clone(&self) -> Self {
117 log::debug!("MouseEvent cloned without wake lease.");
118 Self {
119 location: self.location,
120 wheel_delta_v: self.wheel_delta_v.clone(),
121 wheel_delta_h: self.wheel_delta_h.clone(),
122 is_precision_scroll: self.is_precision_scroll,
123 phase: self.phase,
124 affected_buttons: self.affected_buttons.clone(),
125 pressed_buttons: self.pressed_buttons.clone(),
126 wake_lease: None,
127 }
128 }
129}
130
131impl PartialEq for MouseEvent {
132 fn eq(&self, other: &Self) -> bool {
133 self.location == other.location
134 && self.wheel_delta_v == other.wheel_delta_v
135 && self.wheel_delta_h == other.wheel_delta_h
136 && self.is_precision_scroll == other.is_precision_scroll
137 && self.phase == other.phase
138 && self.affected_buttons == other.affected_buttons
139 && self.pressed_buttons == other.pressed_buttons
140 }
141}
142
143impl MouseEvent {
144 pub fn new(
152 location: MouseLocation,
153 wheel_delta_v: Option<WheelDelta>,
154 wheel_delta_h: Option<WheelDelta>,
155 phase: MousePhase,
156 affected_buttons: SortedVecSet<MouseButton>,
157 pressed_buttons: SortedVecSet<MouseButton>,
158 is_precision_scroll: Option<PrecisionScroll>,
159 wake_lease: Option<zx::EventPair>,
160 ) -> MouseEvent {
161 MouseEvent {
162 location,
163 wheel_delta_v,
164 wheel_delta_h,
165 phase,
166 affected_buttons,
167 pressed_buttons,
168 is_precision_scroll,
169 wake_lease,
170 }
171 }
172
173 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
174 if let Some(wheel_delta_v) = &self.wheel_delta_v {
176 node.record_child("wheel_delta_v", move |wheel_delta_v_node| {
177 wheel_delta_v_node.record_int("ticks", wheel_delta_v.ticks);
178 if let Some(physical_pixel) = wheel_delta_v.physical_pixel {
179 wheel_delta_v_node.record_double("physical_pixel", f64::from(physical_pixel));
180 }
181 });
182 }
183
184 if let Some(wheel_delta_h) = &self.wheel_delta_h {
185 node.record_child("wheel_delta_h", move |wheel_delta_h_node| {
186 wheel_delta_h_node.record_int("ticks", wheel_delta_h.ticks);
187 if let Some(physical_pixel) = wheel_delta_h.physical_pixel {
188 wheel_delta_h_node.record_double("physical_pixel", f64::from(physical_pixel));
189 }
190 });
191 }
192
193 if let Some(is_precision_scroll) = self.is_precision_scroll {
194 match is_precision_scroll {
195 PrecisionScroll::Yes => node.record_string("is_precision_scroll", "yes"),
196 PrecisionScroll::No => node.record_string("is_precision_scroll", "no"),
197 }
198 }
199
200 match self.phase {
201 MousePhase::Down => node.record_string("phase", "down"),
202 MousePhase::Move => node.record_string("phase", "move"),
203 MousePhase::Up => node.record_string("phase", "up"),
204 MousePhase::Wheel => node.record_string("phase", "wheel"),
205 }
206
207 let affected_buttons_node =
208 node.create_uint_array("affected_buttons", self.affected_buttons.len());
209 self.affected_buttons.iter().enumerate().for_each(|(i, button)| {
210 affected_buttons_node.set(i, *button);
211 });
212 node.record(affected_buttons_node);
213
214 let pressed_buttons_node =
215 node.create_uint_array("pressed_buttons", self.pressed_buttons.len());
216 self.pressed_buttons.iter().enumerate().for_each(|(i, button)| {
217 pressed_buttons_node.set(i, *button);
218 });
219 node.record(pressed_buttons_node);
220 }
221}
222
223pub struct MouseBinding {
229 event_sender: UnboundedSender<Vec<InputEvent>>,
231
232 device_descriptor: MouseDeviceDescriptor,
234}
235
236#[derive(Clone, Debug, Eq, PartialEq)]
237pub struct MouseDeviceDescriptor {
238 pub device_id: u32,
240
241 pub absolute_x_range: Option<fidl_fuchsia_input::Range>,
243
244 pub absolute_y_range: Option<fidl_fuchsia_input::Range>,
246
247 pub wheel_v_range: Option<fidl_fuchsia_input::Axis>,
249
250 pub wheel_h_range: Option<fidl_fuchsia_input::Axis>,
252
253 pub buttons: Option<Vec<MouseButton>>,
255}
256
257#[async_trait]
258impl input_device::InputDeviceBinding for MouseBinding {
259 fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>> {
260 self.event_sender.clone()
261 }
262
263 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
264 input_device::InputDeviceDescriptor::Mouse(self.device_descriptor.clone())
265 }
266}
267
268impl MouseBinding {
269 pub async fn new(
284 device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
285 device_id: u32,
286 input_event_sender: UnboundedSender<Vec<InputEvent>>,
287 device_node: fuchsia_inspect::Node,
288 _feature_flags: input_device::InputPipelineFeatureFlags,
289 metrics_logger: metrics::MetricsLogger,
290 ) -> Result<Self, Error> {
291 let (device_binding, mut inspect_status) =
292 Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
293 inspect_status.health_node.set_ok();
294 input_device::initialize_report_stream(
295 device_proxy,
296 device_binding.get_device_descriptor(),
297 device_binding.input_event_sender(),
298 inspect_status,
299 metrics_logger,
300 _feature_flags,
301 Self::process_reports,
302 );
303
304 Ok(device_binding)
305 }
306
307 async fn bind_device(
319 device: &fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
320 device_id: u32,
321 input_event_sender: UnboundedSender<Vec<InputEvent>>,
322 device_node: fuchsia_inspect::Node,
323 ) -> Result<(Self, InputDeviceStatus), Error> {
324 let mut input_device_status = InputDeviceStatus::new(device_node);
325 let device_descriptor: fidl_next_fuchsia_input_report::DeviceDescriptor = match device
326 .get_descriptor()
327 .await
328 {
329 Ok(res) => res.descriptor,
330 Err(_) => {
331 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
332 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
333 }
334 };
335
336 let mouse_descriptor = device_descriptor.mouse.ok_or_else(|| {
337 input_device_status
338 .health_node
339 .set_unhealthy("DeviceDescriptor does not have a MouseDescriptor.");
340 format_err!("DeviceDescriptor does not have a MouseDescriptor")
341 })?;
342
343 let mouse_input_descriptor = mouse_descriptor.input.ok_or_else(|| {
344 input_device_status
345 .health_node
346 .set_unhealthy("MouseDescriptor does not have a MouseInputDescriptor.");
347 format_err!("MouseDescriptor does not have a MouseInputDescriptor")
348 })?;
349
350 let device_descriptor: MouseDeviceDescriptor = MouseDeviceDescriptor {
351 device_id,
352 absolute_x_range: mouse_input_descriptor
353 .position_x
354 .as_ref()
355 .map(|axis| utils::range_to_old(&axis.range)),
356 absolute_y_range: mouse_input_descriptor
357 .position_y
358 .as_ref()
359 .map(|axis| utils::range_to_old(&axis.range)),
360 wheel_v_range: utils::axis_to_old(mouse_input_descriptor.scroll_v.as_ref()),
361 wheel_h_range: utils::axis_to_old(mouse_input_descriptor.scroll_h.as_ref()),
362 buttons: mouse_input_descriptor.buttons,
363 };
364
365 Ok((Self { event_sender: input_event_sender, device_descriptor }, input_device_status))
366 }
367
368 fn process_reports(
390 reports: &[fidl_next_fuchsia_input_report::wire::InputReport<'_>],
391 mut previous_state: Option<input_device::PreviousDeviceState>,
392 device_descriptor: &input_device::InputDeviceDescriptor,
393 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
394 inspect_status: &InputDeviceStatus,
395 metrics_logger: &metrics::MetricsLogger,
396 _feature_flags: &input_device::InputPipelineFeatureFlags,
397 ) -> (Option<input_device::PreviousDeviceState>, Option<UnboundedReceiver<InputEvent>>) {
398 fuchsia_trace::duration!("input", "mouse-binding-process-reports", "num_reports" => reports.len());
399 for report in reports {
400 previous_state = Self::process_report(
401 report,
402 previous_state,
403 device_descriptor,
404 input_event_sender,
405 inspect_status,
406 metrics_logger,
407 );
408 }
409 (previous_state, None)
410 }
411
412 fn process_report(
413 report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
414 previous_state: Option<input_device::PreviousDeviceState>,
415 device_descriptor: &input_device::InputDeviceDescriptor,
416 input_event_sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
417 inspect_status: &InputDeviceStatus,
418 metrics_logger: &metrics::MetricsLogger,
419 ) -> Option<input_device::PreviousDeviceState> {
420 if let Some(trace_id) = report.trace_id() {
421 fuchsia_trace::flow_end!("input", "input_report", trace_id.0.into());
422 }
423
424 let wake_lease = utils::duplicate_wake_lease(report.wake_lease());
428
429 inspect_status.count_received_report_wire(report);
430 let mouse_report = match report.mouse() {
432 Some(mouse) => mouse,
433 None => {
434 inspect_status.count_filtered_report();
435 return previous_state;
436 }
437 };
438
439 let previous_buttons: SortedVecSet<MouseButton> = match previous_state {
440 Some(input_device::PreviousDeviceState::Mouse { pressed_buttons }) => pressed_buttons,
441 _ => SortedVecSet::new(),
442 };
443 let current_buttons: SortedVecSet<MouseButton> =
444 buttons_from_mouse_report_wire(mouse_report);
445
446 send_mouse_event(
452 MouseLocation::Relative(Default::default()),
453 None, None, MousePhase::Down,
456 current_buttons.difference(&previous_buttons).cloned().collect(),
457 current_buttons.clone(),
458 device_descriptor,
459 input_event_sender,
460 inspect_status,
461 metrics_logger,
462 wake_lease.as_ref().map(|lease| {
463 lease
464 .duplicate_handle(zx::Rights::SAME_RIGHTS)
465 .expect("failed to duplicate event pair")
466 }),
467 );
468
469 let location = if let (Some(position_x), Some(position_y)) =
471 (mouse_report.position_x(), mouse_report.position_y())
472 {
473 MouseLocation::Absolute(Position { x: position_x.0 as f32, y: position_y.0 as f32 })
474 } else {
475 let movement_x = mouse_report.movement_x().map(|x| x.0).unwrap_or_default() as f32;
476 let movement_y = mouse_report.movement_y().map(|y| y.0).unwrap_or_default() as f32;
477 MouseLocation::Relative(RelativeLocation {
478 counts: Position { x: movement_x, y: movement_y },
479 })
480 };
481
482 send_mouse_event(
486 location,
487 None, None, MousePhase::Move,
490 current_buttons.union(&previous_buttons).cloned().collect(),
491 current_buttons.union(&previous_buttons).cloned().collect(),
492 device_descriptor,
493 input_event_sender,
494 inspect_status,
495 metrics_logger,
496 wake_lease.as_ref().map(|lease| {
497 lease
498 .duplicate_handle(zx::Rights::SAME_RIGHTS)
499 .expect("failed to duplicate event pair")
500 }),
501 );
502
503 let wheel_delta_v = mouse_report
504 .scroll_v()
505 .map(|ticks| WheelDelta { ticks: ticks.0, physical_pixel: None });
506
507 let wheel_delta_h = mouse_report
508 .scroll_h()
509 .map(|ticks| WheelDelta { ticks: ticks.0, physical_pixel: None });
510
511 send_mouse_event(
513 MouseLocation::Relative(Default::default()),
514 wheel_delta_v,
515 wheel_delta_h,
516 MousePhase::Wheel,
517 current_buttons.union(&previous_buttons).cloned().collect(),
518 current_buttons.union(&previous_buttons).cloned().collect(),
519 device_descriptor,
520 input_event_sender,
521 inspect_status,
522 metrics_logger,
523 wake_lease.as_ref().map(|lease| {
524 lease
525 .duplicate_handle(zx::Rights::SAME_RIGHTS)
526 .expect("failed to duplicate event pair")
527 }),
528 );
529
530 send_mouse_event(
536 MouseLocation::Relative(Default::default()),
537 None, None, MousePhase::Up,
540 previous_buttons.difference(¤t_buttons).cloned().collect(),
541 current_buttons.clone(),
542 device_descriptor,
543 input_event_sender,
544 inspect_status,
545 metrics_logger,
546 wake_lease,
547 );
548
549 Some(input_device::PreviousDeviceState::Mouse { pressed_buttons: current_buttons })
550 }
551}
552
553fn send_mouse_event(
568 location: MouseLocation,
569 wheel_delta_v: Option<WheelDelta>,
570 wheel_delta_h: Option<WheelDelta>,
571 phase: MousePhase,
572 affected_buttons: SortedVecSet<MouseButton>,
573 pressed_buttons: SortedVecSet<MouseButton>,
574 device_descriptor: &input_device::InputDeviceDescriptor,
575 sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
576 inspect_status: &InputDeviceStatus,
577 metrics_logger: &metrics::MetricsLogger,
578 wake_lease: Option<zx::EventPair>,
579) {
580 if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
582 return;
583 }
584
585 if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
588 return;
589 }
590
591 if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
593 return;
594 }
595
596 let trace_id = fuchsia_trace::Id::new();
597 fuchsia_trace::duration!("input", "mouse-binding-send-event");
598 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
599
600 let event = input_device::InputEvent {
601 device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
602 location,
603 wheel_delta_v,
604 wheel_delta_h,
605 phase,
606 affected_buttons,
607 pressed_buttons,
608 match phase {
609 MousePhase::Wheel => Some(PrecisionScroll::No),
610 _ => None,
611 },
612 wake_lease,
613 )),
614 device_descriptor: device_descriptor.clone(),
615 event_time: zx::MonotonicInstant::get(),
616 handled: Handled::No,
617 trace_id: Some(trace_id),
618 };
619 let events = vec![event];
620 inspect_status.count_generated_events(&events);
621
622 if let Err(e) = sender.unbounded_send(events) {
623 metrics_logger.log_error(
624 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
625 std::format!("Failed to send MouseEvent with error: {:?}", e),
626 );
627 }
628}
629
630fn buttons_from_mouse_report_wire(
631 mouse_report: &fidl_next_fuchsia_input_report::wire::MouseInputReport<'_>,
632) -> SortedVecSet<MouseButton> {
633 mouse_report
634 .pressed_buttons()
635 .map(|buttons| SortedVecSet::from_iter(buttons.iter().copied()))
636 .unwrap_or_default()
637}
638
639#[cfg(test)]
640mod tests {
641 use super::*;
642 use crate::testing_utilities;
643 use futures::StreamExt;
644 use sorted_vec_map::SortedVecSet;
645
646 const DEVICE_ID: u32 = 1;
647
648 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
649 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
650 device_id,
651 absolute_x_range: None,
652 absolute_y_range: None,
653 wheel_v_range: Some(fidl_fuchsia_input::Axis {
654 range: fidl_fuchsia_input::Range { min: -1, max: 1 },
655 unit: fidl_fuchsia_input::Unit {
656 type_: fidl_fuchsia_input::UnitType::Other,
657 exponent: 1,
658 },
659 }),
660 wheel_h_range: Some(fidl_fuchsia_input::Axis {
661 range: fidl_fuchsia_input::Range { min: -1, max: 1 },
662 unit: fidl_fuchsia_input::Unit {
663 type_: fidl_fuchsia_input::UnitType::Other,
664 exponent: 1,
665 },
666 }),
667 buttons: None,
668 })
669 }
670
671 fn wheel_delta_ticks(ticks: i64) -> Option<WheelDelta> {
672 Some(WheelDelta { ticks, physical_pixel: None })
673 }
674
675 #[fuchsia::test]
677 async fn movement_without_button() {
678 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
679 let first_report = testing_utilities::create_mouse_input_report_relative(
680 Position { x: 10.0, y: 16.0 },
681 None, None, vec![],
684 event_time_i64,
685 );
686 let descriptor = mouse_device_descriptor(DEVICE_ID);
687
688 let input_reports = vec![first_report];
689 let expected_events = vec![testing_utilities::create_mouse_event(
690 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
691 None, None, None, MousePhase::Move,
695 SortedVecSet::new(),
696 SortedVecSet::new(),
697 event_time_u64,
698 &descriptor,
699 )];
700
701 assert_input_report_sequence_generates_events!(
702 input_reports: input_reports,
703 expected_events: expected_events,
704 device_descriptor: descriptor,
705 device_type: MouseBinding,
706 );
707 }
708
709 #[fuchsia::test]
711 async fn down_without_movement() {
712 let mouse_button: MouseButton = 3;
713 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
714 let first_report = testing_utilities::create_mouse_input_report_relative(
715 Position::zero(),
716 None, None, vec![mouse_button],
719 event_time_i64,
720 );
721 let descriptor = mouse_device_descriptor(DEVICE_ID);
722
723 let input_reports = vec![first_report];
724 let expected_events = vec![testing_utilities::create_mouse_event(
725 MouseLocation::Relative(Default::default()),
726 None, None, None, MousePhase::Down,
730 SortedVecSet::from(vec![mouse_button]),
731 SortedVecSet::from(vec![mouse_button]),
732 event_time_u64,
733 &descriptor,
734 )];
735
736 assert_input_report_sequence_generates_events!(
737 input_reports: input_reports,
738 expected_events: expected_events,
739 device_descriptor: descriptor,
740 device_type: MouseBinding,
741 );
742 }
743
744 #[fuchsia::test]
747 async fn down_with_movement() {
748 let mouse_button: MouseButton = 3;
749 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
750 let first_report = testing_utilities::create_mouse_input_report_relative(
751 Position { x: 10.0, y: 16.0 },
752 None, None, vec![mouse_button],
755 event_time_i64,
756 );
757 let descriptor = mouse_device_descriptor(DEVICE_ID);
758
759 let input_reports = vec![first_report];
760 let expected_events = vec![
761 testing_utilities::create_mouse_event(
762 MouseLocation::Relative(Default::default()),
763 None, None, None, MousePhase::Down,
767 SortedVecSet::from(vec![mouse_button]),
768 SortedVecSet::from(vec![mouse_button]),
769 event_time_u64,
770 &descriptor,
771 ),
772 testing_utilities::create_mouse_event(
773 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
774 None, None, None, MousePhase::Move,
778 SortedVecSet::from(vec![mouse_button]),
779 SortedVecSet::from(vec![mouse_button]),
780 event_time_u64,
781 &descriptor,
782 ),
783 ];
784
785 assert_input_report_sequence_generates_events!(
786 input_reports: input_reports,
787 expected_events: expected_events,
788 device_descriptor: descriptor,
789 device_type: MouseBinding,
790 );
791 }
792
793 #[fuchsia::test]
795 async fn down_up() {
796 let button = 1;
797 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
798 let first_report = testing_utilities::create_mouse_input_report_relative(
799 Position::zero(),
800 None, None, vec![button],
803 event_time_i64,
804 );
805 let second_report = testing_utilities::create_mouse_input_report_relative(
806 Position::zero(),
807 None, None, vec![],
810 event_time_i64,
811 );
812 let descriptor = mouse_device_descriptor(DEVICE_ID);
813
814 let input_reports = vec![first_report, second_report];
815 let expected_events = vec![
816 testing_utilities::create_mouse_event(
817 MouseLocation::Relative(Default::default()),
818 None, None, None, MousePhase::Down,
822 SortedVecSet::from(vec![button]),
823 SortedVecSet::from(vec![button]),
824 event_time_u64,
825 &descriptor,
826 ),
827 testing_utilities::create_mouse_event(
828 MouseLocation::Relative(Default::default()),
829 None, None, None, MousePhase::Up,
833 SortedVecSet::from(vec![button]),
834 SortedVecSet::new(),
835 event_time_u64,
836 &descriptor,
837 ),
838 ];
839
840 assert_input_report_sequence_generates_events!(
841 input_reports: input_reports,
842 expected_events: expected_events,
843 device_descriptor: descriptor,
844 device_type: MouseBinding,
845 );
846 }
847
848 #[fuchsia::test]
850 async fn down_up_with_movement() {
851 let button = 1;
852
853 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
854 let first_report = testing_utilities::create_mouse_input_report_relative(
855 Position::zero(),
856 None, None, vec![button],
859 event_time_i64,
860 );
861 let second_report = testing_utilities::create_mouse_input_report_relative(
862 Position { x: 10.0, y: 16.0 },
863 None, None, vec![],
866 event_time_i64,
867 );
868 let descriptor = mouse_device_descriptor(DEVICE_ID);
869
870 let input_reports = vec![first_report, second_report];
871 let expected_events = vec![
872 testing_utilities::create_mouse_event(
873 MouseLocation::Relative(Default::default()),
874 None, None, None, MousePhase::Down,
878 SortedVecSet::from(vec![button]),
879 SortedVecSet::from(vec![button]),
880 event_time_u64,
881 &descriptor,
882 ),
883 testing_utilities::create_mouse_event(
884 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
885 None, None, None, MousePhase::Move,
889 SortedVecSet::from(vec![button]),
890 SortedVecSet::from(vec![button]),
891 event_time_u64,
892 &descriptor,
893 ),
894 testing_utilities::create_mouse_event(
895 MouseLocation::Relative(Default::default()),
896 None, None, None, MousePhase::Up,
900 SortedVecSet::from(vec![button]),
901 SortedVecSet::new(),
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 #[fuchsia::test]
919 async fn down_move_up() {
920 let button = 1;
921
922 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
923 let first_report = testing_utilities::create_mouse_input_report_relative(
924 Position::zero(),
925 None, None, vec![button],
928 event_time_i64,
929 );
930 let second_report = testing_utilities::create_mouse_input_report_relative(
931 Position { x: 10.0, y: 16.0 },
932 None, None, vec![button],
935 event_time_i64,
936 );
937 let third_report = testing_utilities::create_mouse_input_report_relative(
938 Position::zero(),
939 None, None, vec![],
942 event_time_i64,
943 );
944 let descriptor = mouse_device_descriptor(DEVICE_ID);
945
946 let input_reports = vec![first_report, second_report, third_report];
947 let expected_events = vec![
948 testing_utilities::create_mouse_event(
949 MouseLocation::Relative(Default::default()),
950 None, None, None, MousePhase::Down,
954 SortedVecSet::from(vec![button]),
955 SortedVecSet::from(vec![button]),
956 event_time_u64,
957 &descriptor,
958 ),
959 testing_utilities::create_mouse_event(
960 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
961 None, None, None, MousePhase::Move,
965 SortedVecSet::from(vec![button]),
966 SortedVecSet::from(vec![button]),
967 event_time_u64,
968 &descriptor,
969 ),
970 testing_utilities::create_mouse_event(
971 MouseLocation::Relative(Default::default()),
972 None, None, None, MousePhase::Up,
976 SortedVecSet::from(vec![button]),
977 SortedVecSet::new(),
978 event_time_u64,
979 &descriptor,
980 ),
981 ];
982
983 assert_input_report_sequence_generates_events!(
984 input_reports: input_reports,
985 expected_events: expected_events,
986 device_descriptor: descriptor,
987 device_type: MouseBinding,
988 );
989 }
990
991 #[fuchsia::test(allow_stalls = false)]
993 async fn absolute_movement_to_origin() {
994 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
995 let descriptor = mouse_device_descriptor(DEVICE_ID);
996
997 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
998 Position::zero(),
999 None, None, vec![],
1002 event_time_i64,
1003 )];
1004 let expected_events = vec![testing_utilities::create_mouse_event(
1005 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1006 None, None, None, MousePhase::Move,
1010 SortedVecSet::new(),
1011 SortedVecSet::new(),
1012 event_time_u64,
1013 &descriptor,
1014 )];
1015
1016 assert_input_report_sequence_generates_events!(
1017 input_reports: input_reports,
1018 expected_events: expected_events,
1019 device_descriptor: descriptor,
1020 device_type: MouseBinding,
1021 );
1022 }
1023
1024 #[fuchsia::test(allow_stalls = false)]
1027 async fn report_with_both_movement_and_position() {
1028 let relative_movement = Position { x: 5.0, y: 5.0 };
1029 let absolute_position = Position { x: 10.0, y: 10.0 };
1030 let expected_location = MouseLocation::Absolute(absolute_position);
1031
1032 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1033 let descriptor = mouse_device_descriptor(DEVICE_ID);
1034
1035 let input_reports = vec![fidl_next_fuchsia_input_report::InputReport {
1036 event_time: Some(event_time_i64),
1037 keyboard: None,
1038 mouse: Some(fidl_next_fuchsia_input_report::MouseInputReport {
1039 movement_x: Some(relative_movement.x as i64),
1040 movement_y: Some(relative_movement.y as i64),
1041 position_x: Some(absolute_position.x as i64),
1042 position_y: Some(absolute_position.y as i64),
1043 scroll_h: None,
1044 scroll_v: None,
1045 pressed_buttons: None,
1046 ..Default::default()
1047 }),
1048 touch: None,
1049 sensor: None,
1050 consumer_control: None,
1051 trace_id: None,
1052 ..Default::default()
1053 }];
1054 let expected_events = vec![testing_utilities::create_mouse_event(
1055 expected_location,
1056 None, None, None, MousePhase::Move,
1060 SortedVecSet::new(),
1061 SortedVecSet::new(),
1062 event_time_u64,
1063 &descriptor,
1064 )];
1065
1066 assert_input_report_sequence_generates_events!(
1067 input_reports: input_reports,
1068 expected_events: expected_events,
1069 device_descriptor: descriptor,
1070 device_type: MouseBinding,
1071 );
1072 }
1073
1074 #[fuchsia::test]
1077 async fn down_down() {
1078 const PRIMARY_BUTTON: u8 = 1;
1079 const SECONDARY_BUTTON: u8 = 2;
1080
1081 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1082 let first_report = testing_utilities::create_mouse_input_report_relative(
1083 Position::zero(),
1084 None, None, vec![PRIMARY_BUTTON],
1087 event_time_i64,
1088 );
1089 let second_report = testing_utilities::create_mouse_input_report_relative(
1090 Position::zero(),
1091 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1094 event_time_i64,
1095 );
1096 let descriptor = mouse_device_descriptor(DEVICE_ID);
1097
1098 let input_reports = vec![first_report, second_report];
1099 let expected_events = vec![
1100 testing_utilities::create_mouse_event(
1101 MouseLocation::Relative(Default::default()),
1102 None, None, None, MousePhase::Down,
1106 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1107 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1108 event_time_u64,
1109 &descriptor,
1110 ),
1111 testing_utilities::create_mouse_event(
1112 MouseLocation::Relative(Default::default()),
1113 None, None, None, MousePhase::Down,
1117 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1118 SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1119 event_time_u64,
1120 &descriptor,
1121 ),
1122 ];
1123
1124 assert_input_report_sequence_generates_events!(
1125 input_reports: input_reports,
1126 expected_events: expected_events,
1127 device_descriptor: descriptor,
1128 device_type: MouseBinding,
1129 );
1130 }
1131
1132 #[fuchsia::test]
1142 async fn down_down_up_up() {
1143 const PRIMARY_BUTTON: u8 = 1;
1144 const SECONDARY_BUTTON: u8 = 2;
1145
1146 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1147 let first_report = testing_utilities::create_mouse_input_report_relative(
1148 Position::zero(),
1149 None, None, vec![PRIMARY_BUTTON],
1152 event_time_i64,
1153 );
1154 let second_report = testing_utilities::create_mouse_input_report_relative(
1155 Position::zero(),
1156 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1159 event_time_i64,
1160 );
1161 let third_report = testing_utilities::create_mouse_input_report_relative(
1162 Position::zero(),
1163 None, None, vec![SECONDARY_BUTTON],
1166 event_time_i64,
1167 );
1168 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1169 Position::zero(),
1170 None, None, vec![],
1173 event_time_i64,
1174 );
1175 let descriptor = mouse_device_descriptor(DEVICE_ID);
1176
1177 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1178 let expected_events = vec![
1179 testing_utilities::create_mouse_event(
1180 MouseLocation::Relative(Default::default()),
1181 None, None, None, MousePhase::Down,
1185 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1186 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1187 event_time_u64,
1188 &descriptor,
1189 ),
1190 testing_utilities::create_mouse_event(
1191 MouseLocation::Relative(Default::default()),
1192 None, None, None, MousePhase::Down,
1196 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1197 SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1198 event_time_u64,
1199 &descriptor,
1200 ),
1201 testing_utilities::create_mouse_event(
1202 MouseLocation::Relative(Default::default()),
1203 None, None, None, MousePhase::Up,
1207 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1208 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1209 event_time_u64,
1210 &descriptor,
1211 ),
1212 testing_utilities::create_mouse_event(
1213 MouseLocation::Relative(Default::default()),
1214 None, None, None, MousePhase::Up,
1218 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1219 SortedVecSet::new(),
1220 event_time_u64,
1221 &descriptor,
1222 ),
1223 ];
1224
1225 assert_input_report_sequence_generates_events!(
1226 input_reports: input_reports,
1227 expected_events: expected_events,
1228 device_descriptor: descriptor,
1229 device_type: MouseBinding,
1230 );
1231 }
1232
1233 #[fuchsia::test]
1235 async fn scroll() {
1236 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1237 let first_report = testing_utilities::create_mouse_input_report_relative(
1238 Position::zero(),
1239 Some(1),
1240 None,
1241 vec![],
1242 event_time_i64,
1243 );
1244 let second_report = testing_utilities::create_mouse_input_report_relative(
1245 Position::zero(),
1246 None,
1247 Some(1),
1248 vec![],
1249 event_time_i64,
1250 );
1251
1252 let descriptor = mouse_device_descriptor(DEVICE_ID);
1253
1254 let input_reports = vec![first_report, second_report];
1255 let expected_events = vec![
1256 testing_utilities::create_mouse_event(
1257 MouseLocation::Relative(Default::default()),
1258 wheel_delta_ticks(1),
1259 None,
1260 Some(PrecisionScroll::No),
1261 MousePhase::Wheel,
1262 SortedVecSet::new(),
1263 SortedVecSet::new(),
1264 event_time_u64,
1265 &descriptor,
1266 ),
1267 testing_utilities::create_mouse_event(
1268 MouseLocation::Relative(Default::default()),
1269 None,
1270 wheel_delta_ticks(1),
1271 Some(PrecisionScroll::No),
1272 MousePhase::Wheel,
1273 SortedVecSet::new(),
1274 SortedVecSet::new(),
1275 event_time_u64,
1276 &descriptor,
1277 ),
1278 ];
1279
1280 assert_input_report_sequence_generates_events!(
1281 input_reports: input_reports,
1282 expected_events: expected_events,
1283 device_descriptor: descriptor,
1284 device_type: MouseBinding,
1285 );
1286 }
1287
1288 #[fuchsia::test]
1290 async fn down_scroll_up_scroll() {
1291 const PRIMARY_BUTTON: u8 = 1;
1292
1293 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1294 let first_report = testing_utilities::create_mouse_input_report_relative(
1295 Position::zero(),
1296 None, None, vec![PRIMARY_BUTTON],
1299 event_time_i64,
1300 );
1301 let second_report = testing_utilities::create_mouse_input_report_relative(
1302 Position::zero(),
1303 Some(1),
1304 None,
1305 vec![PRIMARY_BUTTON],
1306 event_time_i64,
1307 );
1308 let third_report = testing_utilities::create_mouse_input_report_relative(
1309 Position::zero(),
1310 None, None, vec![],
1313 event_time_i64,
1314 );
1315 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1316 Position::zero(),
1317 Some(1),
1318 None,
1319 vec![],
1320 event_time_i64,
1321 );
1322
1323 let descriptor = mouse_device_descriptor(DEVICE_ID);
1324
1325 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1326 let expected_events = vec![
1327 testing_utilities::create_mouse_event(
1328 MouseLocation::Relative(Default::default()),
1329 None, None, None, MousePhase::Down,
1333 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1334 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1335 event_time_u64,
1336 &descriptor,
1337 ),
1338 testing_utilities::create_mouse_event(
1339 MouseLocation::Relative(Default::default()),
1340 wheel_delta_ticks(1),
1341 None,
1342 Some(PrecisionScroll::No),
1343 MousePhase::Wheel,
1344 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1345 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1346 event_time_u64,
1347 &descriptor,
1348 ),
1349 testing_utilities::create_mouse_event(
1350 MouseLocation::Relative(Default::default()),
1351 None, None, None, MousePhase::Up,
1355 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1356 SortedVecSet::new(),
1357 event_time_u64,
1358 &descriptor,
1359 ),
1360 testing_utilities::create_mouse_event(
1361 MouseLocation::Relative(Default::default()),
1362 wheel_delta_ticks(1),
1363 None,
1364 Some(PrecisionScroll::No),
1365 MousePhase::Wheel,
1366 SortedVecSet::new(),
1367 SortedVecSet::new(),
1368 event_time_u64,
1369 &descriptor,
1370 ),
1371 ];
1372
1373 assert_input_report_sequence_generates_events!(
1374 input_reports: input_reports,
1375 expected_events: expected_events,
1376 device_descriptor: descriptor,
1377 device_type: MouseBinding,
1378 );
1379 }
1380
1381 #[fuchsia::test]
1383 async fn down_scroll_bundle_up_scroll_bundle() {
1384 const PRIMARY_BUTTON: u8 = 1;
1385
1386 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1387 let first_report = testing_utilities::create_mouse_input_report_relative(
1388 Position::zero(),
1389 Some(1),
1390 None,
1391 vec![PRIMARY_BUTTON],
1392 event_time_i64,
1393 );
1394 let second_report = testing_utilities::create_mouse_input_report_relative(
1395 Position::zero(),
1396 Some(1),
1397 None,
1398 vec![],
1399 event_time_i64,
1400 );
1401 let third_report = testing_utilities::create_mouse_input_report_relative(
1402 Position::zero(),
1403 Some(1),
1404 None,
1405 vec![],
1406 event_time_i64,
1407 );
1408
1409 let descriptor = mouse_device_descriptor(DEVICE_ID);
1410
1411 let input_reports = vec![first_report, second_report, third_report];
1412 let expected_events = vec![
1413 testing_utilities::create_mouse_event(
1414 MouseLocation::Relative(Default::default()),
1415 None, None, None, MousePhase::Down,
1419 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1420 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1421 event_time_u64,
1422 &descriptor,
1423 ),
1424 testing_utilities::create_mouse_event(
1425 MouseLocation::Relative(Default::default()),
1426 wheel_delta_ticks(1),
1427 None,
1428 Some(PrecisionScroll::No),
1429 MousePhase::Wheel,
1430 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1431 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1432 event_time_u64,
1433 &descriptor,
1434 ),
1435 testing_utilities::create_mouse_event(
1436 MouseLocation::Relative(Default::default()),
1437 wheel_delta_ticks(1),
1438 None,
1439 Some(PrecisionScroll::No),
1440 MousePhase::Wheel,
1441 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1442 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1443 event_time_u64,
1444 &descriptor,
1445 ),
1446 testing_utilities::create_mouse_event(
1447 MouseLocation::Relative(Default::default()),
1448 None, None, None, MousePhase::Up,
1452 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1453 SortedVecSet::new(),
1454 event_time_u64,
1455 &descriptor,
1456 ),
1457 testing_utilities::create_mouse_event(
1458 MouseLocation::Relative(Default::default()),
1459 wheel_delta_ticks(1),
1460 None,
1461 Some(PrecisionScroll::No),
1462 MousePhase::Wheel,
1463 SortedVecSet::new(),
1464 SortedVecSet::new(),
1465 event_time_u64,
1466 &descriptor,
1467 ),
1468 ];
1469
1470 assert_input_report_sequence_generates_events!(
1471 input_reports: input_reports,
1472 expected_events: expected_events,
1473 device_descriptor: descriptor,
1474 device_type: MouseBinding,
1475 );
1476 }
1477}