Skip to main content

input_pipeline_dso/
mouse_binding.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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 fuchsia_inspect::ArrayProperty;
12use fuchsia_inspect::health::Reporter;
13use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
14use metrics_registry::*;
15use sorted_vec_map::SortedVecSet;
16use zx;
17
18pub type MouseButton = u8;
19
20/// Flag to indicate the scroll event is from device reporting precision delta.
21#[derive(Copy, Clone, Debug, PartialEq)]
22pub enum PrecisionScroll {
23    /// Touchpad and some mouse able to report precision delta.
24    Yes,
25    /// Tick based mouse wheel.
26    No,
27}
28
29/// A [`MouseLocation`] represents the mouse pointer location at the time of a pointer event.
30#[derive(Copy, Clone, Debug, PartialEq)]
31pub enum MouseLocation {
32    /// A mouse movement relative to its current position.
33    Relative(RelativeLocation),
34
35    /// An absolute position, in device coordinates.
36    Absolute(Position),
37}
38
39#[derive(Copy, Clone, Debug, PartialEq)]
40pub enum MousePhase {
41    Down,  // One or more buttons were newly pressed.
42    Move,  // The mouse moved with no change in button state.
43    Up,    // One or more buttons were newly released.
44    Wheel, // Mouse wheel is rotating.
45}
46
47/// A [`RelativeLocation`] contains the relative mouse pointer location at the time of a pointer event.
48#[derive(Copy, Clone, Debug, PartialEq)]
49pub struct RelativeLocation {
50    /// A pointer location in counts.
51    pub counts: Position,
52}
53
54impl Default for RelativeLocation {
55    fn default() -> Self {
56        RelativeLocation { counts: Position::zero() }
57    }
58}
59
60/// A [`WheelDelta`] contains raw wheel delta ticks from driver or gesture arena
61/// and scaled wheel delta in physical pixels.
62#[derive(Clone, Debug, PartialEq)]
63pub struct WheelDelta {
64    pub ticks: i64,
65    pub physical_pixel: Option<f32>,
66}
67
68/// A [`MouseEvent`] represents a pointer event with a specified phase, and the buttons
69/// involved in said phase. The supported phases for mice include Up, Down, and Move.
70///
71/// # Example
72/// The following MouseEvent represents a relative movement of 40 units in the x axis
73/// and 20 units in the y axis while holding the primary button (1) down.
74///
75/// ```
76/// let mouse_device_event = input_device::InputDeviceEvent::Mouse(MouseEvent::new(
77///     MouseLocation::Relative(RelativeLocation {
78///       counts: Position { x: 40.0, y: 20.0 },
79///     }),
80///     None, // wheel_delta_v
81///     None, // wheel_delta_h
82///     MousePhase::Move,
83///     SortedVecSet::from(vec![1]),
84///     SortedVecSet::from(vec![1]),
85///     None, // is_precision_scroll
86///     None, // wake_lease
87/// ));
88/// ```
89#[derive(Debug)]
90pub struct MouseEvent {
91    /// The mouse location.
92    pub location: MouseLocation,
93
94    /// The mouse wheel rotated delta in vertical.
95    pub wheel_delta_v: Option<WheelDelta>,
96
97    /// The mouse wheel rotated delta in horizontal.
98    pub wheel_delta_h: Option<WheelDelta>,
99
100    /// The mouse device reports precision scroll delta.
101    pub is_precision_scroll: Option<PrecisionScroll>,
102
103    /// The phase of the [`buttons`] associated with this input event.
104    pub phase: MousePhase,
105
106    /// The buttons relevant to this event.
107    pub affected_buttons: SortedVecSet<MouseButton>,
108
109    /// The complete button state including this event.
110    pub pressed_buttons: SortedVecSet<MouseButton>,
111
112    /// The wake lease for this event.
113    pub wake_lease: Option<zx::EventPair>,
114}
115
116impl Clone for MouseEvent {
117    fn clone(&self) -> Self {
118        log::debug!("MouseEvent cloned without wake lease.");
119        Self {
120            location: self.location,
121            wheel_delta_v: self.wheel_delta_v.clone(),
122            wheel_delta_h: self.wheel_delta_h.clone(),
123            is_precision_scroll: self.is_precision_scroll,
124            phase: self.phase,
125            affected_buttons: self.affected_buttons.clone(),
126            pressed_buttons: self.pressed_buttons.clone(),
127            wake_lease: None,
128        }
129    }
130}
131
132impl PartialEq for MouseEvent {
133    fn eq(&self, other: &Self) -> bool {
134        self.location == other.location
135            && self.wheel_delta_v == other.wheel_delta_v
136            && self.wheel_delta_h == other.wheel_delta_h
137            && self.is_precision_scroll == other.is_precision_scroll
138            && self.phase == other.phase
139            && self.affected_buttons == other.affected_buttons
140            && self.pressed_buttons == other.pressed_buttons
141    }
142}
143
144impl MouseEvent {
145    /// Creates a new [`MouseEvent`].
146    ///
147    /// # Parameters
148    /// - `location`: The mouse location.
149    /// - `phase`: The phase of the [`buttons`] associated with this input event.
150    /// - `buttons`: The buttons relevant to this event.
151    /// - `wake_lease`: The wake lease for this event.
152    pub fn new(
153        location: MouseLocation,
154        wheel_delta_v: Option<WheelDelta>,
155        wheel_delta_h: Option<WheelDelta>,
156        phase: MousePhase,
157        affected_buttons: SortedVecSet<MouseButton>,
158        pressed_buttons: SortedVecSet<MouseButton>,
159        is_precision_scroll: Option<PrecisionScroll>,
160        wake_lease: Option<zx::EventPair>,
161    ) -> MouseEvent {
162        MouseEvent {
163            location,
164            wheel_delta_v,
165            wheel_delta_h,
166            phase,
167            affected_buttons,
168            pressed_buttons,
169            is_precision_scroll,
170            wake_lease,
171        }
172    }
173
174    pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
175        match self.location {
176            MouseLocation::Relative(pos) => {
177                node.record_child("location_relative", move |location_node| {
178                    location_node.record_double("x", f64::from(pos.counts.x));
179                    location_node.record_double("y", f64::from(pos.counts.y));
180                })
181            }
182            MouseLocation::Absolute(pos) => {
183                node.record_child("location_absolute", move |location_node| {
184                    location_node.record_double("x", f64::from(pos.x));
185                    location_node.record_double("y", f64::from(pos.y));
186                })
187            }
188        };
189
190        if let Some(wheel_delta_v) = &self.wheel_delta_v {
191            node.record_child("wheel_delta_v", move |wheel_delta_v_node| {
192                wheel_delta_v_node.record_int("ticks", wheel_delta_v.ticks);
193                if let Some(physical_pixel) = wheel_delta_v.physical_pixel {
194                    wheel_delta_v_node.record_double("physical_pixel", f64::from(physical_pixel));
195                }
196            });
197        }
198
199        if let Some(wheel_delta_h) = &self.wheel_delta_h {
200            node.record_child("wheel_delta_h", move |wheel_delta_h_node| {
201                wheel_delta_h_node.record_int("ticks", wheel_delta_h.ticks);
202                if let Some(physical_pixel) = wheel_delta_h.physical_pixel {
203                    wheel_delta_h_node.record_double("physical_pixel", f64::from(physical_pixel));
204                }
205            });
206        }
207
208        if let Some(is_precision_scroll) = self.is_precision_scroll {
209            match is_precision_scroll {
210                PrecisionScroll::Yes => node.record_string("is_precision_scroll", "yes"),
211                PrecisionScroll::No => node.record_string("is_precision_scroll", "no"),
212            }
213        }
214
215        match self.phase {
216            MousePhase::Down => node.record_string("phase", "down"),
217            MousePhase::Move => node.record_string("phase", "move"),
218            MousePhase::Up => node.record_string("phase", "up"),
219            MousePhase::Wheel => node.record_string("phase", "wheel"),
220        }
221
222        let affected_buttons_node =
223            node.create_uint_array("affected_buttons", self.affected_buttons.len());
224        self.affected_buttons.iter().enumerate().for_each(|(i, button)| {
225            affected_buttons_node.set(i, *button);
226        });
227        node.record(affected_buttons_node);
228
229        let pressed_buttons_node =
230            node.create_uint_array("pressed_buttons", self.pressed_buttons.len());
231        self.pressed_buttons.iter().enumerate().for_each(|(i, button)| {
232            pressed_buttons_node.set(i, *button);
233        });
234        node.record(pressed_buttons_node);
235    }
236}
237
238/// A [`MouseBinding`] represents a connection to a mouse input device.
239///
240/// The [`MouseBinding`] parses and exposes mouse descriptor properties (e.g., the range of
241/// possible x values) for the device it is associated with. It also parses [`InputReport`]s
242/// from the device, and sends them to the device binding owner over `event_sender`.
243pub struct MouseBinding {
244    /// The channel to stream InputEvents to.
245    event_sender: UnboundedSender<Vec<InputEvent>>,
246
247    /// Holds information about this device.
248    device_descriptor: MouseDeviceDescriptor,
249}
250
251#[derive(Clone, Debug, Eq, PartialEq)]
252pub struct MouseDeviceDescriptor {
253    /// The id of the connected mouse input device.
254    pub device_id: u32,
255
256    /// The range of possible x values of absolute mouse positions reported by this device.
257    pub absolute_x_range: Option<fidl_input_report::Range>,
258
259    /// The range of possible y values of absolute mouse positions reported by this device.
260    pub absolute_y_range: Option<fidl_input_report::Range>,
261
262    /// The range of possible vertical wheel delta reported by this device.
263    pub wheel_v_range: Option<fidl_input_report::Axis>,
264
265    /// The range of possible horizontal wheel delta reported by this device.
266    pub wheel_h_range: Option<fidl_input_report::Axis>,
267
268    /// This is a vector of ids for the mouse buttons.
269    pub buttons: Option<Vec<MouseButton>>,
270}
271
272#[async_trait]
273impl input_device::InputDeviceBinding for MouseBinding {
274    fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>> {
275        self.event_sender.clone()
276    }
277
278    fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
279        input_device::InputDeviceDescriptor::Mouse(self.device_descriptor.clone())
280    }
281}
282
283impl MouseBinding {
284    /// Creates a new [`InputDeviceBinding`] from the `device_proxy`.
285    ///
286    /// The binding will start listening for input reports immediately and send new InputEvents
287    /// to the device binding owner over `input_event_sender`.
288    ///
289    /// # Parameters
290    /// - `device_proxy`: The proxy to bind the new [`InputDeviceBinding`] to.
291    /// - `device_id`: The id of the connected mouse device.
292    /// - `input_event_sender`: The channel to send new InputEvents to.
293    /// - `device_node`: The inspect node for this device binding
294    /// - `metrics_logger`: The metrics logger.
295    ///
296    /// # Errors
297    /// If there was an error binding to the proxy.
298    pub async fn new(
299        device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
300        device_id: u32,
301        input_event_sender: UnboundedSender<Vec<InputEvent>>,
302        device_node: fuchsia_inspect::Node,
303        _feature_flags: input_device::InputPipelineFeatureFlags,
304        metrics_logger: metrics::MetricsLogger,
305    ) -> Result<Self, Error> {
306        let (device_binding, mut inspect_status) =
307            Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
308        inspect_status.health_node.set_ok();
309        input_device::initialize_report_stream(
310            device_proxy,
311            device_binding.get_device_descriptor(),
312            device_binding.input_event_sender(),
313            inspect_status,
314            metrics_logger,
315            _feature_flags,
316            Self::process_reports,
317        );
318
319        Ok(device_binding)
320    }
321
322    /// Binds the provided input device to a new instance of `Self`.
323    ///
324    /// # Parameters
325    /// - `device`: The device to use to initialize the binding.
326    /// - `device_id`: The id of the connected mouse device.
327    /// - `input_event_sender`: The channel to send new InputEvents to.
328    /// - `device_node`: The inspect node for this device binding
329    ///
330    /// # Errors
331    /// If the device descriptor could not be retrieved, or the descriptor could
332    /// not be parsed correctly.
333    async fn bind_device(
334        device: &fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
335        device_id: u32,
336        input_event_sender: UnboundedSender<Vec<InputEvent>>,
337        device_node: fuchsia_inspect::Node,
338    ) -> Result<(Self, InputDeviceStatus), Error> {
339        let mut input_device_status = InputDeviceStatus::new(device_node);
340        let device_descriptor: fidl_next_fuchsia_input_report::DeviceDescriptor = match device
341            .get_descriptor()
342            .await
343        {
344            Ok(res) => res.descriptor,
345            Err(_) => {
346                input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
347                return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
348            }
349        };
350
351        let mouse_descriptor = device_descriptor.mouse.ok_or_else(|| {
352            input_device_status
353                .health_node
354                .set_unhealthy("DeviceDescriptor does not have a MouseDescriptor.");
355            format_err!("DeviceDescriptor does not have a MouseDescriptor")
356        })?;
357
358        let mouse_input_descriptor = mouse_descriptor.input.ok_or_else(|| {
359            input_device_status
360                .health_node
361                .set_unhealthy("MouseDescriptor does not have a MouseInputDescriptor.");
362            format_err!("MouseDescriptor does not have a MouseInputDescriptor")
363        })?;
364
365        let device_descriptor: MouseDeviceDescriptor = MouseDeviceDescriptor {
366            device_id,
367            absolute_x_range: mouse_input_descriptor
368                .position_x
369                .as_ref()
370                .map(|axis| utils::range_to_old(&axis.range)),
371            absolute_y_range: mouse_input_descriptor
372                .position_y
373                .as_ref()
374                .map(|axis| utils::range_to_old(&axis.range)),
375            wheel_v_range: utils::axis_to_old(mouse_input_descriptor.scroll_v.as_ref()),
376            wheel_h_range: utils::axis_to_old(mouse_input_descriptor.scroll_h.as_ref()),
377            buttons: mouse_input_descriptor.buttons,
378        };
379
380        Ok((Self { event_sender: input_event_sender, device_descriptor }, input_device_status))
381    }
382
383    /// Parses an [`InputReport`] into one or more [`InputEvent`]s.
384    ///
385    /// The [`InputEvent`]s are sent to the device binding owner via [`input_event_sender`].
386    ///
387    /// # Parameters
388    /// `reports`: The incoming [`InputReport`].
389    /// `previous_report`: The previous [`InputReport`] seen for the same device. This can be
390    ///                    used to determine, for example, which keys are no longer present in
391    ///                    a keyboard report to generate key released events. If `None`, no
392    ///                    previous report was found.
393    /// `device_descriptor`: The descriptor for the input device generating the input reports.
394    /// `input_event_sender`: The sender for the device binding's input event stream.
395    ///
396    /// # Returns
397    /// An [`InputReport`] which will be passed to the next call to [`process_reports`], as
398    /// [`previous_report`]. If `None`, the next call's [`previous_report`] will be `None`.
399    /// A [`UnboundedReceiver<InputEvent>`] which will poll asynchronously generated events to be
400    /// recorded by `inspect_status` in `input_device::initialize_report_stream()`. If device
401    /// binding does not generate InputEvents asynchronously, this will be `None`.
402    ///
403    /// The returned [`InputReport`] is guaranteed to have no `wake_lease`.
404    fn process_reports(
405        reports: &[fidl_next_fuchsia_input_report::wire::InputReport<'_>],
406        mut previous_state: Option<input_device::PreviousDeviceState>,
407        device_descriptor: &input_device::InputDeviceDescriptor,
408        input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
409        inspect_status: &InputDeviceStatus,
410        metrics_logger: &metrics::MetricsLogger,
411        _feature_flags: &input_device::InputPipelineFeatureFlags,
412    ) -> (Option<input_device::PreviousDeviceState>, Option<UnboundedReceiver<InputEvent>>) {
413        fuchsia_trace::duration!("input", "mouse-binding-process-reports", "num_reports" => reports.len());
414        for report in reports {
415            previous_state = Self::process_report(
416                report,
417                previous_state,
418                device_descriptor,
419                input_event_sender,
420                inspect_status,
421                metrics_logger,
422            );
423        }
424        (previous_state, None)
425    }
426
427    fn process_report(
428        report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
429        previous_state: Option<input_device::PreviousDeviceState>,
430        device_descriptor: &input_device::InputDeviceDescriptor,
431        input_event_sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
432        inspect_status: &InputDeviceStatus,
433        metrics_logger: &metrics::MetricsLogger,
434    ) -> Option<input_device::PreviousDeviceState> {
435        if let Some(trace_id) = report.trace_id() {
436            fuchsia_trace::flow_end!("input", "input_report", trace_id.0.into());
437        }
438
439        // Extract the wake_lease early to prevent it from leaking. If this is moved
440        // below an early return, the lease could accidentally be stored inside
441        // `previous_report`, which would prevent the system from suspending.
442        let wake_lease = utils::duplicate_wake_lease(report.wake_lease());
443
444        inspect_status.count_received_report_wire(report);
445        // Input devices can have multiple types so ensure `report` is a MouseInputReport.
446        let mouse_report = match report.mouse() {
447            Some(mouse) => mouse,
448            None => {
449                inspect_status.count_filtered_report();
450                return previous_state;
451            }
452        };
453
454        let previous_buttons: SortedVecSet<MouseButton> = match previous_state {
455            Some(input_device::PreviousDeviceState::Mouse { pressed_buttons }) => pressed_buttons,
456            _ => SortedVecSet::new(),
457        };
458        let current_buttons: SortedVecSet<MouseButton> =
459            buttons_from_mouse_report_wire(mouse_report);
460
461        // Send a Down event with:
462        // * affected_buttons: the buttons that were pressed since the previous report,
463        //   i.e. that are in the current report, but were not in the previous report.
464        // * pressed_buttons: the full set of currently pressed buttons, including the
465        //   recently pressed ones (affected_buttons).
466        send_mouse_event(
467            MouseLocation::Relative(Default::default()),
468            None, /* wheel_delta_v */
469            None, /* wheel_delta_h */
470            MousePhase::Down,
471            current_buttons.difference(&previous_buttons).cloned().collect(),
472            current_buttons.clone(),
473            device_descriptor,
474            input_event_sender,
475            inspect_status,
476            metrics_logger,
477            wake_lease.as_ref().map(|lease| {
478                lease
479                    .duplicate_handle(zx::Rights::SAME_RIGHTS)
480                    .expect("failed to duplicate event pair")
481            }),
482        );
483
484        // Create a location for the move event. Use the absolute position if available.
485        let location = if let (Some(position_x), Some(position_y)) =
486            (mouse_report.position_x(), mouse_report.position_y())
487        {
488            MouseLocation::Absolute(Position { x: position_x.0 as f32, y: position_y.0 as f32 })
489        } else {
490            let movement_x = mouse_report.movement_x().map(|x| x.0).unwrap_or_default() as f32;
491            let movement_y = mouse_report.movement_y().map(|y| y.0).unwrap_or_default() as f32;
492            MouseLocation::Relative(RelativeLocation {
493                counts: Position { x: movement_x, y: movement_y },
494            })
495        };
496
497        // Send a Move event with buttons from both the current report and the previous report.
498        // * affected_buttons and pressed_buttons are identical in this case, since the full
499        //   set of currently pressed buttons are the same set affected by the event.
500        send_mouse_event(
501            location,
502            None, /* wheel_delta_v */
503            None, /* wheel_delta_h */
504            MousePhase::Move,
505            current_buttons.union(&previous_buttons).cloned().collect(),
506            current_buttons.union(&previous_buttons).cloned().collect(),
507            device_descriptor,
508            input_event_sender,
509            inspect_status,
510            metrics_logger,
511            wake_lease.as_ref().map(|lease| {
512                lease
513                    .duplicate_handle(zx::Rights::SAME_RIGHTS)
514                    .expect("failed to duplicate event pair")
515            }),
516        );
517
518        let wheel_delta_v = mouse_report
519            .scroll_v()
520            .map(|ticks| WheelDelta { ticks: ticks.0, physical_pixel: None });
521
522        let wheel_delta_h = mouse_report
523            .scroll_h()
524            .map(|ticks| WheelDelta { ticks: ticks.0, physical_pixel: None });
525
526        // Send a mouse wheel event.
527        send_mouse_event(
528            MouseLocation::Relative(Default::default()),
529            wheel_delta_v,
530            wheel_delta_h,
531            MousePhase::Wheel,
532            current_buttons.union(&previous_buttons).cloned().collect(),
533            current_buttons.union(&previous_buttons).cloned().collect(),
534            device_descriptor,
535            input_event_sender,
536            inspect_status,
537            metrics_logger,
538            wake_lease.as_ref().map(|lease| {
539                lease
540                    .duplicate_handle(zx::Rights::SAME_RIGHTS)
541                    .expect("failed to duplicate event pair")
542            }),
543        );
544
545        // Send an Up event with:
546        // * affected_buttons: the buttons that were released since the previous report,
547        //   i.e. that were in the previous report, but are not in the current report.
548        // * pressed_buttons: the full set of currently pressed buttons, excluding the
549        //   recently released ones (affected_buttons).
550        send_mouse_event(
551            MouseLocation::Relative(Default::default()),
552            None, /* wheel_delta_v */
553            None, /* wheel_delta_h */
554            MousePhase::Up,
555            previous_buttons.difference(&current_buttons).cloned().collect(),
556            current_buttons.clone(),
557            device_descriptor,
558            input_event_sender,
559            inspect_status,
560            metrics_logger,
561            wake_lease,
562        );
563
564        Some(input_device::PreviousDeviceState::Mouse { pressed_buttons: current_buttons })
565    }
566}
567
568/// Sends an InputEvent over `sender`.
569///
570/// When no buttons are present, only [`MousePhase::Move`] events will
571/// be sent.
572///
573/// # Parameters
574/// - `location`: The mouse location.
575/// - `wheel_delta_v`: The mouse wheel delta in vertical.
576/// - `wheel_delta_h`: The mouse wheel delta in horizontal.
577/// - `phase`: The phase of the [`buttons`] associated with the input event.
578/// - `buttons`: The buttons relevant to the event.
579/// - `device_descriptor`: The descriptor for the input device generating the input reports.
580/// - `sender`: The stream to send the MouseEvent to.
581/// - `wake_lease`: The wake lease to send with the event.
582fn send_mouse_event(
583    location: MouseLocation,
584    wheel_delta_v: Option<WheelDelta>,
585    wheel_delta_h: Option<WheelDelta>,
586    phase: MousePhase,
587    affected_buttons: SortedVecSet<MouseButton>,
588    pressed_buttons: SortedVecSet<MouseButton>,
589    device_descriptor: &input_device::InputDeviceDescriptor,
590    sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
591    inspect_status: &InputDeviceStatus,
592    metrics_logger: &metrics::MetricsLogger,
593    wake_lease: Option<zx::EventPair>,
594) {
595    // Only send Down/Up events when there are buttons affected.
596    if (phase == MousePhase::Down || phase == MousePhase::Up) && affected_buttons.is_empty() {
597        return;
598    }
599
600    // Don't send Move events when there is no relative movement.
601    // However, absolute movement is always reported.
602    if phase == MousePhase::Move && location == MouseLocation::Relative(Default::default()) {
603        return;
604    }
605
606    // Only send wheel events when the delta has value.
607    if phase == MousePhase::Wheel && wheel_delta_v.is_none() && wheel_delta_h.is_none() {
608        return;
609    }
610
611    let trace_id = fuchsia_trace::Id::new();
612    fuchsia_trace::duration!("input", "mouse-binding-send-event");
613    fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
614
615    let event = input_device::InputEvent {
616        device_event: input_device::InputDeviceEvent::Mouse(MouseEvent::new(
617            location,
618            wheel_delta_v,
619            wheel_delta_h,
620            phase,
621            affected_buttons,
622            pressed_buttons,
623            match phase {
624                MousePhase::Wheel => Some(PrecisionScroll::No),
625                _ => None,
626            },
627            wake_lease,
628        )),
629        device_descriptor: device_descriptor.clone(),
630        event_time: zx::MonotonicInstant::get(),
631        handled: Handled::No,
632        trace_id: Some(trace_id),
633    };
634    let events = vec![event];
635    inspect_status.count_generated_events(&events);
636
637    if let Err(e) = sender.unbounded_send(events) {
638        metrics_logger.log_error(
639            InputPipelineErrorMetricDimensionEvent::MouseFailedToSendEvent,
640            std::format!("Failed to send MouseEvent with error: {:?}", e),
641        );
642    }
643}
644
645fn buttons_from_mouse_report_wire(
646    mouse_report: &fidl_next_fuchsia_input_report::wire::MouseInputReport<'_>,
647) -> SortedVecSet<MouseButton> {
648    mouse_report
649        .pressed_buttons()
650        .map(|buttons| SortedVecSet::from_iter(buttons.iter().copied()))
651        .unwrap_or_default()
652}
653
654#[cfg(test)]
655mod tests {
656    use super::*;
657    use crate::testing_utilities;
658    use fuchsia_async as fasync;
659    use futures::StreamExt;
660    use sorted_vec_map::SortedVecSet;
661
662    const DEVICE_ID: u32 = 1;
663
664    fn mouse_device_descriptor(device_id: u32) -> input_device::InputDeviceDescriptor {
665        input_device::InputDeviceDescriptor::Mouse(MouseDeviceDescriptor {
666            device_id,
667            absolute_x_range: None,
668            absolute_y_range: None,
669            wheel_v_range: Some(fidl_fuchsia_input_report::Axis {
670                range: fidl_input_report::Range { min: -1, max: 1 },
671                unit: fidl_input_report::Unit {
672                    type_: fidl_input_report::UnitType::Other,
673                    exponent: 1,
674                },
675            }),
676            wheel_h_range: Some(fidl_fuchsia_input_report::Axis {
677                range: fidl_input_report::Range { min: -1, max: 1 },
678                unit: fidl_input_report::Unit {
679                    type_: fidl_input_report::UnitType::Other,
680                    exponent: 1,
681                },
682            }),
683            buttons: None,
684        })
685    }
686
687    fn wheel_delta_ticks(ticks: i64) -> Option<WheelDelta> {
688        Some(WheelDelta { ticks, physical_pixel: None })
689    }
690
691    /// Tests that a report containing no buttons but with movement generates a move event.
692    #[fasync::run_singlethreaded(test)]
693    async fn movement_without_button() {
694        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
695        let first_report = testing_utilities::create_mouse_input_report_relative(
696            Position { x: 10.0, y: 16.0 },
697            None, /* scroll_v */
698            None, /* scroll_h */
699            vec![],
700            event_time_i64,
701        );
702        let descriptor = mouse_device_descriptor(DEVICE_ID);
703
704        let input_reports = vec![first_report];
705        let expected_events = vec![testing_utilities::create_mouse_event(
706            MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
707            None, /* wheel_delta_v */
708            None, /* wheel_delta_h */
709            None, /* is_precision_scroll */
710            MousePhase::Move,
711            SortedVecSet::new(),
712            SortedVecSet::new(),
713            event_time_u64,
714            &descriptor,
715        )];
716
717        assert_input_report_sequence_generates_events!(
718            input_reports: input_reports,
719            expected_events: expected_events,
720            device_descriptor: descriptor,
721            device_type: MouseBinding,
722        );
723    }
724
725    /// Tests that a report containing a new mouse button generates a down event.
726    #[fasync::run_singlethreaded(test)]
727    async fn down_without_movement() {
728        let mouse_button: MouseButton = 3;
729        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
730        let first_report = testing_utilities::create_mouse_input_report_relative(
731            Position::zero(),
732            None, /* scroll_v */
733            None, /* scroll_h */
734            vec![mouse_button],
735            event_time_i64,
736        );
737        let descriptor = mouse_device_descriptor(DEVICE_ID);
738
739        let input_reports = vec![first_report];
740        let expected_events = vec![testing_utilities::create_mouse_event(
741            MouseLocation::Relative(Default::default()),
742            None, /* wheel_delta_v */
743            None, /* wheel_delta_h */
744            None, /* is_precision_scroll */
745            MousePhase::Down,
746            SortedVecSet::from(vec![mouse_button]),
747            SortedVecSet::from(vec![mouse_button]),
748            event_time_u64,
749            &descriptor,
750        )];
751
752        assert_input_report_sequence_generates_events!(
753            input_reports: input_reports,
754            expected_events: expected_events,
755            device_descriptor: descriptor,
756            device_type: MouseBinding,
757        );
758    }
759
760    /// Tests that a report containing a new mouse button with movement generates a down event and a
761    /// move event.
762    #[fasync::run_singlethreaded(test)]
763    async fn down_with_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 { x: 10.0, y: 16.0 },
768            None, /* scroll_v */
769            None, /* scroll_h */
770            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![
777            testing_utilities::create_mouse_event(
778                MouseLocation::Relative(Default::default()),
779                None, /* wheel_delta_v */
780                None, /* wheel_delta_h */
781                None, /* is_precision_scroll */
782                MousePhase::Down,
783                SortedVecSet::from(vec![mouse_button]),
784                SortedVecSet::from(vec![mouse_button]),
785                event_time_u64,
786                &descriptor,
787            ),
788            testing_utilities::create_mouse_event(
789                MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
790                None, /* wheel_delta_v */
791                None, /* wheel_delta_h */
792                None, /* is_precision_scroll */
793                MousePhase::Move,
794                SortedVecSet::from(vec![mouse_button]),
795                SortedVecSet::from(vec![mouse_button]),
796                event_time_u64,
797                &descriptor,
798            ),
799        ];
800
801        assert_input_report_sequence_generates_events!(
802            input_reports: input_reports,
803            expected_events: expected_events,
804            device_descriptor: descriptor,
805            device_type: MouseBinding,
806        );
807    }
808
809    /// Tests that a press and release of a mouse button without movement generates a down and up event.
810    #[fasync::run_singlethreaded(test)]
811    async fn down_up() {
812        let button = 1;
813        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
814        let first_report = testing_utilities::create_mouse_input_report_relative(
815            Position::zero(),
816            None, /* scroll_v */
817            None, /* scroll_h */
818            vec![button],
819            event_time_i64,
820        );
821        let second_report = testing_utilities::create_mouse_input_report_relative(
822            Position::zero(),
823            None, /* scroll_v */
824            None, /* scroll_h */
825            vec![],
826            event_time_i64,
827        );
828        let descriptor = mouse_device_descriptor(DEVICE_ID);
829
830        let input_reports = vec![first_report, second_report];
831        let expected_events = vec![
832            testing_utilities::create_mouse_event(
833                MouseLocation::Relative(Default::default()),
834                None, /* wheel_delta_v */
835                None, /* wheel_delta_h */
836                None, /* is_precision_scroll */
837                MousePhase::Down,
838                SortedVecSet::from(vec![button]),
839                SortedVecSet::from(vec![button]),
840                event_time_u64,
841                &descriptor,
842            ),
843            testing_utilities::create_mouse_event(
844                MouseLocation::Relative(Default::default()),
845                None, /* wheel_delta_v */
846                None, /* wheel_delta_h */
847                None, /* is_precision_scroll */
848                MousePhase::Up,
849                SortedVecSet::from(vec![button]),
850                SortedVecSet::new(),
851                event_time_u64,
852                &descriptor,
853            ),
854        ];
855
856        assert_input_report_sequence_generates_events!(
857            input_reports: input_reports,
858            expected_events: expected_events,
859            device_descriptor: descriptor,
860            device_type: MouseBinding,
861        );
862    }
863
864    /// Tests that a press and release of a mouse button with movement generates down, move, and up events.
865    #[fasync::run_singlethreaded(test)]
866    async fn down_up_with_movement() {
867        let button = 1;
868
869        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
870        let first_report = testing_utilities::create_mouse_input_report_relative(
871            Position::zero(),
872            None, /* scroll_v */
873            None, /* scroll_h */
874            vec![button],
875            event_time_i64,
876        );
877        let second_report = testing_utilities::create_mouse_input_report_relative(
878            Position { x: 10.0, y: 16.0 },
879            None, /* scroll_v */
880            None, /* scroll_h */
881            vec![],
882            event_time_i64,
883        );
884        let descriptor = mouse_device_descriptor(DEVICE_ID);
885
886        let input_reports = vec![first_report, second_report];
887        let expected_events = vec![
888            testing_utilities::create_mouse_event(
889                MouseLocation::Relative(Default::default()),
890                None, /* wheel_delta_v */
891                None, /* wheel_delta_h */
892                None, /* is_precision_scroll */
893                MousePhase::Down,
894                SortedVecSet::from(vec![button]),
895                SortedVecSet::from(vec![button]),
896                event_time_u64,
897                &descriptor,
898            ),
899            testing_utilities::create_mouse_event(
900                MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
901                None, /* wheel_delta_v */
902                None, /* wheel_delta_h */
903                None, /* is_precision_scroll */
904                MousePhase::Move,
905                SortedVecSet::from(vec![button]),
906                SortedVecSet::from(vec![button]),
907                event_time_u64,
908                &descriptor,
909            ),
910            testing_utilities::create_mouse_event(
911                MouseLocation::Relative(Default::default()),
912                None, /* wheel_delta_v */
913                None, /* wheel_delta_h */
914                None, /* is_precision_scroll */
915                MousePhase::Up,
916                SortedVecSet::from(vec![button]),
917                SortedVecSet::new(),
918                event_time_u64,
919                &descriptor,
920            ),
921        ];
922
923        assert_input_report_sequence_generates_events!(
924            input_reports: input_reports,
925            expected_events: expected_events,
926            device_descriptor: descriptor,
927            device_type: MouseBinding,
928        );
929    }
930
931    /// Tests that a press, move, and release of a button generates down, move, and up events.
932    /// This specifically tests the separate input report containing the movement, instead of sending
933    /// the movement as part of the down or up events.
934    #[fasync::run_singlethreaded(test)]
935    async fn down_move_up() {
936        let button = 1;
937
938        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
939        let first_report = testing_utilities::create_mouse_input_report_relative(
940            Position::zero(),
941            None, /* scroll_v */
942            None, /* scroll_h */
943            vec![button],
944            event_time_i64,
945        );
946        let second_report = testing_utilities::create_mouse_input_report_relative(
947            Position { x: 10.0, y: 16.0 },
948            None, /* scroll_v */
949            None, /* scroll_h */
950            vec![button],
951            event_time_i64,
952        );
953        let third_report = testing_utilities::create_mouse_input_report_relative(
954            Position::zero(),
955            None, /* scroll_v */
956            None, /* scroll_h */
957            vec![],
958            event_time_i64,
959        );
960        let descriptor = mouse_device_descriptor(DEVICE_ID);
961
962        let input_reports = vec![first_report, second_report, third_report];
963        let expected_events = vec![
964            testing_utilities::create_mouse_event(
965                MouseLocation::Relative(Default::default()),
966                None, /* wheel_delta_v */
967                None, /* wheel_delta_h */
968                None, /* is_precision_scroll */
969                MousePhase::Down,
970                SortedVecSet::from(vec![button]),
971                SortedVecSet::from(vec![button]),
972                event_time_u64,
973                &descriptor,
974            ),
975            testing_utilities::create_mouse_event(
976                MouseLocation::Relative(RelativeLocation { counts: Position { x: 10.0, y: 16.0 } }),
977                None, /* wheel_delta_v */
978                None, /* wheel_delta_h */
979                None, /* is_precision_scroll */
980                MousePhase::Move,
981                SortedVecSet::from(vec![button]),
982                SortedVecSet::from(vec![button]),
983                event_time_u64,
984                &descriptor,
985            ),
986            testing_utilities::create_mouse_event(
987                MouseLocation::Relative(Default::default()),
988                None, /* wheel_delta_v */
989                None, /* wheel_delta_h */
990                None, /* is_precision_scroll */
991                MousePhase::Up,
992                SortedVecSet::from(vec![button]),
993                SortedVecSet::new(),
994                event_time_u64,
995                &descriptor,
996            ),
997        ];
998
999        assert_input_report_sequence_generates_events!(
1000            input_reports: input_reports,
1001            expected_events: expected_events,
1002            device_descriptor: descriptor,
1003            device_type: MouseBinding,
1004        );
1005    }
1006
1007    /// Tests that a report with absolute movement to {0, 0} generates a move event.
1008    #[fasync::run_until_stalled(test)]
1009    async fn absolute_movement_to_origin() {
1010        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1011        let descriptor = mouse_device_descriptor(DEVICE_ID);
1012
1013        let input_reports = vec![testing_utilities::create_mouse_input_report_absolute(
1014            Position::zero(),
1015            None, /* wheel_delta_v */
1016            None, /* wheel_delta_h */
1017            vec![],
1018            event_time_i64,
1019        )];
1020        let expected_events = vec![testing_utilities::create_mouse_event(
1021            MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1022            None, /* wheel_delta_v */
1023            None, /* wheel_delta_h */
1024            None, /* is_precision_scroll */
1025            MousePhase::Move,
1026            SortedVecSet::new(),
1027            SortedVecSet::new(),
1028            event_time_u64,
1029            &descriptor,
1030        )];
1031
1032        assert_input_report_sequence_generates_events!(
1033            input_reports: input_reports,
1034            expected_events: expected_events,
1035            device_descriptor: descriptor,
1036            device_type: MouseBinding,
1037        );
1038    }
1039
1040    /// Tests that a report that contains both a relative movement and absolute position
1041    /// generates a move event to the absolute position.
1042    #[fasync::run_until_stalled(test)]
1043    async fn report_with_both_movement_and_position() {
1044        let relative_movement = Position { x: 5.0, y: 5.0 };
1045        let absolute_position = Position { x: 10.0, y: 10.0 };
1046        let expected_location = MouseLocation::Absolute(absolute_position);
1047
1048        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1049        let descriptor = mouse_device_descriptor(DEVICE_ID);
1050
1051        let input_reports = vec![fidl_next_fuchsia_input_report::InputReport {
1052            event_time: Some(event_time_i64),
1053            keyboard: None,
1054            mouse: Some(fidl_next_fuchsia_input_report::MouseInputReport {
1055                movement_x: Some(relative_movement.x as i64),
1056                movement_y: Some(relative_movement.y as i64),
1057                position_x: Some(absolute_position.x as i64),
1058                position_y: Some(absolute_position.y as i64),
1059                scroll_h: None,
1060                scroll_v: None,
1061                pressed_buttons: None,
1062                ..Default::default()
1063            }),
1064            touch: None,
1065            sensor: None,
1066            consumer_control: None,
1067            trace_id: None,
1068            ..Default::default()
1069        }];
1070        let expected_events = vec![testing_utilities::create_mouse_event(
1071            expected_location,
1072            None, /* wheel_delta_v */
1073            None, /* wheel_delta_h */
1074            None, /* is_precision_scroll */
1075            MousePhase::Move,
1076            SortedVecSet::new(),
1077            SortedVecSet::new(),
1078            event_time_u64,
1079            &descriptor,
1080        )];
1081
1082        assert_input_report_sequence_generates_events!(
1083            input_reports: input_reports,
1084            expected_events: expected_events,
1085            device_descriptor: descriptor,
1086            device_type: MouseBinding,
1087        );
1088    }
1089
1090    /// Tests that two separate button presses generate two separate down events with differing
1091    /// sets of `affected_buttons` and `pressed_buttons`.
1092    #[fasync::run_singlethreaded(test)]
1093    async fn down_down() {
1094        const PRIMARY_BUTTON: u8 = 1;
1095        const SECONDARY_BUTTON: u8 = 2;
1096
1097        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1098        let first_report = testing_utilities::create_mouse_input_report_relative(
1099            Position::zero(),
1100            None, /* scroll_v */
1101            None, /* scroll_h */
1102            vec![PRIMARY_BUTTON],
1103            event_time_i64,
1104        );
1105        let second_report = testing_utilities::create_mouse_input_report_relative(
1106            Position::zero(),
1107            None, /* scroll_v */
1108            None, /* scroll_h */
1109            vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1110            event_time_i64,
1111        );
1112        let descriptor = mouse_device_descriptor(DEVICE_ID);
1113
1114        let input_reports = vec![first_report, second_report];
1115        let expected_events = vec![
1116            testing_utilities::create_mouse_event(
1117                MouseLocation::Relative(Default::default()),
1118                None, /* wheel_delta_v */
1119                None, /* wheel_delta_h */
1120                None, /* is_precision_scroll */
1121                MousePhase::Down,
1122                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1123                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1124                event_time_u64,
1125                &descriptor,
1126            ),
1127            testing_utilities::create_mouse_event(
1128                MouseLocation::Relative(Default::default()),
1129                None, /* wheel_delta_v */
1130                None, /* wheel_delta_h */
1131                None, /* is_precision_scroll */
1132                MousePhase::Down,
1133                SortedVecSet::from(vec![SECONDARY_BUTTON]),
1134                SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1135                event_time_u64,
1136                &descriptor,
1137            ),
1138        ];
1139
1140        assert_input_report_sequence_generates_events!(
1141            input_reports: input_reports,
1142            expected_events: expected_events,
1143            device_descriptor: descriptor,
1144            device_type: MouseBinding,
1145        );
1146    }
1147
1148    /// Tests that two staggered button presses followed by stagged releases generate four mouse
1149    /// events with distinct `affected_buttons` and `pressed_buttons`.
1150    /// Specifically, we test and expect the following in order:
1151    /// | Action           | MousePhase | `affected_buttons` | `pressed_buttons` |
1152    /// | ---------------- | ---------- | ------------------ | ----------------- |
1153    /// | Press button 1   | Down       | [1]                | [1]               |
1154    /// | Press button 2   | Down       | [2]                | [1, 2]            |
1155    /// | Release button 1 | Up         | [1]                | [2]               |
1156    /// | Release button 2 | Up         | [2]                | []                |
1157    #[fasync::run_singlethreaded(test)]
1158    async fn down_down_up_up() {
1159        const PRIMARY_BUTTON: u8 = 1;
1160        const SECONDARY_BUTTON: u8 = 2;
1161
1162        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1163        let first_report = testing_utilities::create_mouse_input_report_relative(
1164            Position::zero(),
1165            None, /* scroll_v */
1166            None, /* scroll_h */
1167            vec![PRIMARY_BUTTON],
1168            event_time_i64,
1169        );
1170        let second_report = testing_utilities::create_mouse_input_report_relative(
1171            Position::zero(),
1172            None, /* scroll_v */
1173            None, /* scroll_h */
1174            vec![PRIMARY_BUTTON, SECONDARY_BUTTON],
1175            event_time_i64,
1176        );
1177        let third_report = testing_utilities::create_mouse_input_report_relative(
1178            Position::zero(),
1179            None, /* scroll_v */
1180            None, /* scroll_h */
1181            vec![SECONDARY_BUTTON],
1182            event_time_i64,
1183        );
1184        let fourth_report = testing_utilities::create_mouse_input_report_relative(
1185            Position::zero(),
1186            None, /* scroll_v */
1187            None, /* scroll_h */
1188            vec![],
1189            event_time_i64,
1190        );
1191        let descriptor = mouse_device_descriptor(DEVICE_ID);
1192
1193        let input_reports = vec![first_report, second_report, third_report, fourth_report];
1194        let expected_events = vec![
1195            testing_utilities::create_mouse_event(
1196                MouseLocation::Relative(Default::default()),
1197                None, /* wheel_delta_v */
1198                None, /* wheel_delta_h */
1199                None, /* is_precision_scroll */
1200                MousePhase::Down,
1201                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1202                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1203                event_time_u64,
1204                &descriptor,
1205            ),
1206            testing_utilities::create_mouse_event(
1207                MouseLocation::Relative(Default::default()),
1208                None, /* wheel_delta_v */
1209                None, /* wheel_delta_h */
1210                None, /* is_precision_scroll */
1211                MousePhase::Down,
1212                SortedVecSet::from(vec![SECONDARY_BUTTON]),
1213                SortedVecSet::from(vec![PRIMARY_BUTTON, SECONDARY_BUTTON]),
1214                event_time_u64,
1215                &descriptor,
1216            ),
1217            testing_utilities::create_mouse_event(
1218                MouseLocation::Relative(Default::default()),
1219                None, /* wheel_delta_v */
1220                None, /* wheel_delta_h */
1221                None, /* is_precision_scroll */
1222                MousePhase::Up,
1223                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1224                SortedVecSet::from(vec![SECONDARY_BUTTON]),
1225                event_time_u64,
1226                &descriptor,
1227            ),
1228            testing_utilities::create_mouse_event(
1229                MouseLocation::Relative(Default::default()),
1230                None, /* wheel_delta_v */
1231                None, /* wheel_delta_h */
1232                None, /* is_precision_scroll */
1233                MousePhase::Up,
1234                SortedVecSet::from(vec![SECONDARY_BUTTON]),
1235                SortedVecSet::new(),
1236                event_time_u64,
1237                &descriptor,
1238            ),
1239        ];
1240
1241        assert_input_report_sequence_generates_events!(
1242            input_reports: input_reports,
1243            expected_events: expected_events,
1244            device_descriptor: descriptor,
1245            device_type: MouseBinding,
1246        );
1247    }
1248
1249    /// Test simple scroll in vertical and horizontal.
1250    #[fasync::run_singlethreaded(test)]
1251    async fn scroll() {
1252        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1253        let first_report = testing_utilities::create_mouse_input_report_relative(
1254            Position::zero(),
1255            Some(1),
1256            None,
1257            vec![],
1258            event_time_i64,
1259        );
1260        let second_report = testing_utilities::create_mouse_input_report_relative(
1261            Position::zero(),
1262            None,
1263            Some(1),
1264            vec![],
1265            event_time_i64,
1266        );
1267
1268        let descriptor = mouse_device_descriptor(DEVICE_ID);
1269
1270        let input_reports = vec![first_report, second_report];
1271        let expected_events = vec![
1272            testing_utilities::create_mouse_event(
1273                MouseLocation::Relative(Default::default()),
1274                wheel_delta_ticks(1),
1275                None,
1276                Some(PrecisionScroll::No),
1277                MousePhase::Wheel,
1278                SortedVecSet::new(),
1279                SortedVecSet::new(),
1280                event_time_u64,
1281                &descriptor,
1282            ),
1283            testing_utilities::create_mouse_event(
1284                MouseLocation::Relative(Default::default()),
1285                None,
1286                wheel_delta_ticks(1),
1287                Some(PrecisionScroll::No),
1288                MousePhase::Wheel,
1289                SortedVecSet::new(),
1290                SortedVecSet::new(),
1291                event_time_u64,
1292                &descriptor,
1293            ),
1294        ];
1295
1296        assert_input_report_sequence_generates_events!(
1297            input_reports: input_reports,
1298            expected_events: expected_events,
1299            device_descriptor: descriptor,
1300            device_type: MouseBinding,
1301        );
1302    }
1303
1304    /// Test button down -> scroll -> button up -> continue scroll.
1305    #[fasync::run_singlethreaded(test)]
1306    async fn down_scroll_up_scroll() {
1307        const PRIMARY_BUTTON: u8 = 1;
1308
1309        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1310        let first_report = testing_utilities::create_mouse_input_report_relative(
1311            Position::zero(),
1312            None, /* scroll_v */
1313            None, /* scroll_h */
1314            vec![PRIMARY_BUTTON],
1315            event_time_i64,
1316        );
1317        let second_report = testing_utilities::create_mouse_input_report_relative(
1318            Position::zero(),
1319            Some(1),
1320            None,
1321            vec![PRIMARY_BUTTON],
1322            event_time_i64,
1323        );
1324        let third_report = testing_utilities::create_mouse_input_report_relative(
1325            Position::zero(),
1326            None, /* scroll_v */
1327            None, /* scroll_h */
1328            vec![],
1329            event_time_i64,
1330        );
1331        let fourth_report = testing_utilities::create_mouse_input_report_relative(
1332            Position::zero(),
1333            Some(1),
1334            None,
1335            vec![],
1336            event_time_i64,
1337        );
1338
1339        let descriptor = mouse_device_descriptor(DEVICE_ID);
1340
1341        let input_reports = vec![first_report, second_report, third_report, fourth_report];
1342        let expected_events = vec![
1343            testing_utilities::create_mouse_event(
1344                MouseLocation::Relative(Default::default()),
1345                None, /* wheel_delta_v */
1346                None, /* wheel_delta_h */
1347                None, /* is_precision_scroll */
1348                MousePhase::Down,
1349                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1350                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1351                event_time_u64,
1352                &descriptor,
1353            ),
1354            testing_utilities::create_mouse_event(
1355                MouseLocation::Relative(Default::default()),
1356                wheel_delta_ticks(1),
1357                None,
1358                Some(PrecisionScroll::No),
1359                MousePhase::Wheel,
1360                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1361                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1362                event_time_u64,
1363                &descriptor,
1364            ),
1365            testing_utilities::create_mouse_event(
1366                MouseLocation::Relative(Default::default()),
1367                None, /* wheel_delta_v */
1368                None, /* wheel_delta_h */
1369                None, /* is_precision_scroll */
1370                MousePhase::Up,
1371                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1372                SortedVecSet::new(),
1373                event_time_u64,
1374                &descriptor,
1375            ),
1376            testing_utilities::create_mouse_event(
1377                MouseLocation::Relative(Default::default()),
1378                wheel_delta_ticks(1),
1379                None,
1380                Some(PrecisionScroll::No),
1381                MousePhase::Wheel,
1382                SortedVecSet::new(),
1383                SortedVecSet::new(),
1384                event_time_u64,
1385                &descriptor,
1386            ),
1387        ];
1388
1389        assert_input_report_sequence_generates_events!(
1390            input_reports: input_reports,
1391            expected_events: expected_events,
1392            device_descriptor: descriptor,
1393            device_type: MouseBinding,
1394        );
1395    }
1396
1397    /// Test button down with scroll -> button up with scroll -> scroll.
1398    #[fasync::run_singlethreaded(test)]
1399    async fn down_scroll_bundle_up_scroll_bundle() {
1400        const PRIMARY_BUTTON: u8 = 1;
1401
1402        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1403        let first_report = testing_utilities::create_mouse_input_report_relative(
1404            Position::zero(),
1405            Some(1),
1406            None,
1407            vec![PRIMARY_BUTTON],
1408            event_time_i64,
1409        );
1410        let second_report = testing_utilities::create_mouse_input_report_relative(
1411            Position::zero(),
1412            Some(1),
1413            None,
1414            vec![],
1415            event_time_i64,
1416        );
1417        let third_report = testing_utilities::create_mouse_input_report_relative(
1418            Position::zero(),
1419            Some(1),
1420            None,
1421            vec![],
1422            event_time_i64,
1423        );
1424
1425        let descriptor = mouse_device_descriptor(DEVICE_ID);
1426
1427        let input_reports = vec![first_report, second_report, third_report];
1428        let expected_events = vec![
1429            testing_utilities::create_mouse_event(
1430                MouseLocation::Relative(Default::default()),
1431                None, /* wheel_delta_v */
1432                None, /* wheel_delta_h */
1433                None, /* is_precision_scroll */
1434                MousePhase::Down,
1435                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1436                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1437                event_time_u64,
1438                &descriptor,
1439            ),
1440            testing_utilities::create_mouse_event(
1441                MouseLocation::Relative(Default::default()),
1442                wheel_delta_ticks(1),
1443                None,
1444                Some(PrecisionScroll::No),
1445                MousePhase::Wheel,
1446                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1447                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1448                event_time_u64,
1449                &descriptor,
1450            ),
1451            testing_utilities::create_mouse_event(
1452                MouseLocation::Relative(Default::default()),
1453                wheel_delta_ticks(1),
1454                None,
1455                Some(PrecisionScroll::No),
1456                MousePhase::Wheel,
1457                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1458                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1459                event_time_u64,
1460                &descriptor,
1461            ),
1462            testing_utilities::create_mouse_event(
1463                MouseLocation::Relative(Default::default()),
1464                None, /* wheel_delta_v */
1465                None, /* wheel_delta_h */
1466                None, /* is_precision_scroll */
1467                MousePhase::Up,
1468                SortedVecSet::from(vec![PRIMARY_BUTTON]),
1469                SortedVecSet::new(),
1470                event_time_u64,
1471                &descriptor,
1472            ),
1473            testing_utilities::create_mouse_event(
1474                MouseLocation::Relative(Default::default()),
1475                wheel_delta_ticks(1),
1476                None,
1477                Some(PrecisionScroll::No),
1478                MousePhase::Wheel,
1479                SortedVecSet::new(),
1480                SortedVecSet::new(),
1481                event_time_u64,
1482                &descriptor,
1483            ),
1484        ];
1485
1486        assert_input_report_sequence_generates_events!(
1487            input_reports: input_reports,
1488            expected_events: expected_events,
1489            device_descriptor: descriptor,
1490            device_type: MouseBinding,
1491        );
1492    }
1493}