1use crate::input_device::{self, Handled, 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, crate::dispatcher::TaskHandle<()>), Error> {
291 let (device_descriptor, mut inspect_status) =
292 Self::bind_device(&device_proxy, device_id, device_node).await?;
293 inspect_status.health_node.set_ok();
294 let task = input_device::initialize_report_stream(
295 device_proxy,
296 input_device::InputDeviceDescriptor::Mouse(device_descriptor.clone()),
297 input_event_sender.clone(),
298 inspect_status,
299 metrics_logger,
300 _feature_flags,
301 Self::process_reports,
302 );
303
304 Ok((MouseBinding { event_sender: input_event_sender, device_descriptor }, task))
305 }
306
307 async fn bind_device(
319 device: &fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
320 device_id: u32,
321 device_node: fuchsia_inspect::Node,
322 ) -> Result<(MouseDeviceDescriptor, InputDeviceStatus), Error> {
323 let mut input_device_status = InputDeviceStatus::new(device_node);
324 let device_descriptor: fidl_next_fuchsia_input_report::DeviceDescriptor = match device
325 .get_descriptor()
326 .await
327 {
328 Ok(res) => res.descriptor,
329 Err(_) => {
330 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
331 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
332 }
333 };
334
335 let mouse_descriptor = device_descriptor.mouse.ok_or_else(|| {
336 input_device_status
337 .health_node
338 .set_unhealthy("DeviceDescriptor does not have a MouseDescriptor.");
339 format_err!("DeviceDescriptor does not have a MouseDescriptor")
340 })?;
341
342 let mouse_input_descriptor = mouse_descriptor.input.ok_or_else(|| {
343 input_device_status
344 .health_node
345 .set_unhealthy("MouseDescriptor does not have a MouseInputDescriptor.");
346 format_err!("MouseDescriptor does not have a MouseInputDescriptor")
347 })?;
348
349 let device_descriptor: MouseDeviceDescriptor = MouseDeviceDescriptor {
350 device_id,
351 absolute_x_range: mouse_input_descriptor
352 .position_x
353 .as_ref()
354 .map(|axis| utils::range_to_old(&axis.range)),
355 absolute_y_range: mouse_input_descriptor
356 .position_y
357 .as_ref()
358 .map(|axis| utils::range_to_old(&axis.range)),
359 wheel_v_range: utils::axis_to_old(mouse_input_descriptor.scroll_v.as_ref()),
360 wheel_h_range: utils::axis_to_old(mouse_input_descriptor.scroll_h.as_ref()),
361 buttons: mouse_input_descriptor.buttons,
362 };
363
364 Ok((device_descriptor, input_device_status))
365 }
366
367 fn process_reports(
389 reports: &[fidl_next_fuchsia_input_report::wire::InputReport<'_>],
390 mut previous_state: Option<input_device::PreviousDeviceState>,
391 device_descriptor: &input_device::InputDeviceDescriptor,
392 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
393 inspect_status: &InputDeviceStatus,
394 metrics_logger: &metrics::MetricsLogger,
395 _feature_flags: &input_device::InputPipelineFeatureFlags,
396 ) -> (Option<input_device::PreviousDeviceState>, Option<UnboundedReceiver<InputEvent>>) {
397 fuchsia_trace::duration!("input", "mouse-binding-process-reports", "num_reports" => reports.len());
398 for report in reports {
399 previous_state = Self::process_report(
400 report,
401 previous_state,
402 device_descriptor,
403 input_event_sender,
404 inspect_status,
405 metrics_logger,
406 );
407 }
408 (previous_state, None)
409 }
410
411 fn process_report(
412 report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
413 previous_state: Option<input_device::PreviousDeviceState>,
414 device_descriptor: &input_device::InputDeviceDescriptor,
415 input_event_sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
416 inspect_status: &InputDeviceStatus,
417 metrics_logger: &metrics::MetricsLogger,
418 ) -> Option<input_device::PreviousDeviceState> {
419 if let Some(trace_id) = report.trace_id() {
420 fuchsia_trace::flow_end!("input", "input_report", trace_id.0.into());
421 }
422
423 let wake_lease = utils::duplicate_wake_lease(report.wake_lease());
427
428 inspect_status.count_received_report_wire(report);
429 let mouse_report = match report.mouse() {
431 Some(mouse) => mouse,
432 None => {
433 inspect_status.count_filtered_report();
434 return previous_state;
435 }
436 };
437
438 let previous_buttons: SortedVecSet<MouseButton> = match previous_state {
439 Some(input_device::PreviousDeviceState::Mouse { pressed_buttons }) => pressed_buttons,
440 _ => SortedVecSet::new(),
441 };
442 let current_buttons: SortedVecSet<MouseButton> =
443 buttons_from_mouse_report_wire(mouse_report);
444
445 send_mouse_event(
451 MouseLocation::Relative(Default::default()),
452 None, None, MousePhase::Down,
455 current_buttons.difference(&previous_buttons).cloned().collect(),
456 current_buttons.clone(),
457 device_descriptor,
458 input_event_sender,
459 inspect_status,
460 metrics_logger,
461 wake_lease.as_ref().map(|lease| {
462 lease
463 .duplicate_handle(zx::Rights::SAME_RIGHTS)
464 .expect("failed to duplicate event pair")
465 }),
466 );
467
468 let location = if let (Some(position_x), Some(position_y)) =
470 (mouse_report.position_x(), mouse_report.position_y())
471 {
472 MouseLocation::Absolute(Position { x: position_x.0 as f32, y: position_y.0 as f32 })
473 } else {
474 let movement_x = mouse_report.movement_x().map(|x| x.0).unwrap_or_default() as f32;
475 let movement_y = mouse_report.movement_y().map(|y| y.0).unwrap_or_default() as f32;
476 MouseLocation::Relative(RelativeLocation {
477 counts: Position { x: movement_x, y: movement_y },
478 })
479 };
480
481 send_mouse_event(
485 location,
486 None, None, MousePhase::Move,
489 current_buttons.union(&previous_buttons).cloned().collect(),
490 current_buttons.union(&previous_buttons).cloned().collect(),
491 device_descriptor,
492 input_event_sender,
493 inspect_status,
494 metrics_logger,
495 wake_lease.as_ref().map(|lease| {
496 lease
497 .duplicate_handle(zx::Rights::SAME_RIGHTS)
498 .expect("failed to duplicate event pair")
499 }),
500 );
501
502 let wheel_delta_v = mouse_report
503 .scroll_v()
504 .map(|ticks| WheelDelta { ticks: ticks.0, physical_pixel: None });
505
506 let wheel_delta_h = mouse_report
507 .scroll_h()
508 .map(|ticks| WheelDelta { ticks: ticks.0, physical_pixel: None });
509
510 send_mouse_event(
512 MouseLocation::Relative(Default::default()),
513 wheel_delta_v,
514 wheel_delta_h,
515 MousePhase::Wheel,
516 current_buttons.union(&previous_buttons).cloned().collect(),
517 current_buttons.union(&previous_buttons).cloned().collect(),
518 device_descriptor,
519 input_event_sender,
520 inspect_status,
521 metrics_logger,
522 wake_lease.as_ref().map(|lease| {
523 lease
524 .duplicate_handle(zx::Rights::SAME_RIGHTS)
525 .expect("failed to duplicate event pair")
526 }),
527 );
528
529 send_mouse_event(
535 MouseLocation::Relative(Default::default()),
536 None, None, MousePhase::Up,
539 previous_buttons.difference(¤t_buttons).cloned().collect(),
540 current_buttons.clone(),
541 device_descriptor,
542 input_event_sender,
543 inspect_status,
544 metrics_logger,
545 wake_lease,
546 );
547
548 Some(input_device::PreviousDeviceState::Mouse { pressed_buttons: current_buttons })
549 }
550}
551
552fn send_mouse_event(
567 location: MouseLocation,
568 wheel_delta_v: Option<WheelDelta>,
569 wheel_delta_h: Option<WheelDelta>,
570 phase: MousePhase,
571 affected_buttons: SortedVecSet<MouseButton>,
572 pressed_buttons: SortedVecSet<MouseButton>,
573 device_descriptor: &input_device::InputDeviceDescriptor,
574 sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
575 inspect_status: &InputDeviceStatus,
576 metrics_logger: &metrics::MetricsLogger,
577 wake_lease: Option<zx::EventPair>,
578) {
579 if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
581 return;
582 }
583
584 if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
587 return;
588 }
589
590 if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
592 return;
593 }
594
595 let trace_id = fuchsia_trace::Id::new();
596 fuchsia_trace::duration!("input", "mouse-binding-send-event");
597 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
598
599 let event = input_device::InputEvent {
600 device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
601 location,
602 wheel_delta_v,
603 wheel_delta_h,
604 phase,
605 affected_buttons,
606 pressed_buttons,
607 match phase {
608 MousePhase::Wheel => Some(PrecisionScroll::No),
609 _ => None,
610 },
611 wake_lease,
612 )),
613 device_descriptor: device_descriptor.clone(),
614 event_time: zx::MonotonicInstant::get(),
615 handled: Handled::No,
616 trace_id: Some(trace_id),
617 };
618 let events = vec![event];
619 inspect_status.count_generated_events(&events);
620
621 if let Err(e) = sender.unbounded_send(events) {
622 metrics_logger.log_error(
623 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
624 std::format!("Failed to send MouseEvent with error: {:?}", e),
625 );
626 }
627}
628
629fn buttons_from_mouse_report_wire(
630 mouse_report: &fidl_next_fuchsia_input_report::wire::MouseInputReport<'_>,
631) -> SortedVecSet<MouseButton> {
632 mouse_report
633 .pressed_buttons()
634 .map(|buttons| SortedVecSet::from_iter(buttons.iter().copied()))
635 .unwrap_or_default()
636}
637
638#[cfg(test)]
639mod tests {
640 use super::*;
641 use crate::testing_utilities;
642 use futures::StreamExt;
643 use sorted_vec_map::SortedVecSet;
644
645 const DEVICE_ID: u32 = 1;
646
647 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
648 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
649 device_id,
650 absolute_x_range: None,
651 absolute_y_range: None,
652 wheel_v_range: Some(fidl_fuchsia_input::Axis {
653 range: fidl_fuchsia_input::Range { min: -1, max: 1 },
654 unit: fidl_fuchsia_input::Unit {
655 type_: fidl_fuchsia_input::UnitType::Other,
656 exponent: 1,
657 },
658 }),
659 wheel_h_range: Some(fidl_fuchsia_input::Axis {
660 range: fidl_fuchsia_input::Range { min: -1, max: 1 },
661 unit: fidl_fuchsia_input::Unit {
662 type_: fidl_fuchsia_input::UnitType::Other,
663 exponent: 1,
664 },
665 }),
666 buttons: None,
667 })
668 }
669
670 fn wheel_delta_ticks(ticks: i64) -> Option<WheelDelta> {
671 Some(WheelDelta { ticks, physical_pixel: None })
672 }
673
674 #[fuchsia::test]
676 async fn movement_without_button() {
677 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
678 let first_report = testing_utilities::create_mouse_input_report_relative(
679 Position { x: 10.0, y: 16.0 },
680 None, None, vec![],
683 event_time_i64,
684 );
685 let descriptor = mouse_device_descriptor(DEVICE_ID);
686
687 let input_reports = vec![first_report];
688 let expected_events = vec![testing_utilities::create_mouse_event(
689 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
690 None, None, None, MousePhase::Move,
694 SortedVecSet::new(),
695 SortedVecSet::new(),
696 event_time_u64,
697 &descriptor,
698 )];
699
700 assert_input_report_sequence_generates_events!(
701 input_reports: input_reports,
702 expected_events: expected_events,
703 device_descriptor: descriptor,
704 device_type: MouseBinding,
705 );
706 }
707
708 #[fuchsia::test]
710 async fn down_without_movement() {
711 let mouse_button: MouseButton = 3;
712 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
713 let first_report = testing_utilities::create_mouse_input_report_relative(
714 Position::zero(),
715 None, None, vec![mouse_button],
718 event_time_i64,
719 );
720 let descriptor = mouse_device_descriptor(DEVICE_ID);
721
722 let input_reports = vec![first_report];
723 let expected_events = vec![testing_utilities::create_mouse_event(
724 MouseLocation::Relative(Default::default()),
725 None, None, None, MousePhase::Down,
729 SortedVecSet::from(vec![mouse_button]),
730 SortedVecSet::from(vec![mouse_button]),
731 event_time_u64,
732 &descriptor,
733 )];
734
735 assert_input_report_sequence_generates_events!(
736 input_reports: input_reports,
737 expected_events: expected_events,
738 device_descriptor: descriptor,
739 device_type: MouseBinding,
740 );
741 }
742
743 #[fuchsia::test]
746 async fn down_with_movement() {
747 let mouse_button: MouseButton = 3;
748 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
749 let first_report = testing_utilities::create_mouse_input_report_relative(
750 Position { x: 10.0, y: 16.0 },
751 None, None, vec![mouse_button],
754 event_time_i64,
755 );
756 let descriptor = mouse_device_descriptor(DEVICE_ID);
757
758 let input_reports = vec![first_report];
759 let expected_events = vec![
760 testing_utilities::create_mouse_event(
761 MouseLocation::Relative(Default::default()),
762 None, None, None, MousePhase::Down,
766 SortedVecSet::from(vec![mouse_button]),
767 SortedVecSet::from(vec![mouse_button]),
768 event_time_u64,
769 &descriptor,
770 ),
771 testing_utilities::create_mouse_event(
772 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
773 None, None, None, MousePhase::Move,
777 SortedVecSet::from(vec![mouse_button]),
778 SortedVecSet::from(vec![mouse_button]),
779 event_time_u64,
780 &descriptor,
781 ),
782 ];
783
784 assert_input_report_sequence_generates_events!(
785 input_reports: input_reports,
786 expected_events: expected_events,
787 device_descriptor: descriptor,
788 device_type: MouseBinding,
789 );
790 }
791
792 #[fuchsia::test]
794 async fn down_up() {
795 let button = 1;
796 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
797 let first_report = testing_utilities::create_mouse_input_report_relative(
798 Position::zero(),
799 None, None, vec![button],
802 event_time_i64,
803 );
804 let second_report = testing_utilities::create_mouse_input_report_relative(
805 Position::zero(),
806 None, None, vec![],
809 event_time_i64,
810 );
811 let descriptor = mouse_device_descriptor(DEVICE_ID);
812
813 let input_reports = vec![first_report, second_report];
814 let expected_events = vec![
815 testing_utilities::create_mouse_event(
816 MouseLocation::Relative(Default::default()),
817 None, None, None, MousePhase::Down,
821 SortedVecSet::from(vec![button]),
822 SortedVecSet::from(vec![button]),
823 event_time_u64,
824 &descriptor,
825 ),
826 testing_utilities::create_mouse_event(
827 MouseLocation::Relative(Default::default()),
828 None, None, None, MousePhase::Up,
832 SortedVecSet::from(vec![button]),
833 SortedVecSet::new(),
834 event_time_u64,
835 &descriptor,
836 ),
837 ];
838
839 assert_input_report_sequence_generates_events!(
840 input_reports: input_reports,
841 expected_events: expected_events,
842 device_descriptor: descriptor,
843 device_type: MouseBinding,
844 );
845 }
846
847 #[fuchsia::test]
849 async fn down_up_with_movement() {
850 let button = 1;
851
852 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
853 let first_report = testing_utilities::create_mouse_input_report_relative(
854 Position::zero(),
855 None, None, vec![button],
858 event_time_i64,
859 );
860 let second_report = testing_utilities::create_mouse_input_report_relative(
861 Position { x: 10.0, y: 16.0 },
862 None, None, vec![],
865 event_time_i64,
866 );
867 let descriptor = mouse_device_descriptor(DEVICE_ID);
868
869 let input_reports = vec![first_report, second_report];
870 let expected_events = vec![
871 testing_utilities::create_mouse_event(
872 MouseLocation::Relative(Default::default()),
873 None, None, None, MousePhase::Down,
877 SortedVecSet::from(vec![button]),
878 SortedVecSet::from(vec![button]),
879 event_time_u64,
880 &descriptor,
881 ),
882 testing_utilities::create_mouse_event(
883 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
884 None, None, None, MousePhase::Move,
888 SortedVecSet::from(vec![button]),
889 SortedVecSet::from(vec![button]),
890 event_time_u64,
891 &descriptor,
892 ),
893 testing_utilities::create_mouse_event(
894 MouseLocation::Relative(Default::default()),
895 None, None, None, MousePhase::Up,
899 SortedVecSet::from(vec![button]),
900 SortedVecSet::new(),
901 event_time_u64,
902 &descriptor,
903 ),
904 ];
905
906 assert_input_report_sequence_generates_events!(
907 input_reports: input_reports,
908 expected_events: expected_events,
909 device_descriptor: descriptor,
910 device_type: MouseBinding,
911 );
912 }
913
914 #[fuchsia::test]
918 async fn down_move_up() {
919 let button = 1;
920
921 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
922 let first_report = testing_utilities::create_mouse_input_report_relative(
923 Position::zero(),
924 None, None, vec![button],
927 event_time_i64,
928 );
929 let second_report = testing_utilities::create_mouse_input_report_relative(
930 Position { x: 10.0, y: 16.0 },
931 None, None, vec![button],
934 event_time_i64,
935 );
936 let third_report = testing_utilities::create_mouse_input_report_relative(
937 Position::zero(),
938 None, None, vec![],
941 event_time_i64,
942 );
943 let descriptor = mouse_device_descriptor(DEVICE_ID);
944
945 let input_reports = vec![first_report, second_report, third_report];
946 let expected_events = vec![
947 testing_utilities::create_mouse_event(
948 MouseLocation::Relative(Default::default()),
949 None, None, None, MousePhase::Down,
953 SortedVecSet::from(vec![button]),
954 SortedVecSet::from(vec![button]),
955 event_time_u64,
956 &descriptor,
957 ),
958 testing_utilities::create_mouse_event(
959 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
960 None, None, None, MousePhase::Move,
964 SortedVecSet::from(vec![button]),
965 SortedVecSet::from(vec![button]),
966 event_time_u64,
967 &descriptor,
968 ),
969 testing_utilities::create_mouse_event(
970 MouseLocation::Relative(Default::default()),
971 None, None, None, MousePhase::Up,
975 SortedVecSet::from(vec![button]),
976 SortedVecSet::new(),
977 event_time_u64,
978 &descriptor,
979 ),
980 ];
981
982 assert_input_report_sequence_generates_events!(
983 input_reports: input_reports,
984 expected_events: expected_events,
985 device_descriptor: descriptor,
986 device_type: MouseBinding,
987 );
988 }
989
990 #[fuchsia::test(allow_stalls = false)]
992 async fn absolute_movement_to_origin() {
993 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
994 let descriptor = mouse_device_descriptor(DEVICE_ID);
995
996 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
997 Position::zero(),
998 None, None, vec![],
1001 event_time_i64,
1002 )];
1003 let expected_events = vec![testing_utilities::create_mouse_event(
1004 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1005 None, None, None, MousePhase::Move,
1009 SortedVecSet::new(),
1010 SortedVecSet::new(),
1011 event_time_u64,
1012 &descriptor,
1013 )];
1014
1015 assert_input_report_sequence_generates_events!(
1016 input_reports: input_reports,
1017 expected_events: expected_events,
1018 device_descriptor: descriptor,
1019 device_type: MouseBinding,
1020 );
1021 }
1022
1023 #[fuchsia::test(allow_stalls = false)]
1026 async fn report_with_both_movement_and_position() {
1027 let relative_movement = Position { x: 5.0, y: 5.0 };
1028 let absolute_position = Position { x: 10.0, y: 10.0 };
1029 let expected_location = MouseLocation::Absolute(absolute_position);
1030
1031 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1032 let descriptor = mouse_device_descriptor(DEVICE_ID);
1033
1034 let input_reports = vec![fidl_next_fuchsia_input_report::InputReport {
1035 event_time: Some(event_time_i64),
1036 keyboard: None,
1037 mouse: Some(fidl_next_fuchsia_input_report::MouseInputReport {
1038 movement_x: Some(relative_movement.x as i64),
1039 movement_y: Some(relative_movement.y as i64),
1040 position_x: Some(absolute_position.x as i64),
1041 position_y: Some(absolute_position.y as i64),
1042 scroll_h: None,
1043 scroll_v: None,
1044 pressed_buttons: None,
1045 ..Default::default()
1046 }),
1047 touch: None,
1048 sensor: None,
1049 consumer_control: None,
1050 trace_id: None,
1051 ..Default::default()
1052 }];
1053 let expected_events = vec![testing_utilities::create_mouse_event(
1054 expected_location,
1055 None, None, None, MousePhase::Move,
1059 SortedVecSet::new(),
1060 SortedVecSet::new(),
1061 event_time_u64,
1062 &descriptor,
1063 )];
1064
1065 assert_input_report_sequence_generates_events!(
1066 input_reports: input_reports,
1067 expected_events: expected_events,
1068 device_descriptor: descriptor,
1069 device_type: MouseBinding,
1070 );
1071 }
1072
1073 #[fuchsia::test]
1076 async fn down_down() {
1077 const PRIMARY_BUTTON: u8 = 1;
1078 const SECONDARY_BUTTON: u8 = 2;
1079
1080 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1081 let first_report = testing_utilities::create_mouse_input_report_relative(
1082 Position::zero(),
1083 None, None, vec![PRIMARY_BUTTON],
1086 event_time_i64,
1087 );
1088 let second_report = testing_utilities::create_mouse_input_report_relative(
1089 Position::zero(),
1090 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1093 event_time_i64,
1094 );
1095 let descriptor = mouse_device_descriptor(DEVICE_ID);
1096
1097 let input_reports = vec![first_report, second_report];
1098 let expected_events = vec![
1099 testing_utilities::create_mouse_event(
1100 MouseLocation::Relative(Default::default()),
1101 None, None, None, MousePhase::Down,
1105 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1106 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1107 event_time_u64,
1108 &descriptor,
1109 ),
1110 testing_utilities::create_mouse_event(
1111 MouseLocation::Relative(Default::default()),
1112 None, None, None, MousePhase::Down,
1116 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1117 SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1118 event_time_u64,
1119 &descriptor,
1120 ),
1121 ];
1122
1123 assert_input_report_sequence_generates_events!(
1124 input_reports: input_reports,
1125 expected_events: expected_events,
1126 device_descriptor: descriptor,
1127 device_type: MouseBinding,
1128 );
1129 }
1130
1131 #[fuchsia::test]
1141 async fn down_down_up_up() {
1142 const PRIMARY_BUTTON: u8 = 1;
1143 const SECONDARY_BUTTON: u8 = 2;
1144
1145 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1146 let first_report = testing_utilities::create_mouse_input_report_relative(
1147 Position::zero(),
1148 None, None, vec![PRIMARY_BUTTON],
1151 event_time_i64,
1152 );
1153 let second_report = testing_utilities::create_mouse_input_report_relative(
1154 Position::zero(),
1155 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1158 event_time_i64,
1159 );
1160 let third_report = testing_utilities::create_mouse_input_report_relative(
1161 Position::zero(),
1162 None, None, vec![SECONDARY_BUTTON],
1165 event_time_i64,
1166 );
1167 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1168 Position::zero(),
1169 None, None, vec![],
1172 event_time_i64,
1173 );
1174 let descriptor = mouse_device_descriptor(DEVICE_ID);
1175
1176 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1177 let expected_events = vec![
1178 testing_utilities::create_mouse_event(
1179 MouseLocation::Relative(Default::default()),
1180 None, None, None, MousePhase::Down,
1184 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1185 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1186 event_time_u64,
1187 &descriptor,
1188 ),
1189 testing_utilities::create_mouse_event(
1190 MouseLocation::Relative(Default::default()),
1191 None, None, None, MousePhase::Down,
1195 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1196 SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1197 event_time_u64,
1198 &descriptor,
1199 ),
1200 testing_utilities::create_mouse_event(
1201 MouseLocation::Relative(Default::default()),
1202 None, None, None, MousePhase::Up,
1206 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1207 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1208 event_time_u64,
1209 &descriptor,
1210 ),
1211 testing_utilities::create_mouse_event(
1212 MouseLocation::Relative(Default::default()),
1213 None, None, None, MousePhase::Up,
1217 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1218 SortedVecSet::new(),
1219 event_time_u64,
1220 &descriptor,
1221 ),
1222 ];
1223
1224 assert_input_report_sequence_generates_events!(
1225 input_reports: input_reports,
1226 expected_events: expected_events,
1227 device_descriptor: descriptor,
1228 device_type: MouseBinding,
1229 );
1230 }
1231
1232 #[fuchsia::test]
1234 async fn scroll() {
1235 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1236 let first_report = testing_utilities::create_mouse_input_report_relative(
1237 Position::zero(),
1238 Some(1),
1239 None,
1240 vec![],
1241 event_time_i64,
1242 );
1243 let second_report = testing_utilities::create_mouse_input_report_relative(
1244 Position::zero(),
1245 None,
1246 Some(1),
1247 vec![],
1248 event_time_i64,
1249 );
1250
1251 let descriptor = mouse_device_descriptor(DEVICE_ID);
1252
1253 let input_reports = vec![first_report, second_report];
1254 let expected_events = vec![
1255 testing_utilities::create_mouse_event(
1256 MouseLocation::Relative(Default::default()),
1257 wheel_delta_ticks(1),
1258 None,
1259 Some(PrecisionScroll::No),
1260 MousePhase::Wheel,
1261 SortedVecSet::new(),
1262 SortedVecSet::new(),
1263 event_time_u64,
1264 &descriptor,
1265 ),
1266 testing_utilities::create_mouse_event(
1267 MouseLocation::Relative(Default::default()),
1268 None,
1269 wheel_delta_ticks(1),
1270 Some(PrecisionScroll::No),
1271 MousePhase::Wheel,
1272 SortedVecSet::new(),
1273 SortedVecSet::new(),
1274 event_time_u64,
1275 &descriptor,
1276 ),
1277 ];
1278
1279 assert_input_report_sequence_generates_events!(
1280 input_reports: input_reports,
1281 expected_events: expected_events,
1282 device_descriptor: descriptor,
1283 device_type: MouseBinding,
1284 );
1285 }
1286
1287 #[fuchsia::test]
1289 async fn down_scroll_up_scroll() {
1290 const PRIMARY_BUTTON: u8 = 1;
1291
1292 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1293 let first_report = testing_utilities::create_mouse_input_report_relative(
1294 Position::zero(),
1295 None, None, vec![PRIMARY_BUTTON],
1298 event_time_i64,
1299 );
1300 let second_report = testing_utilities::create_mouse_input_report_relative(
1301 Position::zero(),
1302 Some(1),
1303 None,
1304 vec![PRIMARY_BUTTON],
1305 event_time_i64,
1306 );
1307 let third_report = testing_utilities::create_mouse_input_report_relative(
1308 Position::zero(),
1309 None, None, vec![],
1312 event_time_i64,
1313 );
1314 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1315 Position::zero(),
1316 Some(1),
1317 None,
1318 vec![],
1319 event_time_i64,
1320 );
1321
1322 let descriptor = mouse_device_descriptor(DEVICE_ID);
1323
1324 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1325 let expected_events = vec![
1326 testing_utilities::create_mouse_event(
1327 MouseLocation::Relative(Default::default()),
1328 None, None, None, MousePhase::Down,
1332 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1333 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1334 event_time_u64,
1335 &descriptor,
1336 ),
1337 testing_utilities::create_mouse_event(
1338 MouseLocation::Relative(Default::default()),
1339 wheel_delta_ticks(1),
1340 None,
1341 Some(PrecisionScroll::No),
1342 MousePhase::Wheel,
1343 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1344 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1345 event_time_u64,
1346 &descriptor,
1347 ),
1348 testing_utilities::create_mouse_event(
1349 MouseLocation::Relative(Default::default()),
1350 None, None, None, MousePhase::Up,
1354 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1355 SortedVecSet::new(),
1356 event_time_u64,
1357 &descriptor,
1358 ),
1359 testing_utilities::create_mouse_event(
1360 MouseLocation::Relative(Default::default()),
1361 wheel_delta_ticks(1),
1362 None,
1363 Some(PrecisionScroll::No),
1364 MousePhase::Wheel,
1365 SortedVecSet::new(),
1366 SortedVecSet::new(),
1367 event_time_u64,
1368 &descriptor,
1369 ),
1370 ];
1371
1372 assert_input_report_sequence_generates_events!(
1373 input_reports: input_reports,
1374 expected_events: expected_events,
1375 device_descriptor: descriptor,
1376 device_type: MouseBinding,
1377 );
1378 }
1379
1380 #[fuchsia::test]
1382 async fn down_scroll_bundle_up_scroll_bundle() {
1383 const PRIMARY_BUTTON: u8 = 1;
1384
1385 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1386 let first_report = testing_utilities::create_mouse_input_report_relative(
1387 Position::zero(),
1388 Some(1),
1389 None,
1390 vec![PRIMARY_BUTTON],
1391 event_time_i64,
1392 );
1393 let second_report = testing_utilities::create_mouse_input_report_relative(
1394 Position::zero(),
1395 Some(1),
1396 None,
1397 vec![],
1398 event_time_i64,
1399 );
1400 let third_report = testing_utilities::create_mouse_input_report_relative(
1401 Position::zero(),
1402 Some(1),
1403 None,
1404 vec![],
1405 event_time_i64,
1406 );
1407
1408 let descriptor = mouse_device_descriptor(DEVICE_ID);
1409
1410 let input_reports = vec![first_report, second_report, third_report];
1411 let expected_events = vec![
1412 testing_utilities::create_mouse_event(
1413 MouseLocation::Relative(Default::default()),
1414 None, None, None, MousePhase::Down,
1418 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1419 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1420 event_time_u64,
1421 &descriptor,
1422 ),
1423 testing_utilities::create_mouse_event(
1424 MouseLocation::Relative(Default::default()),
1425 wheel_delta_ticks(1),
1426 None,
1427 Some(PrecisionScroll::No),
1428 MousePhase::Wheel,
1429 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1430 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1431 event_time_u64,
1432 &descriptor,
1433 ),
1434 testing_utilities::create_mouse_event(
1435 MouseLocation::Relative(Default::default()),
1436 wheel_delta_ticks(1),
1437 None,
1438 Some(PrecisionScroll::No),
1439 MousePhase::Wheel,
1440 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1441 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1442 event_time_u64,
1443 &descriptor,
1444 ),
1445 testing_utilities::create_mouse_event(
1446 MouseLocation::Relative(Default::default()),
1447 None, None, None, MousePhase::Up,
1451 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1452 SortedVecSet::new(),
1453 event_time_u64,
1454 &descriptor,
1455 ),
1456 testing_utilities::create_mouse_event(
1457 MouseLocation::Relative(Default::default()),
1458 wheel_delta_ticks(1),
1459 None,
1460 Some(PrecisionScroll::No),
1461 MousePhase::Wheel,
1462 SortedVecSet::new(),
1463 SortedVecSet::new(),
1464 event_time_u64,
1465 &descriptor,
1466 ),
1467 ];
1468
1469 assert_input_report_sequence_generates_events!(
1470 input_reports: input_reports,
1471 expected_events: expected_events,
1472 device_descriptor: descriptor,
1473 device_type: MouseBinding,
1474 );
1475 }
1476}