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 fidl_fuchsia_input_report as fidl_input_report;
11use fidl_next_fuchsia_input_report::InputReport;
12use fuchsia_inspect::ArrayProperty;
13use fuchsia_inspect::health::Reporter;
14use fuchsia_sync::Mutex;
15use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
16use metrics_registry::*;
17use sorted_vec_map::SortedVecSet;
18use zx;
19
20pub type MouseButton = u8;
21
22#[derive(Copy, Clone, Debug, PartialEq)]
24pub enum PrecisionScroll {
25 Yes,
27 No,
29}
30
31#[derive(Copy, Clone, Debug, PartialEq)]
33pub enum MouseLocation {
34 Relative(RelativeLocation),
36
37 Absolute(Position),
39}
40
41#[derive(Copy, Clone, Debug, PartialEq)]
42pub enum MousePhase {
43 Down, Move, Up, Wheel, }
48
49#[derive(Copy, Clone, Debug, PartialEq)]
51pub struct RelativeLocation {
52 pub counts: Position,
54}
55
56impl Default for RelativeLocation {
57 fn default() -> Self {
58 RelativeLocation { counts: Position::zero() }
59 }
60}
61
62#[derive(Clone, Debug, PartialEq)]
65pub struct WheelDelta {
66 pub ticks: i64,
67 pub physical_pixel: Option<f32>,
68}
69
70#[derive(Debug)]
92pub struct MouseEvent {
93 pub location: MouseLocation,
95
96 pub wheel_delta_v: Option<WheelDelta>,
98
99 pub wheel_delta_h: Option<WheelDelta>,
101
102 pub is_precision_scroll: Option<PrecisionScroll>,
104
105 pub phase: MousePhase,
107
108 pub affected_buttons: SortedVecSet<MouseButton>,
110
111 pub pressed_buttons: SortedVecSet<MouseButton>,
113
114 pub wake_lease: Mutex<Option<zx::EventPair>>,
116}
117
118impl Clone for MouseEvent {
119 fn clone(&self) -> Self {
120 log::debug!("MouseEvent cloned without wake lease.");
121 Self {
122 location: self.location,
123 wheel_delta_v: self.wheel_delta_v.clone(),
124 wheel_delta_h: self.wheel_delta_h.clone(),
125 is_precision_scroll: self.is_precision_scroll,
126 phase: self.phase,
127 affected_buttons: self.affected_buttons.clone(),
128 pressed_buttons: self.pressed_buttons.clone(),
129 wake_lease: None.into(),
130 }
131 }
132}
133
134impl PartialEq for MouseEvent {
135 fn eq(&self, other: &Self) -> bool {
136 self.location == other.location
137 && self.wheel_delta_v == other.wheel_delta_v
138 && self.wheel_delta_h == other.wheel_delta_h
139 && self.is_precision_scroll == other.is_precision_scroll
140 && self.phase == other.phase
141 && self.affected_buttons == other.affected_buttons
142 && self.pressed_buttons == other.pressed_buttons
143 }
144}
145
146impl MouseEvent {
147 pub fn new(
155 location: MouseLocation,
156 wheel_delta_v: Option<WheelDelta>,
157 wheel_delta_h: Option<WheelDelta>,
158 phase: MousePhase,
159 affected_buttons: SortedVecSet<MouseButton>,
160 pressed_buttons: SortedVecSet<MouseButton>,
161 is_precision_scroll: Option<PrecisionScroll>,
162 wake_lease: Option<zx::EventPair>,
163 ) -> MouseEvent {
164 MouseEvent {
165 location,
166 wheel_delta_v,
167 wheel_delta_h,
168 phase,
169 affected_buttons,
170 pressed_buttons,
171 is_precision_scroll,
172 wake_lease: Mutex::new(wake_lease),
173 }
174 }
175
176 pub fn clone_with_wake_lease(&self) -> Self {
177 log::debug!("MouseEvent cloned with wake lease: {:?}", self.wake_lease);
178 Self {
179 location: self.location,
180 wheel_delta_v: self.wheel_delta_v.clone(),
181 wheel_delta_h: self.wheel_delta_h.clone(),
182 is_precision_scroll: self.is_precision_scroll,
183 phase: self.phase,
184 affected_buttons: self.affected_buttons.clone(),
185 pressed_buttons: self.pressed_buttons.clone(),
186 wake_lease: Mutex::new(self.wake_lease.lock().as_ref().map(|lease| {
187 lease
188 .duplicate_handle(zx::Rights::SAME_RIGHTS)
189 .expect("failed to duplicate event pair")
190 })),
191 }
192 }
193
194 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
195 match self.location {
196 MouseLocation::Relative(pos) => {
197 node.record_child("location_relative", move |location_node| {
198 location_node.record_double("x", f64::from(pos.counts.x));
199 location_node.record_double("y", f64::from(pos.counts.y));
200 })
201 }
202 MouseLocation::Absolute(pos) => {
203 node.record_child("location_absolute", move |location_node| {
204 location_node.record_double("x", f64::from(pos.x));
205 location_node.record_double("y", f64::from(pos.y));
206 })
207 }
208 };
209
210 if let Some(wheel_delta_v) = &self.wheel_delta_v {
211 node.record_child("wheel_delta_v", move |wheel_delta_v_node| {
212 wheel_delta_v_node.record_int("ticks", wheel_delta_v.ticks);
213 if let Some(physical_pixel) = wheel_delta_v.physical_pixel {
214 wheel_delta_v_node.record_double("physical_pixel", f64::from(physical_pixel));
215 }
216 });
217 }
218
219 if let Some(wheel_delta_h) = &self.wheel_delta_h {
220 node.record_child("wheel_delta_h", move |wheel_delta_h_node| {
221 wheel_delta_h_node.record_int("ticks", wheel_delta_h.ticks);
222 if let Some(physical_pixel) = wheel_delta_h.physical_pixel {
223 wheel_delta_h_node.record_double("physical_pixel", f64::from(physical_pixel));
224 }
225 });
226 }
227
228 if let Some(is_precision_scroll) = self.is_precision_scroll {
229 match is_precision_scroll {
230 PrecisionScroll::Yes => node.record_string("is_precision_scroll", "yes"),
231 PrecisionScroll::No => node.record_string("is_precision_scroll", "no"),
232 }
233 }
234
235 match self.phase {
236 MousePhase::Down => node.record_string("phase", "down"),
237 MousePhase::Move => node.record_string("phase", "move"),
238 MousePhase::Up => node.record_string("phase", "up"),
239 MousePhase::Wheel => node.record_string("phase", "wheel"),
240 }
241
242 let affected_buttons_node =
243 node.create_uint_array("affected_buttons", self.affected_buttons.len());
244 self.affected_buttons.iter().enumerate().for_each(|(i, button)| {
245 affected_buttons_node.set(i, *button);
246 });
247 node.record(affected_buttons_node);
248
249 let pressed_buttons_node =
250 node.create_uint_array("pressed_buttons", self.pressed_buttons.len());
251 self.pressed_buttons.iter().enumerate().for_each(|(i, button)| {
252 pressed_buttons_node.set(i, *button);
253 });
254 node.record(pressed_buttons_node);
255 }
256}
257
258pub struct MouseBinding {
264 event_sender: UnboundedSender<Vec<InputEvent>>,
266
267 device_descriptor: MouseDeviceDescriptor,
269}
270
271#[derive(Clone, Debug, Eq, PartialEq)]
272pub struct MouseDeviceDescriptor {
273 pub device_id: u32,
275
276 pub absolute_x_range: Option<fidl_input_report::Range>,
278
279 pub absolute_y_range: Option<fidl_input_report::Range>,
281
282 pub wheel_v_range: Option<fidl_input_report::Axis>,
284
285 pub wheel_h_range: Option<fidl_input_report::Axis>,
287
288 pub buttons: Option<Vec<MouseButton>>,
290}
291
292#[async_trait]
293impl input_device::InputDeviceBinding for MouseBinding {
294 fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>> {
295 self.event_sender.clone()
296 }
297
298 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
299 input_device::InputDeviceDescriptor::Mouse(self.device_descriptor.clone())
300 }
301}
302
303impl MouseBinding {
304 pub async fn new(
319 device_proxy: 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 _feature_flags: input_device::InputPipelineFeatureFlags,
324 metrics_logger: metrics::MetricsLogger,
325 ) -> Result<Self, Error> {
326 let (device_binding, mut inspect_status) =
327 Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
328 inspect_status.health_node.set_ok();
329 input_device::initialize_report_stream(
330 device_proxy,
331 device_binding.get_device_descriptor(),
332 device_binding.input_event_sender(),
333 inspect_status,
334 metrics_logger,
335 _feature_flags,
336 Self::process_reports,
337 );
338
339 Ok(device_binding)
340 }
341
342 async fn bind_device(
354 device: &fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
355 device_id: u32,
356 input_event_sender: UnboundedSender<Vec<InputEvent>>,
357 device_node: fuchsia_inspect::Node,
358 ) -> Result<(Self, InputDeviceStatus), Error> {
359 let mut input_device_status = InputDeviceStatus::new(device_node);
360 let device_descriptor: fidl_next_fuchsia_input_report::DeviceDescriptor = match device
361 .get_descriptor()
362 .await
363 {
364 Ok(res) => res.descriptor,
365 Err(_) => {
366 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
367 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
368 }
369 };
370
371 let mouse_descriptor = device_descriptor.mouse.ok_or_else(|| {
372 input_device_status
373 .health_node
374 .set_unhealthy("DeviceDescriptor does not have a MouseDescriptor.");
375 format_err!("DeviceDescriptor does not have a MouseDescriptor")
376 })?;
377
378 let mouse_input_descriptor = mouse_descriptor.input.ok_or_else(|| {
379 input_device_status
380 .health_node
381 .set_unhealthy("MouseDescriptor does not have a MouseInputDescriptor.");
382 format_err!("MouseDescriptor does not have a MouseInputDescriptor")
383 })?;
384
385 let device_descriptor: MouseDeviceDescriptor = MouseDeviceDescriptor {
386 device_id,
387 absolute_x_range: mouse_input_descriptor
388 .position_x
389 .as_ref()
390 .map(|axis| utils::range_to_old(&axis.range)),
391 absolute_y_range: mouse_input_descriptor
392 .position_y
393 .as_ref()
394 .map(|axis| utils::range_to_old(&axis.range)),
395 wheel_v_range: utils::axis_to_old(mouse_input_descriptor.scroll_v.as_ref()),
396 wheel_h_range: utils::axis_to_old(mouse_input_descriptor.scroll_h.as_ref()),
397 buttons: mouse_input_descriptor.buttons,
398 };
399
400 Ok((Self { event_sender: input_event_sender, device_descriptor }, input_device_status))
401 }
402
403 fn process_reports(
425 reports: &[fidl_next_fuchsia_input_report::wire::InputReport<'_>],
426 mut previous_report: Option<InputReport>,
427 device_descriptor: &input_device::InputDeviceDescriptor,
428 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
429 inspect_status: &InputDeviceStatus,
430 metrics_logger: &metrics::MetricsLogger,
431 _feature_flags: &input_device::InputPipelineFeatureFlags,
432 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
433 fuchsia_trace::duration!("input", "mouse-binding-process-reports", "num_reports" => reports.len());
434 for report in reports {
435 previous_report = Self::process_report(
436 report,
437 previous_report,
438 device_descriptor,
439 input_event_sender,
440 inspect_status,
441 metrics_logger,
442 );
443 }
444 (previous_report, None)
445 }
446
447 fn process_report(
448 report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
449 previous_report: Option<InputReport>,
450 device_descriptor: &input_device::InputDeviceDescriptor,
451 input_event_sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
452 inspect_status: &InputDeviceStatus,
453 metrics_logger: &metrics::MetricsLogger,
454 ) -> Option<InputReport> {
455 if let Some(trace_id) = report.trace_id() {
456 fuchsia_trace::flow_end!("input", "input_report", trace_id.0.into());
457 }
458
459 let wake_lease = utils::duplicate_wake_lease(report.wake_lease());
463
464 inspect_status.count_received_report_wire(report);
465 let mouse_report = match report.mouse() {
467 Some(mouse) => mouse,
468 None => {
469 inspect_status.count_filtered_report();
470 return previous_report;
471 }
472 };
473
474 let previous_buttons: SortedVecSet<MouseButton> =
475 buttons_from_optional_report(&previous_report.as_ref());
476 let current_buttons: SortedVecSet<MouseButton> =
477 buttons_from_mouse_report_wire(mouse_report);
478
479 send_mouse_event(
485 MouseLocation::Relative(Default::default()),
486 None, None, MousePhase::Down,
489 current_buttons.difference(&previous_buttons).cloned().collect(),
490 current_buttons.clone(),
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 location = if let (Some(position_x), Some(position_y)) =
504 (mouse_report.position_x(), mouse_report.position_y())
505 {
506 MouseLocation::Absolute(Position { x: position_x.0 as f32, y: position_y.0 as f32 })
507 } else {
508 let movement_x = mouse_report.movement_x().map(|x| x.0).unwrap_or_default() as f32;
509 let movement_y = mouse_report.movement_y().map(|y| y.0).unwrap_or_default() as f32;
510 MouseLocation::Relative(RelativeLocation {
511 counts: Position { x: movement_x, y: movement_y },
512 })
513 };
514
515 send_mouse_event(
519 location,
520 None, None, MousePhase::Move,
523 current_buttons.union(&previous_buttons).cloned().collect(),
524 current_buttons.union(&previous_buttons).cloned().collect(),
525 device_descriptor,
526 input_event_sender,
527 inspect_status,
528 metrics_logger,
529 wake_lease.as_ref().map(|lease| {
530 lease
531 .duplicate_handle(zx::Rights::SAME_RIGHTS)
532 .expect("failed to duplicate event pair")
533 }),
534 );
535
536 let wheel_delta_v = mouse_report
537 .scroll_v()
538 .map(|ticks| WheelDelta { ticks: ticks.0, physical_pixel: None });
539
540 let wheel_delta_h = mouse_report
541 .scroll_h()
542 .map(|ticks| WheelDelta { ticks: ticks.0, physical_pixel: None });
543
544 send_mouse_event(
546 MouseLocation::Relative(Default::default()),
547 wheel_delta_v,
548 wheel_delta_h,
549 MousePhase::Wheel,
550 current_buttons.union(&previous_buttons).cloned().collect(),
551 current_buttons.union(&previous_buttons).cloned().collect(),
552 device_descriptor,
553 input_event_sender,
554 inspect_status,
555 metrics_logger,
556 wake_lease.as_ref().map(|lease| {
557 lease
558 .duplicate_handle(zx::Rights::SAME_RIGHTS)
559 .expect("failed to duplicate event pair")
560 }),
561 );
562
563 send_mouse_event(
569 MouseLocation::Relative(Default::default()),
570 None, None, MousePhase::Up,
573 previous_buttons.difference(¤t_buttons).cloned().collect(),
574 current_buttons.clone(),
575 device_descriptor,
576 input_event_sender,
577 inspect_status,
578 metrics_logger,
579 wake_lease,
580 );
581
582 let natural_report = utils::input_report_to_natural(report);
583 Some(natural_report)
584 }
585}
586
587fn send_mouse_event(
602 location: MouseLocation,
603 wheel_delta_v: Option<WheelDelta>,
604 wheel_delta_h: Option<WheelDelta>,
605 phase: MousePhase,
606 affected_buttons: SortedVecSet<MouseButton>,
607 pressed_buttons: SortedVecSet<MouseButton>,
608 device_descriptor: &input_device::InputDeviceDescriptor,
609 sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
610 inspect_status: &InputDeviceStatus,
611 metrics_logger: &metrics::MetricsLogger,
612 wake_lease: Option<zx::EventPair>,
613) {
614 if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
616 return;
617 }
618
619 if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
622 return;
623 }
624
625 if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
627 return;
628 }
629
630 let trace_id = fuchsia_trace::Id::new();
631 fuchsia_trace::duration!("input", "mouse-binding-send-event");
632 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
633
634 let event = input_device::InputEvent {
635 device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
636 location,
637 wheel_delta_v,
638 wheel_delta_h,
639 phase,
640 affected_buttons,
641 pressed_buttons,
642 match phase {
643 MousePhase::Wheel => Some(PrecisionScroll::No),
644 _ => None,
645 },
646 wake_lease,
647 )),
648 device_descriptor: device_descriptor.clone(),
649 event_time: zx::MonotonicInstant::get(),
650 handled: Handled::No,
651 trace_id: Some(trace_id),
652 };
653 let events = vec![event];
654 inspect_status.count_generated_events(&events);
655
656 if let Err(e) = sender.unbounded_send(events) {
657 metrics_logger.log_error(
658 InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
659 std::format!("Failed to send MouseEvent with error: {:?}", e),
660 );
661 }
662}
663
664fn buttons_from_mouse_report_wire(
665 mouse_report: &fidl_next_fuchsia_input_report::wire::MouseInputReport<'_>,
666) -> SortedVecSet<MouseButton> {
667 mouse_report
668 .pressed_buttons()
669 .map(|buttons| SortedVecSet::from_iter(buttons.iter().copied()))
670 .unwrap_or_default()
671}
672
673fn buttons_from_optional_report(
678 input_report: &Option<&fidl_next_fuchsia_input_report::InputReport>,
679) -> SortedVecSet<MouseButton> {
680 input_report
681 .as_ref()
682 .and_then(|unwrapped_report| unwrapped_report.mouse.as_ref())
683 .and_then(|mouse_report| match &mouse_report.pressed_buttons {
684 Some(buttons) => Some(SortedVecSet::from(buttons.clone())),
685 None => None,
686 })
687 .unwrap_or_default()
688}
689
690#[cfg(test)]
691mod tests {
692 use super::*;
693 use crate::testing_utilities;
694 use fuchsia_async as fasync;
695 use futures::StreamExt;
696 use sorted_vec_map::SortedVecSet;
697
698 const DEVICE_ID: u32 = 1;
699
700 fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
701 input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
702 device_id,
703 absolute_x_range: None,
704 absolute_y_range: None,
705 wheel_v_range: Some(fidl_fuchsia_input_report::Axis {
706 range: fidl_input_report::Range { min: -1, max: 1 },
707 unit: fidl_input_report::Unit {
708 type_: fidl_input_report::UnitType::Other,
709 exponent: 1,
710 },
711 }),
712 wheel_h_range: Some(fidl_fuchsia_input_report::Axis {
713 range: fidl_input_report::Range { min: -1, max: 1 },
714 unit: fidl_input_report::Unit {
715 type_: fidl_input_report::UnitType::Other,
716 exponent: 1,
717 },
718 }),
719 buttons: None,
720 })
721 }
722
723 fn wheel_delta_ticks(ticks: i64) -> Option<WheelDelta> {
724 Some(WheelDelta { ticks, physical_pixel: None })
725 }
726
727 #[fasync::run_singlethreaded(test)]
729 async fn movement_without_button() {
730 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
731 let first_report = testing_utilities::create_mouse_input_report_relative(
732 Position { x: 10.0, y: 16.0 },
733 None, None, vec![],
736 event_time_i64,
737 );
738 let descriptor = mouse_device_descriptor(DEVICE_ID);
739
740 let input_reports = vec![first_report];
741 let expected_events = vec![testing_utilities::create_mouse_event(
742 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
743 None, None, None, MousePhase::Move,
747 SortedVecSet::new(),
748 SortedVecSet::new(),
749 event_time_u64,
750 &descriptor,
751 )];
752
753 assert_input_report_sequence_generates_events!(
754 input_reports: input_reports,
755 expected_events: expected_events,
756 device_descriptor: descriptor,
757 device_type: MouseBinding,
758 );
759 }
760
761 #[fasync::run_singlethreaded(test)]
763 async fn down_without_movement() {
764 let mouse_button: MouseButton = 3;
765 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
766 let first_report = testing_utilities::create_mouse_input_report_relative(
767 Position::zero(),
768 None, None, vec![mouse_button],
771 event_time_i64,
772 );
773 let descriptor = mouse_device_descriptor(DEVICE_ID);
774
775 let input_reports = vec![first_report];
776 let expected_events = vec![testing_utilities::create_mouse_event(
777 MouseLocation::Relative(Default::default()),
778 None, None, None, MousePhase::Down,
782 SortedVecSet::from(vec![mouse_button]),
783 SortedVecSet::from(vec![mouse_button]),
784 event_time_u64,
785 &descriptor,
786 )];
787
788 assert_input_report_sequence_generates_events!(
789 input_reports: input_reports,
790 expected_events: expected_events,
791 device_descriptor: descriptor,
792 device_type: MouseBinding,
793 );
794 }
795
796 #[fasync::run_singlethreaded(test)]
799 async fn down_with_movement() {
800 let mouse_button: MouseButton = 3;
801 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
802 let first_report = testing_utilities::create_mouse_input_report_relative(
803 Position { x: 10.0, y: 16.0 },
804 None, None, vec![mouse_button],
807 event_time_i64,
808 );
809 let descriptor = mouse_device_descriptor(DEVICE_ID);
810
811 let input_reports = vec![first_report];
812 let expected_events = vec![
813 testing_utilities::create_mouse_event(
814 MouseLocation::Relative(Default::default()),
815 None, None, None, MousePhase::Down,
819 SortedVecSet::from(vec![mouse_button]),
820 SortedVecSet::from(vec![mouse_button]),
821 event_time_u64,
822 &descriptor,
823 ),
824 testing_utilities::create_mouse_event(
825 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
826 None, None, None, MousePhase::Move,
830 SortedVecSet::from(vec![mouse_button]),
831 SortedVecSet::from(vec![mouse_button]),
832 event_time_u64,
833 &descriptor,
834 ),
835 ];
836
837 assert_input_report_sequence_generates_events!(
838 input_reports: input_reports,
839 expected_events: expected_events,
840 device_descriptor: descriptor,
841 device_type: MouseBinding,
842 );
843 }
844
845 #[fasync::run_singlethreaded(test)]
847 async fn down_up() {
848 let button = 1;
849 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
850 let first_report = testing_utilities::create_mouse_input_report_relative(
851 Position::zero(),
852 None, None, vec![button],
855 event_time_i64,
856 );
857 let second_report = testing_utilities::create_mouse_input_report_relative(
858 Position::zero(),
859 None, None, vec![],
862 event_time_i64,
863 );
864 let descriptor = mouse_device_descriptor(DEVICE_ID);
865
866 let input_reports = vec![first_report, second_report];
867 let expected_events = vec![
868 testing_utilities::create_mouse_event(
869 MouseLocation::Relative(Default::default()),
870 None, None, None, MousePhase::Down,
874 SortedVecSet::from(vec![button]),
875 SortedVecSet::from(vec![button]),
876 event_time_u64,
877 &descriptor,
878 ),
879 testing_utilities::create_mouse_event(
880 MouseLocation::Relative(Default::default()),
881 None, None, None, MousePhase::Up,
885 SortedVecSet::from(vec![button]),
886 SortedVecSet::new(),
887 event_time_u64,
888 &descriptor,
889 ),
890 ];
891
892 assert_input_report_sequence_generates_events!(
893 input_reports: input_reports,
894 expected_events: expected_events,
895 device_descriptor: descriptor,
896 device_type: MouseBinding,
897 );
898 }
899
900 #[fasync::run_singlethreaded(test)]
902 async fn down_up_with_movement() {
903 let button = 1;
904
905 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
906 let first_report = testing_utilities::create_mouse_input_report_relative(
907 Position::zero(),
908 None, None, vec![button],
911 event_time_i64,
912 );
913 let second_report = testing_utilities::create_mouse_input_report_relative(
914 Position { x: 10.0, y: 16.0 },
915 None, None, vec![],
918 event_time_i64,
919 );
920 let descriptor = mouse_device_descriptor(DEVICE_ID);
921
922 let input_reports = vec![first_report, second_report];
923 let expected_events = vec![
924 testing_utilities::create_mouse_event(
925 MouseLocation::Relative(Default::default()),
926 None, None, None, MousePhase::Down,
930 SortedVecSet::from(vec![button]),
931 SortedVecSet::from(vec![button]),
932 event_time_u64,
933 &descriptor,
934 ),
935 testing_utilities::create_mouse_event(
936 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
937 None, None, None, MousePhase::Move,
941 SortedVecSet::from(vec![button]),
942 SortedVecSet::from(vec![button]),
943 event_time_u64,
944 &descriptor,
945 ),
946 testing_utilities::create_mouse_event(
947 MouseLocation::Relative(Default::default()),
948 None, None, None, MousePhase::Up,
952 SortedVecSet::from(vec![button]),
953 SortedVecSet::new(),
954 event_time_u64,
955 &descriptor,
956 ),
957 ];
958
959 assert_input_report_sequence_generates_events!(
960 input_reports: input_reports,
961 expected_events: expected_events,
962 device_descriptor: descriptor,
963 device_type: MouseBinding,
964 );
965 }
966
967 #[fasync::run_singlethreaded(test)]
971 async fn down_move_up() {
972 let button = 1;
973
974 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
975 let first_report = testing_utilities::create_mouse_input_report_relative(
976 Position::zero(),
977 None, None, vec![button],
980 event_time_i64,
981 );
982 let second_report = testing_utilities::create_mouse_input_report_relative(
983 Position { x: 10.0, y: 16.0 },
984 None, None, vec![button],
987 event_time_i64,
988 );
989 let third_report = testing_utilities::create_mouse_input_report_relative(
990 Position::zero(),
991 None, None, vec![],
994 event_time_i64,
995 );
996 let descriptor = mouse_device_descriptor(DEVICE_ID);
997
998 let input_reports = vec![first_report, second_report, third_report];
999 let expected_events = vec![
1000 testing_utilities::create_mouse_event(
1001 MouseLocation::Relative(Default::default()),
1002 None, None, None, MousePhase::Down,
1006 SortedVecSet::from(vec![button]),
1007 SortedVecSet::from(vec![button]),
1008 event_time_u64,
1009 &descriptor,
1010 ),
1011 testing_utilities::create_mouse_event(
1012 MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
1013 None, None, None, MousePhase::Move,
1017 SortedVecSet::from(vec![button]),
1018 SortedVecSet::from(vec![button]),
1019 event_time_u64,
1020 &descriptor,
1021 ),
1022 testing_utilities::create_mouse_event(
1023 MouseLocation::Relative(Default::default()),
1024 None, None, None, MousePhase::Up,
1028 SortedVecSet::from(vec![button]),
1029 SortedVecSet::new(),
1030 event_time_u64,
1031 &descriptor,
1032 ),
1033 ];
1034
1035 assert_input_report_sequence_generates_events!(
1036 input_reports: input_reports,
1037 expected_events: expected_events,
1038 device_descriptor: descriptor,
1039 device_type: MouseBinding,
1040 );
1041 }
1042
1043 #[fasync::run_until_stalled(test)]
1045 async fn absolute_movement_to_origin() {
1046 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1047 let descriptor = mouse_device_descriptor(DEVICE_ID);
1048
1049 let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
1050 Position::zero(),
1051 None, None, vec![],
1054 event_time_i64,
1055 )];
1056 let expected_events = vec![testing_utilities::create_mouse_event(
1057 MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1058 None, None, None, MousePhase::Move,
1062 SortedVecSet::new(),
1063 SortedVecSet::new(),
1064 event_time_u64,
1065 &descriptor,
1066 )];
1067
1068 assert_input_report_sequence_generates_events!(
1069 input_reports: input_reports,
1070 expected_events: expected_events,
1071 device_descriptor: descriptor,
1072 device_type: MouseBinding,
1073 );
1074 }
1075
1076 #[fasync::run_until_stalled(test)]
1079 async fn report_with_both_movement_and_position() {
1080 let relative_movement = Position { x: 5.0, y: 5.0 };
1081 let absolute_position = Position { x: 10.0, y: 10.0 };
1082 let expected_location = MouseLocation::Absolute(absolute_position);
1083
1084 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1085 let descriptor = mouse_device_descriptor(DEVICE_ID);
1086
1087 let input_reports = vec![fidl_next_fuchsia_input_report::InputReport {
1088 event_time: Some(event_time_i64),
1089 keyboard: None,
1090 mouse: Some(fidl_next_fuchsia_input_report::MouseInputReport {
1091 movement_x: Some(relative_movement.x as i64),
1092 movement_y: Some(relative_movement.y as i64),
1093 position_x: Some(absolute_position.x as i64),
1094 position_y: Some(absolute_position.y as i64),
1095 scroll_h: None,
1096 scroll_v: None,
1097 pressed_buttons: None,
1098 ..Default::default()
1099 }),
1100 touch: None,
1101 sensor: None,
1102 consumer_control: None,
1103 trace_id: None,
1104 ..Default::default()
1105 }];
1106 let expected_events = vec![testing_utilities::create_mouse_event(
1107 expected_location,
1108 None, None, None, MousePhase::Move,
1112 SortedVecSet::new(),
1113 SortedVecSet::new(),
1114 event_time_u64,
1115 &descriptor,
1116 )];
1117
1118 assert_input_report_sequence_generates_events!(
1119 input_reports: input_reports,
1120 expected_events: expected_events,
1121 device_descriptor: descriptor,
1122 device_type: MouseBinding,
1123 );
1124 }
1125
1126 #[fasync::run_singlethreaded(test)]
1129 async fn down_down() {
1130 const PRIMARY_BUTTON: u8 = 1;
1131 const SECONDARY_BUTTON: u8 = 2;
1132
1133 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1134 let first_report = testing_utilities::create_mouse_input_report_relative(
1135 Position::zero(),
1136 None, None, vec![PRIMARY_BUTTON],
1139 event_time_i64,
1140 );
1141 let second_report = testing_utilities::create_mouse_input_report_relative(
1142 Position::zero(),
1143 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1146 event_time_i64,
1147 );
1148 let descriptor = mouse_device_descriptor(DEVICE_ID);
1149
1150 let input_reports = vec![first_report, second_report];
1151 let expected_events = vec![
1152 testing_utilities::create_mouse_event(
1153 MouseLocation::Relative(Default::default()),
1154 None, None, None, MousePhase::Down,
1158 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1159 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1160 event_time_u64,
1161 &descriptor,
1162 ),
1163 testing_utilities::create_mouse_event(
1164 MouseLocation::Relative(Default::default()),
1165 None, None, None, MousePhase::Down,
1169 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1170 SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1171 event_time_u64,
1172 &descriptor,
1173 ),
1174 ];
1175
1176 assert_input_report_sequence_generates_events!(
1177 input_reports: input_reports,
1178 expected_events: expected_events,
1179 device_descriptor: descriptor,
1180 device_type: MouseBinding,
1181 );
1182 }
1183
1184 #[fasync::run_singlethreaded(test)]
1194 async fn down_down_up_up() {
1195 const PRIMARY_BUTTON: u8 = 1;
1196 const SECONDARY_BUTTON: u8 = 2;
1197
1198 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1199 let first_report = testing_utilities::create_mouse_input_report_relative(
1200 Position::zero(),
1201 None, None, vec![PRIMARY_BUTTON],
1204 event_time_i64,
1205 );
1206 let second_report = testing_utilities::create_mouse_input_report_relative(
1207 Position::zero(),
1208 None, None, vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1211 event_time_i64,
1212 );
1213 let third_report = testing_utilities::create_mouse_input_report_relative(
1214 Position::zero(),
1215 None, None, vec![SECONDARY_BUTTON],
1218 event_time_i64,
1219 );
1220 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1221 Position::zero(),
1222 None, None, vec![],
1225 event_time_i64,
1226 );
1227 let descriptor = mouse_device_descriptor(DEVICE_ID);
1228
1229 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1230 let expected_events = vec![
1231 testing_utilities::create_mouse_event(
1232 MouseLocation::Relative(Default::default()),
1233 None, None, None, MousePhase::Down,
1237 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1238 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1239 event_time_u64,
1240 &descriptor,
1241 ),
1242 testing_utilities::create_mouse_event(
1243 MouseLocation::Relative(Default::default()),
1244 None, None, None, MousePhase::Down,
1248 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1249 SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1250 event_time_u64,
1251 &descriptor,
1252 ),
1253 testing_utilities::create_mouse_event(
1254 MouseLocation::Relative(Default::default()),
1255 None, None, None, MousePhase::Up,
1259 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1260 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1261 event_time_u64,
1262 &descriptor,
1263 ),
1264 testing_utilities::create_mouse_event(
1265 MouseLocation::Relative(Default::default()),
1266 None, None, None, MousePhase::Up,
1270 SortedVecSet::from(vec![SECONDARY_BUTTON]),
1271 SortedVecSet::new(),
1272 event_time_u64,
1273 &descriptor,
1274 ),
1275 ];
1276
1277 assert_input_report_sequence_generates_events!(
1278 input_reports: input_reports,
1279 expected_events: expected_events,
1280 device_descriptor: descriptor,
1281 device_type: MouseBinding,
1282 );
1283 }
1284
1285 #[fasync::run_singlethreaded(test)]
1287 async fn scroll() {
1288 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1289 let first_report = testing_utilities::create_mouse_input_report_relative(
1290 Position::zero(),
1291 Some(1),
1292 None,
1293 vec![],
1294 event_time_i64,
1295 );
1296 let second_report = testing_utilities::create_mouse_input_report_relative(
1297 Position::zero(),
1298 None,
1299 Some(1),
1300 vec![],
1301 event_time_i64,
1302 );
1303
1304 let descriptor = mouse_device_descriptor(DEVICE_ID);
1305
1306 let input_reports = vec![first_report, second_report];
1307 let expected_events = vec![
1308 testing_utilities::create_mouse_event(
1309 MouseLocation::Relative(Default::default()),
1310 wheel_delta_ticks(1),
1311 None,
1312 Some(PrecisionScroll::No),
1313 MousePhase::Wheel,
1314 SortedVecSet::new(),
1315 SortedVecSet::new(),
1316 event_time_u64,
1317 &descriptor,
1318 ),
1319 testing_utilities::create_mouse_event(
1320 MouseLocation::Relative(Default::default()),
1321 None,
1322 wheel_delta_ticks(1),
1323 Some(PrecisionScroll::No),
1324 MousePhase::Wheel,
1325 SortedVecSet::new(),
1326 SortedVecSet::new(),
1327 event_time_u64,
1328 &descriptor,
1329 ),
1330 ];
1331
1332 assert_input_report_sequence_generates_events!(
1333 input_reports: input_reports,
1334 expected_events: expected_events,
1335 device_descriptor: descriptor,
1336 device_type: MouseBinding,
1337 );
1338 }
1339
1340 #[fasync::run_singlethreaded(test)]
1342 async fn down_scroll_up_scroll() {
1343 const PRIMARY_BUTTON: u8 = 1;
1344
1345 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1346 let first_report = testing_utilities::create_mouse_input_report_relative(
1347 Position::zero(),
1348 None, None, vec![PRIMARY_BUTTON],
1351 event_time_i64,
1352 );
1353 let second_report = testing_utilities::create_mouse_input_report_relative(
1354 Position::zero(),
1355 Some(1),
1356 None,
1357 vec![PRIMARY_BUTTON],
1358 event_time_i64,
1359 );
1360 let third_report = testing_utilities::create_mouse_input_report_relative(
1361 Position::zero(),
1362 None, None, vec![],
1365 event_time_i64,
1366 );
1367 let fourth_report = testing_utilities::create_mouse_input_report_relative(
1368 Position::zero(),
1369 Some(1),
1370 None,
1371 vec![],
1372 event_time_i64,
1373 );
1374
1375 let descriptor = mouse_device_descriptor(DEVICE_ID);
1376
1377 let input_reports = vec![first_report, second_report, third_report, fourth_report];
1378 let expected_events = vec![
1379 testing_utilities::create_mouse_event(
1380 MouseLocation::Relative(Default::default()),
1381 None, None, None, MousePhase::Down,
1385 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1386 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1387 event_time_u64,
1388 &descriptor,
1389 ),
1390 testing_utilities::create_mouse_event(
1391 MouseLocation::Relative(Default::default()),
1392 wheel_delta_ticks(1),
1393 None,
1394 Some(PrecisionScroll::No),
1395 MousePhase::Wheel,
1396 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1397 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1398 event_time_u64,
1399 &descriptor,
1400 ),
1401 testing_utilities::create_mouse_event(
1402 MouseLocation::Relative(Default::default()),
1403 None, None, None, MousePhase::Up,
1407 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1408 SortedVecSet::new(),
1409 event_time_u64,
1410 &descriptor,
1411 ),
1412 testing_utilities::create_mouse_event(
1413 MouseLocation::Relative(Default::default()),
1414 wheel_delta_ticks(1),
1415 None,
1416 Some(PrecisionScroll::No),
1417 MousePhase::Wheel,
1418 SortedVecSet::new(),
1419 SortedVecSet::new(),
1420 event_time_u64,
1421 &descriptor,
1422 ),
1423 ];
1424
1425 assert_input_report_sequence_generates_events!(
1426 input_reports: input_reports,
1427 expected_events: expected_events,
1428 device_descriptor: descriptor,
1429 device_type: MouseBinding,
1430 );
1431 }
1432
1433 #[fasync::run_singlethreaded(test)]
1435 async fn down_scroll_bundle_up_scroll_bundle() {
1436 const PRIMARY_BUTTON: u8 = 1;
1437
1438 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1439 let first_report = testing_utilities::create_mouse_input_report_relative(
1440 Position::zero(),
1441 Some(1),
1442 None,
1443 vec![PRIMARY_BUTTON],
1444 event_time_i64,
1445 );
1446 let second_report = testing_utilities::create_mouse_input_report_relative(
1447 Position::zero(),
1448 Some(1),
1449 None,
1450 vec![],
1451 event_time_i64,
1452 );
1453 let third_report = testing_utilities::create_mouse_input_report_relative(
1454 Position::zero(),
1455 Some(1),
1456 None,
1457 vec![],
1458 event_time_i64,
1459 );
1460
1461 let descriptor = mouse_device_descriptor(DEVICE_ID);
1462
1463 let input_reports = vec![first_report, second_report, third_report];
1464 let expected_events = vec![
1465 testing_utilities::create_mouse_event(
1466 MouseLocation::Relative(Default::default()),
1467 None, None, None, MousePhase::Down,
1471 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1472 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1473 event_time_u64,
1474 &descriptor,
1475 ),
1476 testing_utilities::create_mouse_event(
1477 MouseLocation::Relative(Default::default()),
1478 wheel_delta_ticks(1),
1479 None,
1480 Some(PrecisionScroll::No),
1481 MousePhase::Wheel,
1482 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1483 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1484 event_time_u64,
1485 &descriptor,
1486 ),
1487 testing_utilities::create_mouse_event(
1488 MouseLocation::Relative(Default::default()),
1489 wheel_delta_ticks(1),
1490 None,
1491 Some(PrecisionScroll::No),
1492 MousePhase::Wheel,
1493 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1494 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1495 event_time_u64,
1496 &descriptor,
1497 ),
1498 testing_utilities::create_mouse_event(
1499 MouseLocation::Relative(Default::default()),
1500 None, None, None, MousePhase::Up,
1504 SortedVecSet::from(vec![PRIMARY_BUTTON]),
1505 SortedVecSet::new(),
1506 event_time_u64,
1507 &descriptor,
1508 ),
1509 testing_utilities::create_mouse_event(
1510 MouseLocation::Relative(Default::default()),
1511 wheel_delta_ticks(1),
1512 None,
1513 Some(PrecisionScroll::No),
1514 MousePhase::Wheel,
1515 SortedVecSet::new(),
1516 SortedVecSet::new(),
1517 event_time_u64,
1518 &descriptor,
1519 ),
1520 ];
1521
1522 assert_input_report_sequence_generates_events!(
1523 input_reports: input_reports,
1524 expected_events: expected_events,
1525 device_descriptor: descriptor,
1526 device_type: MouseBinding,
1527 );
1528 }
1529}