input_pipeline/
mouse_injector_handler.rs

1// Copyright 2021 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
5#![warn(clippy::await_holding_refcell_ref)]
6
7use crate::input_handler::{InputHandler, InputHandlerStatus};
8use crate::utils::{CursorMessage, Position, Size};
9use crate::{input_device, metrics, mouse_binding};
10use anyhow::{Context, Error, Result, anyhow};
11use async_trait::async_trait;
12use async_utils::hanging_get::client::HangingGetStream;
13use fidl::endpoints::create_proxy;
14use fidl_fuchsia_input_report::Range;
15use fuchsia_component::client::connect_to_protocol;
16use fuchsia_inspect::health::Reporter;
17use futures::SinkExt;
18use futures::channel::mpsc::Sender;
19use futures::stream::StreamExt;
20use metrics_registry::*;
21use std::cell::{Ref, RefCell, RefMut};
22use std::collections::HashMap;
23use std::rc::Rc;
24use {
25    fidl_fuchsia_ui_pointerinjector as pointerinjector,
26    fidl_fuchsia_ui_pointerinjector_configuration as pointerinjector_config,
27};
28
29/// Each mm of physical movement by the mouse translates to the cursor moving
30/// on the display by 10 logical pixels.
31/// Because pointer_display_scale_handler scaled for device pixel ratio, here
32/// only need to apply mm * logical pixel scale factor to get physical pixel.
33/// TODO(https://fxbug.dev/42066909): need to revisit this
34/// 1. allow users to adjust how fast the mouse move.
35/// 2. allow different value per monitor model.
36const MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL: f32 = 10.0;
37
38/// A [`MouseInjectorHandler`] parses mouse events and forwards them to Scenic through the
39/// fidl_fuchsia_pointerinjector protocols.
40pub struct MouseInjectorHandler {
41    /// The mutable fields of this handler.
42    mutable_state: RefCell<MutableState>,
43
44    /// The scope and coordinate system of injection.
45    /// See [`fidl_fuchsia_pointerinjector::Context`] for more details.
46    context_view_ref: fidl_fuchsia_ui_views::ViewRef,
47
48    /// The region where dispatch is attempted for injected events.
49    /// See [`fidl_fuchsia_pointerinjector::Target`] for more details.
50    target_view_ref: fidl_fuchsia_ui_views::ViewRef,
51
52    /// The maximum position sent to clients, used to bound relative movements
53    /// and scale absolute positions from device coordinates.
54    max_position: Position,
55
56    /// The FIDL proxy to register new injectors.
57    injector_registry_proxy: pointerinjector::RegistryProxy,
58
59    /// The FIDL proxy used to get configuration details for pointer injection.
60    configuration_proxy: pointerinjector_config::SetupProxy,
61
62    /// The inventory of this handler's Inspect status.
63    pub inspect_status: InputHandlerStatus,
64
65    metrics_logger: metrics::MetricsLogger,
66}
67
68struct MutableState {
69    /// A rectangular region that directs injected events into a target.
70    /// See fidl_fuchsia_pointerinjector::Viewport for more details.
71    viewport: Option<pointerinjector::Viewport>,
72
73    /// The injectors registered with Scenic, indexed by their device ids.
74    injectors: HashMap<u32, pointerinjector::DeviceProxy>,
75
76    /// The current position.
77    current_position: Position,
78
79    /// A [`Sender`] used to communicate the current cursor state.
80    cursor_message_sender: Sender<CursorMessage>,
81}
82
83#[async_trait(?Send)]
84impl InputHandler for MouseInjectorHandler {
85    async fn handle_input_event(
86        self: Rc<Self>,
87        mut input_event: input_device::InputEvent,
88    ) -> Vec<input_device::InputEvent> {
89        fuchsia_trace::duration!("input", "mouse_injector_handler");
90        match input_event {
91            input_device::InputEvent {
92                device_event: input_device::InputDeviceEvent::Mouse(ref mouse_event),
93                device_descriptor:
94                    input_device::InputDeviceDescriptor::Mouse(ref mouse_device_descriptor),
95                event_time,
96                handled: input_device::Handled::No,
97                trace_id,
98            } => {
99                fuchsia_trace::duration!("input", "mouse_injector_handler[processing]");
100                let trace_id = match trace_id {
101                    Some(id) => {
102                        fuchsia_trace::flow_end!("input", "event_in_input_pipeline", id.into());
103                        id
104                    }
105                    None => fuchsia_trace::Id::random(),
106                };
107
108                self.inspect_status.count_received_event(&event_time);
109                // TODO(https://fxbug.dev/42171756): Investigate latency introduced by waiting for update_cursor_renderer
110                if let Err(e) =
111                    self.update_cursor_renderer(mouse_event, &mouse_device_descriptor).await
112                {
113                    self.metrics_logger.log_error(
114                        InputPipelineErrorMetricDimensionEvent::MouseInjectorUpdateCursorRendererFailed,
115                        std::format!("update_cursor_renderer failed: {}", e));
116                }
117
118                // Create a new injector if this is the first time seeing device_id.
119                if let Err(e) = self
120                    .ensure_injector_registered(&mouse_event, &mouse_device_descriptor, event_time)
121                    .await
122                {
123                    self.metrics_logger.log_error(
124                        InputPipelineErrorMetricDimensionEvent::MouseInjectorEnsureInjectorRegisteredFailed,
125                        std::format!("ensure_injector_registered failed: {}", e));
126                }
127
128                // Handle the event.
129                if let Err(e) = self
130                    .send_event_to_scenic(
131                        &mouse_event,
132                        &mouse_device_descriptor,
133                        event_time,
134                        trace_id.into(),
135                    )
136                    .await
137                {
138                    self.metrics_logger.log_error(
139                        InputPipelineErrorMetricDimensionEvent::MouseInjectorSendEventToScenicFailed,
140                        std::format!("send_event_to_scenic failed: {}", e));
141                }
142
143                // Consume the input event.
144                input_event.handled = input_device::Handled::Yes;
145                self.inspect_status.count_handled_event();
146            }
147            _ => {
148                // TODO: b/478249522 - add cobalt logging
149                log::warn!("Unhandled input event: {:?}", input_event.get_event_type());
150            }
151        }
152        vec![input_event]
153    }
154
155    fn set_handler_healthy(self: std::rc::Rc<Self>) {
156        self.inspect_status.health_node.borrow_mut().set_ok();
157    }
158
159    fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
160        self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
161    }
162
163    fn get_name(&self) -> &'static str {
164        "MouseInjectorHandler"
165    }
166
167    fn interest(&self) -> Vec<input_device::InputEventType> {
168        vec![input_device::InputEventType::Mouse]
169    }
170}
171
172impl MouseInjectorHandler {
173    /// Creates a new mouse handler that holds mouse pointer injectors.
174    /// The caller is expected to spawn a task to continually watch for updates to the viewport.
175    /// Example:
176    /// let handler = MouseInjectorHandler::new(display_size).await?;
177    /// fasync::Task::local(handler.clone().watch_viewport()).detach();
178    ///
179    /// # Parameters
180    /// - `display_size`: The size of the associated display.
181    /// - `cursor_message_sender`: A [`Sender`] used to communicate the current cursor state.
182    ///
183    /// # Errors
184    /// If unable to connect to pointerinjector protocols.
185    pub async fn new(
186        display_size: Size,
187        cursor_message_sender: Sender<CursorMessage>,
188        input_handlers_node: &fuchsia_inspect::Node,
189        metrics_logger: metrics::MetricsLogger,
190    ) -> Result<Rc<Self>, Error> {
191        let configuration_proxy = connect_to_protocol::<pointerinjector_config::SetupMarker>()?;
192        let injector_registry_proxy = connect_to_protocol::<pointerinjector::RegistryMarker>()?;
193
194        Self::new_handler(
195            configuration_proxy,
196            injector_registry_proxy,
197            display_size,
198            cursor_message_sender,
199            input_handlers_node,
200            metrics_logger,
201        )
202        .await
203    }
204
205    /// Creates a new mouse handler that holds mouse pointer injectors.
206    /// The caller is expected to spawn a task to continually watch for updates to the viewport.
207    /// Example:
208    /// let handler = MouseInjectorHandler::new_with_config_proxy(config_proxy, display_size).await?;
209    /// fasync::Task::local(handler.clone().watch_viewport()).detach();
210    ///
211    /// # Parameters
212    /// - `configuration_proxy`: A proxy used to get configuration details for pointer
213    ///    injection.
214    /// - `display_size`: The size of the associated display.
215    /// - `cursor_message_sender`: A [`Sender`] used to communicate the current cursor state.
216    ///
217    /// # Errors
218    /// If unable to get injection view refs from `configuration_proxy`.
219    /// If unable to connect to pointerinjector Registry protocol.
220    pub async fn new_with_config_proxy(
221        configuration_proxy: pointerinjector_config::SetupProxy,
222        display_size: Size,
223        cursor_message_sender: Sender<CursorMessage>,
224        input_handlers_node: &fuchsia_inspect::Node,
225        metrics_logger: metrics::MetricsLogger,
226    ) -> Result<Rc<Self>, Error> {
227        let injector_registry_proxy = connect_to_protocol::<pointerinjector::RegistryMarker>()?;
228        Self::new_handler(
229            configuration_proxy,
230            injector_registry_proxy,
231            display_size,
232            cursor_message_sender,
233            input_handlers_node,
234            metrics_logger,
235        )
236        .await
237    }
238
239    fn inner(&self) -> Ref<'_, MutableState> {
240        self.mutable_state.borrow()
241    }
242
243    fn inner_mut(&self) -> RefMut<'_, MutableState> {
244        self.mutable_state.borrow_mut()
245    }
246
247    /// Creates a new mouse handler that holds mouse pointer injectors.
248    /// The caller is expected to spawn a task to continually watch for updates to the viewport.
249    /// Example:
250    /// let handler = MouseInjectorHandler::new_handler(None, None, display_size).await?;
251    /// fasync::Task::local(handler.clone().watch_viewport()).detach();
252    ///
253    /// # Parameters
254    /// - `configuration_proxy`: A proxy used to get configuration details for pointer
255    ///    injection.
256    /// - `injector_registry_proxy`: A proxy used to register new pointer injectors.
257    /// - `display_size`: The size of the associated display.
258    /// - `cursor_message_sender`: A [`Sender`] used to communicate the current cursor state.
259    ///
260    /// # Errors
261    /// If unable to get injection view refs from `configuration_proxy`.
262    async fn new_handler(
263        configuration_proxy: pointerinjector_config::SetupProxy,
264        injector_registry_proxy: pointerinjector::RegistryProxy,
265        display_size: Size,
266        cursor_message_sender: Sender<CursorMessage>,
267        input_handlers_node: &fuchsia_inspect::Node,
268        metrics_logger: metrics::MetricsLogger,
269    ) -> Result<Rc<Self>, Error> {
270        // Get the context and target views to inject into.
271        let (context_view_ref, target_view_ref) = configuration_proxy.get_view_refs().await?;
272        let inspect_status = InputHandlerStatus::new(
273            input_handlers_node,
274            "mouse_injector_handler",
275            /* generates_events */ false,
276        );
277        let handler = Rc::new(Self {
278            mutable_state: RefCell::new(MutableState {
279                viewport: None,
280                injectors: HashMap::new(),
281                // Initially centered.
282                current_position: Position {
283                    x: display_size.width / 2.0,
284                    y: display_size.height / 2.0,
285                },
286                cursor_message_sender,
287            }),
288            context_view_ref,
289            target_view_ref,
290            max_position: Position { x: display_size.width, y: display_size.height },
291            injector_registry_proxy,
292            configuration_proxy,
293            inspect_status,
294            metrics_logger,
295        });
296
297        Ok(handler)
298    }
299
300    /// Adds a new pointer injector and tracks it in `self.injectors` if one doesn't exist at
301    /// `mouse_descriptor.device_id`.
302    ///
303    /// # Parameters
304    /// - `mouse_event`: The mouse event to send to Scenic.
305    /// - `mouse_descriptor`: The descriptor for the device that sent the mouse event.
306    /// - `event_time`: The time in nanoseconds when the event was first recorded.
307    async fn ensure_injector_registered(
308        self: &Rc<Self>,
309        mouse_event: &mouse_binding::MouseEvent,
310        mouse_descriptor: &mouse_binding::MouseDeviceDescriptor,
311        event_time: zx::MonotonicInstant,
312    ) -> Result<(), anyhow::Error> {
313        if self.inner().injectors.contains_key(&mouse_descriptor.device_id) {
314            return Ok(());
315        }
316
317        // Create a new injector.
318        let (device_proxy, device_server) = create_proxy::<pointerinjector::DeviceMarker>();
319        let context = fuchsia_scenic::duplicate_view_ref(&self.context_view_ref)
320            .context("Failed to duplicate context view ref.")?;
321        let target = fuchsia_scenic::duplicate_view_ref(&self.target_view_ref)
322            .context("Failed to duplicate target view ref.")?;
323
324        let viewport = self.inner().viewport.clone();
325        let config = pointerinjector::Config {
326            device_id: Some(mouse_descriptor.device_id),
327            device_type: Some(pointerinjector::DeviceType::Mouse),
328            context: Some(pointerinjector::Context::View(context)),
329            target: Some(pointerinjector::Target::View(target)),
330            viewport,
331            dispatch_policy: Some(pointerinjector::DispatchPolicy::MouseHoverAndLatchInTarget),
332            scroll_v_range: mouse_descriptor.wheel_v_range.clone(),
333            scroll_h_range: mouse_descriptor.wheel_h_range.clone(),
334            buttons: mouse_descriptor.buttons.clone(),
335            ..Default::default()
336        };
337
338        // Register the new injector.
339        self.injector_registry_proxy
340            .register(config, device_server)
341            .await
342            .context("Failed to register injector.")?;
343        log::info!("Registered injector with device id {:?}", mouse_descriptor.device_id);
344
345        // Keep track of the injector.
346        self.inner_mut().injectors.insert(mouse_descriptor.device_id, device_proxy.clone());
347
348        // Inject ADD event the first time a MouseDevice is seen.
349        let events_to_send = vec![self.create_pointer_sample_event(
350            mouse_event,
351            event_time,
352            pointerinjector::EventPhase::Add,
353            self.inner().current_position,
354            None,
355            None,
356        )];
357        device_proxy.inject_events(events_to_send).context("Failed to ADD new MouseDevice.")?;
358
359        Ok(())
360    }
361
362    /// Updates the current cursor position according to the received mouse event.
363    ///
364    /// The updated cursor state is sent via `self.inner.cursor_message_sender` to a client
365    /// that renders the cursor on-screen.
366    ///
367    /// If there is no movement, the location is not sent.
368    ///
369    /// # Parameters
370    /// - `mouse_event`: The mouse event to use to update the cursor location.
371    /// - `mouse_descriptor`: The descriptor for the input device generating the input reports.
372    async fn update_cursor_renderer(
373        &self,
374        mouse_event: &mouse_binding::MouseEvent,
375        mouse_descriptor: &mouse_binding::MouseDeviceDescriptor,
376    ) -> Result<(), anyhow::Error> {
377        let mut new_position = match (mouse_event.location, mouse_descriptor) {
378            (
379                mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
380                    millimeters,
381                }),
382                _,
383            ) => {
384                self.inner().current_position
385                    + self.relative_movement_mm_to_phyical_pixel(millimeters)
386            }
387            (
388                mouse_binding::MouseLocation::Absolute(position),
389                mouse_binding::MouseDeviceDescriptor {
390                    absolute_x_range: Some(x_range),
391                    absolute_y_range: Some(y_range),
392                    ..
393                },
394            ) => self.scale_absolute_position(&position, &x_range, &y_range),
395            (mouse_binding::MouseLocation::Absolute(_), _) => {
396                return Err(anyhow!(
397                    "Received an Absolute mouse location without absolute device ranges."
398                ));
399            }
400        };
401        Position::clamp(&mut new_position, Position::zero(), self.max_position);
402        self.inner_mut().current_position = new_position;
403
404        let mut cursor_message_sender = self.inner().cursor_message_sender.clone();
405        cursor_message_sender
406            .send(CursorMessage::SetPosition(new_position))
407            .await
408            .context("Failed to send current mouse position to cursor renderer")?;
409
410        Ok(())
411    }
412
413    /// Returns an absolute cursor position scaled from device coordinates to the handler's
414    /// max position.
415    ///
416    /// # Parameters
417    /// - `position`: Absolute cursor position in device coordinates.
418    /// - `x_range`: The range of possible x values of absolute mouse positions.
419    /// - `y_range`: The range of possible y values of absolute mouse positions.
420    fn scale_absolute_position(
421        &self,
422        position: &Position,
423        x_range: &Range,
424        y_range: &Range,
425    ) -> Position {
426        let range_min = Position { x: x_range.min as f32, y: y_range.min as f32 };
427        let range_max = Position { x: x_range.max as f32, y: y_range.max as f32 };
428        self.max_position * ((*position - range_min) / (range_max - range_min))
429    }
430
431    /// Sends the given event to Scenic.
432    ///
433    /// # Parameters
434    /// - `mouse_event`: The mouse event to send to Scenic.
435    /// - `mouse_descriptor`: The descriptor for the device that sent the mouse event.
436    /// - `event_time`: The time in nanoseconds when the event was first recorded.
437    async fn send_event_to_scenic(
438        &self,
439        mouse_event: &mouse_binding::MouseEvent,
440        mouse_descriptor: &mouse_binding::MouseDeviceDescriptor,
441        event_time: zx::MonotonicInstant,
442        tracing_id: u64,
443    ) -> Result<(), anyhow::Error> {
444        let injector = self.inner().injectors.get(&mouse_descriptor.device_id).cloned();
445        if let Some(injector) = injector {
446            let relative_motion = match mouse_event.location {
447                mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
448                    millimeters: offset_mm,
449                }) if mouse_event.phase == mouse_binding::MousePhase::Move => {
450                    let offset = self.relative_movement_mm_to_phyical_pixel(offset_mm);
451                    Some([offset.x, offset.y])
452                }
453                _ => None,
454            };
455            let events_to_send = vec![self.create_pointer_sample_event(
456                mouse_event,
457                event_time,
458                pointerinjector::EventPhase::Change,
459                self.inner().current_position,
460                relative_motion,
461                Some(tracing_id),
462            )];
463
464            fuchsia_trace::flow_begin!("input", "dispatch_event_to_scenic", tracing_id.into());
465
466            let _ = injector.inject_events(events_to_send);
467
468            Ok(())
469        } else {
470            Err(anyhow::format_err!(
471                "No injector found for mouse device {}.",
472                mouse_descriptor.device_id
473            ))
474        }
475    }
476
477    /// Creates a [`fidl_fuchsia_ui_pointerinjector::Event`] representing the given MouseEvent.
478    ///
479    /// # Parameters
480    /// - `mouse_event`: The mouse event to send to Scenic.
481    /// - `event_time`: The time in nanoseconds when the event was first recorded.
482    /// - `phase`: The EventPhase to send to Scenic.
483    /// - `current_position`: The current cursor position.
484    /// - `relative_motion`: The relative motion to send to Scenic.
485    fn create_pointer_sample_event(
486        &self,
487        mouse_event: &mouse_binding::MouseEvent,
488        event_time: zx::MonotonicInstant,
489        phase: pointerinjector::EventPhase,
490        current_position: Position,
491        relative_motion: Option<[f32; 2]>,
492        trace_id: Option<u64>,
493    ) -> pointerinjector::Event {
494        let pointer_sample = pointerinjector::PointerSample {
495            pointer_id: Some(0),
496            phase: Some(phase),
497            position_in_viewport: Some([current_position.x, current_position.y]),
498            scroll_v: match mouse_event.wheel_delta_v {
499                Some(mouse_binding::WheelDelta {
500                    raw_data: mouse_binding::RawWheelDelta::Ticks(tick),
501                    ..
502                }) => Some(tick),
503                _ => None,
504            },
505            scroll_h: match mouse_event.wheel_delta_h {
506                Some(mouse_binding::WheelDelta {
507                    raw_data: mouse_binding::RawWheelDelta::Ticks(tick),
508                    ..
509                }) => Some(tick),
510                _ => None,
511            },
512            scroll_v_physical_pixel: match mouse_event.wheel_delta_v {
513                Some(mouse_binding::WheelDelta { physical_pixel: Some(pixel), .. }) => {
514                    Some(pixel.into())
515                }
516                _ => None,
517            },
518            scroll_h_physical_pixel: match mouse_event.wheel_delta_h {
519                Some(mouse_binding::WheelDelta { physical_pixel: Some(pixel), .. }) => {
520                    Some(pixel.into())
521                }
522                _ => None,
523            },
524            is_precision_scroll: match mouse_event.phase {
525                mouse_binding::MousePhase::Wheel => match mouse_event.is_precision_scroll {
526                    Some(mouse_binding::PrecisionScroll::Yes) => Some(true),
527                    Some(mouse_binding::PrecisionScroll::No) => Some(false),
528                    None => {
529                        self.metrics_logger.log_error(
530                            InputPipelineErrorMetricDimensionEvent::MouseInjectorMissingIsPrecisionScroll,
531                            "mouse wheel event does not have value in is_precision_scroll.");
532                        None
533                    }
534                },
535                _ => None,
536            },
537            pressed_buttons: Some(Vec::from_iter(mouse_event.pressed_buttons.iter().cloned())),
538            relative_motion,
539            ..Default::default()
540        };
541        pointerinjector::Event {
542            timestamp: Some(event_time.into_nanos()),
543            data: Some(pointerinjector::Data::PointerSample(pointer_sample)),
544            trace_flow_id: trace_id,
545            wake_lease: mouse_event.wake_lease.lock().take(),
546            ..Default::default()
547        }
548    }
549
550    /// Watches for viewport updates from the scene manager.
551    pub async fn watch_viewport(self: Rc<Self>) {
552        let configuration_proxy = self.configuration_proxy.clone();
553        let mut viewport_stream = HangingGetStream::new(
554            configuration_proxy,
555            pointerinjector_config::SetupProxy::watch_viewport,
556        );
557        loop {
558            match viewport_stream.next().await {
559                Some(Ok(new_viewport)) => {
560                    // Update the viewport tracked by this handler.
561                    self.inner_mut().viewport = Some(new_viewport.clone());
562
563                    // Update Scenic with the latest viewport.
564                    let injectors = self.inner().injectors.values().cloned().collect::<Vec<_>>();
565                    for injector in injectors {
566                        let events = vec![pointerinjector::Event {
567                            timestamp: Some(fuchsia_async::MonotonicInstant::now().into_nanos()),
568                            data: Some(pointerinjector::Data::Viewport(new_viewport.clone())),
569                            trace_flow_id: Some(fuchsia_trace::Id::random().into()),
570                            ..Default::default()
571                        }];
572                        injector.inject_events(events).expect("Failed to inject updated viewport.");
573                    }
574                }
575                Some(Err(e)) => {
576                    self.metrics_logger.log_error(
577                        InputPipelineErrorMetricDimensionEvent::MouseInjectorErrorWhileReadingViewportUpdate,
578                        std::format!("Error while reading viewport update: {}", e));
579                    return;
580                }
581                None => {
582                    self.metrics_logger.log_error(
583                        InputPipelineErrorMetricDimensionEvent::MouseInjectorViewportUpdateStreamTerminatedUnexpectedly,
584                        "Viewport update stream terminated unexpectedly");
585                    return;
586                }
587            }
588        }
589    }
590
591    /// Converts a relative movement given in millimeters to movement in phyical pixel.
592    /// Because pointer_display_scale_handler scaled for device pixel ratio, this method
593    /// only need to apply phyical distance to logical pixel scale factor.
594    fn relative_movement_mm_to_phyical_pixel(&self, movement_mm: Position) -> Position {
595        Position {
596            x: movement_mm.x * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
597            y: movement_mm.y * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
598        }
599    }
600}
601
602#[cfg(test)]
603mod tests {
604    use super::*;
605    use crate::testing_utilities::{
606        assert_handler_ignores_input_event_sequence, create_mouse_event,
607        create_mouse_event_with_handled, create_mouse_pointer_sample_event,
608        create_mouse_pointer_sample_event_phase_add,
609        create_mouse_pointer_sample_event_with_wheel_physical_pixel,
610    };
611    use assert_matches::assert_matches;
612    use futures::channel::mpsc;
613    use pretty_assertions::assert_eq;
614    use std::collections::HashSet;
615    use std::ops::Add;
616    use test_case::test_case;
617    use {
618        fidl_fuchsia_input_report as fidl_input_report,
619        fidl_fuchsia_ui_pointerinjector as pointerinjector, fuchsia_async as fasync,
620    };
621
622    const DISPLAY_WIDTH_IN_PHYSICAL_PX: f32 = 100.0;
623    const DISPLAY_HEIGHT_IN_PHYSICAL_PX: f32 = 100.0;
624    const COUNTS_PER_MM: u32 = 12;
625
626    /// Returns an |input_device::InputDeviceDescriptor::MouseDescriptor|.
627    const DESCRIPTOR: input_device::InputDeviceDescriptor =
628        input_device::InputDeviceDescriptor::Mouse(mouse_binding::MouseDeviceDescriptor {
629            device_id: 1,
630            absolute_x_range: Some(fidl_input_report::Range { min: 0, max: 100 }),
631            absolute_y_range: Some(fidl_input_report::Range { min: 0, max: 100 }),
632            wheel_v_range: Some(fidl_input_report::Axis {
633                range: fidl_input_report::Range { min: -1, max: 1 },
634                unit: fidl_input_report::Unit {
635                    type_: fidl_input_report::UnitType::Other,
636                    exponent: 0,
637                },
638            }),
639            wheel_h_range: Some(fidl_input_report::Axis {
640                range: fidl_input_report::Range { min: -1, max: 1 },
641                unit: fidl_input_report::Unit {
642                    type_: fidl_input_report::UnitType::Other,
643                    exponent: 0,
644                },
645            }),
646            buttons: None,
647            counts_per_mm: COUNTS_PER_MM,
648        });
649
650    /// Handles |fidl_fuchsia_pointerinjector_configuration::SetupRequest::GetViewRefs|.
651    async fn handle_configuration_request_stream(
652        stream: &mut pointerinjector_config::SetupRequestStream,
653    ) {
654        if let Some(Ok(request)) = stream.next().await {
655            match request {
656                pointerinjector_config::SetupRequest::GetViewRefs { responder, .. } => {
657                    let context = fuchsia_scenic::ViewRefPair::new()
658                        .expect("Failed to create viewrefpair.")
659                        .view_ref;
660                    let target = fuchsia_scenic::ViewRefPair::new()
661                        .expect("Failed to create viewrefpair.")
662                        .view_ref;
663                    let _ = responder.send(context, target);
664                }
665                _ => {}
666            };
667        }
668    }
669
670    /// Handles |fidl_fuchsia_pointerinjector::RegistryRequest|s by forwarding the registered device
671    /// over `injector_sender` to be handled by handle_device_request_stream().
672    async fn handle_registry_request_stream(
673        mut stream: pointerinjector::RegistryRequestStream,
674        injector_sender: futures::channel::oneshot::Sender<pointerinjector::DeviceRequestStream>,
675    ) {
676        if let Some(request) = stream.next().await {
677            match request {
678                Ok(pointerinjector::RegistryRequest::Register {
679                    config: _,
680                    injector,
681                    responder,
682                    ..
683                }) => {
684                    let injector_stream = injector.into_stream();
685                    let _ = injector_sender.send(injector_stream);
686                    responder.send().expect("failed to respond");
687                }
688                _ => {}
689            };
690        } else {
691            panic!("RegistryRequestStream failed.");
692        }
693    }
694
695    // Handles |fidl_fuchsia_pointerinjector::RegistryRequest|s
696    async fn handle_registry_request_stream2(
697        mut stream: pointerinjector::RegistryRequestStream,
698        injector_sender: mpsc::UnboundedSender<Vec<pointerinjector::Event>>,
699    ) {
700        let (injector, responder) = match stream.next().await {
701            Some(Ok(pointerinjector::RegistryRequest::Register {
702                config: _,
703                injector,
704                responder,
705                ..
706            })) => (injector, responder),
707            other => panic!("expected register request, but got {:?}", other),
708        };
709        let injector_stream: pointerinjector::DeviceRequestStream = injector.into_stream();
710        responder.send().expect("failed to respond");
711        injector_stream
712            .for_each(|request| {
713                futures::future::ready({
714                    match request {
715                        Ok(pointerinjector::DeviceRequest::Inject { .. }) => {
716                            panic!("DeviceRequest::Inject is deprecated.");
717                        }
718                        Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. }) => {
719                            let _ = injector_sender.unbounded_send(events);
720                        }
721                        Err(e) => panic!("FIDL error {}", e),
722                    }
723                })
724            })
725            .await;
726    }
727
728    /// Handles |fidl_fuchsia_pointerinjector::DeviceRequest|s by asserting the injector stream
729    /// received on `injector_stream_receiver` gets `expected_events`.
730    async fn handle_device_request_stream(
731        injector_stream_receiver: futures::channel::oneshot::Receiver<
732            pointerinjector::DeviceRequestStream,
733        >,
734        expected_events: Vec<pointerinjector::Event>,
735    ) {
736        let mut injector_stream =
737            injector_stream_receiver.await.expect("Failed to get DeviceRequestStream.");
738        for expected_event in expected_events {
739            match injector_stream.next().await {
740                Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
741                    panic!("DeviceRequest::Inject is deprecated.");
742                }
743                Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
744                    assert_eq!(events, vec![expected_event]);
745                }
746                Some(Err(e)) => panic!("FIDL error {}", e),
747                None => panic!("Expected another event."),
748            }
749        }
750    }
751
752    // Creates a |pointerinjector::Viewport|.
753    fn create_viewport(min: f32, max: f32) -> pointerinjector::Viewport {
754        pointerinjector::Viewport {
755            extents: Some([[min, min], [max, max]]),
756            viewport_to_context_transform: None,
757            ..Default::default()
758        }
759    }
760
761    // Tests that MouseInjectorHandler::receives_viewport_updates() tracks viewport updates
762    // and notifies injectors about said updates.
763    #[fuchsia::test]
764    fn receives_viewport_updates() {
765        let mut exec = fasync::TestExecutor::new();
766
767        // Set up fidl streams.
768        let (configuration_proxy, mut configuration_request_stream) =
769            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
770        let (injector_registry_proxy, _) =
771            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
772        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(0);
773
774        let inspector = fuchsia_inspect::Inspector::default();
775        let test_node = inspector.root().create_child("test_node");
776
777        // Create mouse handler.
778        let mouse_handler_fut = MouseInjectorHandler::new_handler(
779            configuration_proxy,
780            injector_registry_proxy,
781            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
782            sender,
783            &test_node,
784            metrics::MetricsLogger::default(),
785        );
786        let config_request_stream_fut =
787            handle_configuration_request_stream(&mut configuration_request_stream);
788        let (mouse_handler_res, _) = exec.run_singlethreaded(futures::future::join(
789            mouse_handler_fut,
790            config_request_stream_fut,
791        ));
792        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
793
794        // Add an injector.
795        let (injector_device_proxy, mut injector_device_request_stream) =
796            fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
797        mouse_handler.inner_mut().injectors.insert(1, injector_device_proxy);
798
799        // This nested block is used to bound the lifetime of `watch_viewport_fut`.
800        {
801            // Request a viewport update.
802            let watch_viewport_fut = mouse_handler.clone().watch_viewport();
803            futures::pin_mut!(watch_viewport_fut);
804            assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
805
806            // Send a viewport update.
807            match exec.run_singlethreaded(&mut configuration_request_stream.next()) {
808                Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
809                    responder, ..
810                })) => {
811                    responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
812                }
813                other => panic!("Received unexpected value: {:?}", other),
814            };
815            assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
816
817            // Check that the injector received an updated viewport
818            exec.run_singlethreaded(async {
819                match injector_device_request_stream.next().await {
820                    Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
821                        panic!("DeviceRequest::Inject is deprecated.");
822                    }
823                    Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
824                        assert_eq!(events.len(), 1);
825                        assert!(events[0].data.is_some());
826                        assert_eq!(
827                            events[0].data,
828                            Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
829                        );
830                    }
831                    other => panic!("Received unexpected value: {:?}", other),
832                }
833            });
834
835            // Request viewport update.
836            assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
837
838            // Send viewport update.
839            match exec.run_singlethreaded(&mut configuration_request_stream.next()) {
840                Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
841                    responder, ..
842                })) => {
843                    responder
844                        .send(&create_viewport(100.0, 200.0))
845                        .expect("Failed to send viewport.");
846                }
847                other => panic!("Received unexpected value: {:?}", other),
848            };
849
850            // Process viewport update.
851            assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
852        }
853
854        // Check that the injector received an updated viewport
855        exec.run_singlethreaded(async {
856            match injector_device_request_stream.next().await {
857                Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
858                    panic!("DeviceRequest::Inject is deprecated.");
859                }
860                Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
861                    assert_eq!(events.len(), 1);
862                    assert!(events[0].data.is_some());
863                    assert_eq!(
864                        events[0].data,
865                        Some(pointerinjector::Data::Viewport(create_viewport(100.0, 200.0)))
866                    );
867                }
868                other => panic!("Received unexpected value: {:?}", other),
869            }
870        });
871
872        // Check the viewport on the handler is accurate.
873        let expected_viewport = create_viewport(100.0, 200.0);
874        assert_eq!(mouse_handler.inner().viewport, Some(expected_viewport));
875    }
876
877    fn wheel_delta_ticks(
878        ticks: i64,
879        physical_pixel: Option<f32>,
880    ) -> Option<mouse_binding::WheelDelta> {
881        Some(mouse_binding::WheelDelta {
882            raw_data: mouse_binding::RawWheelDelta::Ticks(ticks),
883            physical_pixel,
884        })
885    }
886
887    fn wheel_delta_mm(mm: f32, physical_pixel: Option<f32>) -> Option<mouse_binding::WheelDelta> {
888        Some(mouse_binding::WheelDelta {
889            raw_data: mouse_binding::RawWheelDelta::Millimeters(mm),
890            physical_pixel,
891        })
892    }
893
894    // Tests that a mouse move event both sends an update to scenic and sends the current cursor
895    // location via the cursor location sender.
896    #[test_case(
897        mouse_binding::MouseLocation::Relative(
898            mouse_binding::RelativeLocation {
899                millimeters: Position { x: 1.0, y: 2.0 }
900            }),
901        Position {
902            x: DISPLAY_WIDTH_IN_PHYSICAL_PX / 2.0
903                + 1.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
904            y: DISPLAY_HEIGHT_IN_PHYSICAL_PX / 2.0
905                + 2.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
906        },
907        [
908            1.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
909            2.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
910        ]; "Valid move event."
911    )]
912    #[test_case(
913        mouse_binding::MouseLocation::Relative(
914            mouse_binding::RelativeLocation {
915                millimeters: Position {
916                    x: DISPLAY_WIDTH_IN_PHYSICAL_PX / MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL + 2.0,
917                    y: DISPLAY_HEIGHT_IN_PHYSICAL_PX / MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL + 1.0,
918                }}),
919        Position {
920          x: DISPLAY_WIDTH_IN_PHYSICAL_PX,
921          y: DISPLAY_HEIGHT_IN_PHYSICAL_PX,
922        },
923        [
924            DISPLAY_WIDTH_IN_PHYSICAL_PX + 2.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
925            DISPLAY_HEIGHT_IN_PHYSICAL_PX + 1.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
926        ]; "Move event exceeds max bounds."
927    )]
928    #[test_case(
929        mouse_binding::MouseLocation::Relative(
930            mouse_binding::RelativeLocation {
931                millimeters: Position {
932                    x: -(DISPLAY_WIDTH_IN_PHYSICAL_PX / MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL + 2.0),
933                    y: -(DISPLAY_HEIGHT_IN_PHYSICAL_PX / MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL + 1.0),
934                }}),
935        Position { x: 0.0, y: 0.0 },
936        [
937            -(DISPLAY_WIDTH_IN_PHYSICAL_PX + 2.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL),
938            -(DISPLAY_HEIGHT_IN_PHYSICAL_PX + 1.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL),
939        ]; "Move event exceeds min bounds."
940    )]
941    #[fuchsia::test(allow_stalls = false)]
942    async fn move_event(
943        move_location: mouse_binding::MouseLocation,
944        expected_position: Position,
945        expected_relative_motion: [f32; 2],
946    ) {
947        // Set up fidl streams.
948        let (configuration_proxy, mut configuration_request_stream) =
949            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
950        let (injector_registry_proxy, injector_registry_request_stream) =
951            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
952        let config_request_stream_fut =
953            handle_configuration_request_stream(&mut configuration_request_stream);
954
955        // Create MouseInjectorHandler.
956        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(1);
957        let inspector = fuchsia_inspect::Inspector::default();
958        let test_node = inspector.root().create_child("test_node");
959        let mouse_handler_fut = MouseInjectorHandler::new_handler(
960            configuration_proxy,
961            injector_registry_proxy,
962            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
963            sender,
964            &test_node,
965            metrics::MetricsLogger::default(),
966        );
967        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
968        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
969
970        let event_time = zx::MonotonicInstant::get();
971        let input_event = create_mouse_event(
972            move_location,
973            None, /* wheel_delta_v */
974            None, /* wheel_delta_h */
975            None, /* is_precision_scroll */
976            mouse_binding::MousePhase::Move,
977            HashSet::new(),
978            HashSet::new(),
979            event_time,
980            &DESCRIPTOR,
981        );
982
983        // Handle event.
984        let handle_event_fut = mouse_handler.handle_input_event(input_event);
985        let expected_events = vec![
986            create_mouse_pointer_sample_event_phase_add(vec![], expected_position, event_time),
987            create_mouse_pointer_sample_event(
988                pointerinjector::EventPhase::Change,
989                vec![],
990                expected_position,
991                Some(expected_relative_motion),
992                None, /*wheel_delta_v*/
993                None, /*wheel_delta_h*/
994                None, /*is_precision_scroll*/
995                event_time,
996            ),
997        ];
998
999        // Create a channel for the the registered device's handle to be forwarded to the
1000        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1001        // handle_input_event() to continue.
1002        let (injector_stream_sender, injector_stream_receiver) =
1003            futures::channel::oneshot::channel::<pointerinjector::DeviceRequestStream>();
1004        let registry_fut = handle_registry_request_stream(
1005            injector_registry_request_stream,
1006            injector_stream_sender,
1007        );
1008        let device_fut = handle_device_request_stream(injector_stream_receiver, expected_events);
1009
1010        // Await all futures concurrently. If this completes, then the mouse event was handled and
1011        // matches `expected_events`.
1012        let (handle_result, _, _) = futures::join!(handle_event_fut, registry_fut, device_fut);
1013        match receiver.next().await {
1014            Some(CursorMessage::SetPosition(position)) => {
1015                pretty_assertions::assert_eq!(position, expected_position);
1016            }
1017            Some(CursorMessage::SetVisibility(_)) => {
1018                panic!("Received unexpected cursor visibility update.")
1019            }
1020            None => panic!("Did not receive cursor update."),
1021        }
1022
1023        // No unhandled events.
1024        assert_matches!(
1025            handle_result.as_slice(),
1026            [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
1027        );
1028    }
1029
1030    // Tests that an absolute mouse move event scales the location from device coordinates to
1031    // between {0, 0} and the handler's maximum position.
1032    #[fuchsia::test(allow_stalls = false)]
1033    async fn move_absolute_event() {
1034        const DEVICE_ID: u32 = 1;
1035
1036        // Set up fidl streams.
1037        let (configuration_proxy, mut configuration_request_stream) =
1038            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1039        let (injector_registry_proxy, injector_registry_request_stream) =
1040            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
1041        let config_request_stream_fut =
1042            handle_configuration_request_stream(&mut configuration_request_stream);
1043
1044        // Create MouseInjectorHandler.
1045        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(1);
1046        let inspector = fuchsia_inspect::Inspector::default();
1047        let test_node = inspector.root().create_child("test_node");
1048        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1049            configuration_proxy,
1050            injector_registry_proxy,
1051            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1052            sender,
1053            &test_node,
1054            metrics::MetricsLogger::default(),
1055        );
1056        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1057        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1058
1059        // The location is rescaled from the device coordinate system defined
1060        // by `absolute_x_range` and `absolute_y_range`, to the display coordinate
1061        // system defined by `max_position`.
1062        //
1063        //          -50 y              0 +------------------ w
1064        //            |                  |         .
1065        //            |                  |         .
1066        //            |                  |         .
1067        // -50 x -----o----- 50   ->     | . . . . . . . . .
1068        //            |                  |         .
1069        //         * { x: -25, y: 25 }   |    * { x: w * 0.25, y: h * 0.75 }
1070        //            |                  |         .
1071        //           50                h |         .
1072        //
1073        // Where w = DISPLAY_WIDTH, h = DISPLAY_HEIGHT
1074        let cursor_location =
1075            mouse_binding::MouseLocation::Absolute(Position { x: -25.0, y: 25.0 });
1076        let event_time = zx::MonotonicInstant::get();
1077        let descriptor =
1078            input_device::InputDeviceDescriptor::Mouse(mouse_binding::MouseDeviceDescriptor {
1079                device_id: DEVICE_ID,
1080                absolute_x_range: Some(fidl_input_report::Range { min: -50, max: 50 }),
1081                absolute_y_range: Some(fidl_input_report::Range { min: -50, max: 50 }),
1082                wheel_v_range: None,
1083                wheel_h_range: None,
1084                buttons: None,
1085                counts_per_mm: COUNTS_PER_MM,
1086            });
1087        let input_event = create_mouse_event(
1088            cursor_location,
1089            None, /* wheel_delta_v */
1090            None, /* wheel_delta_h */
1091            None, /* is_precision_scroll */
1092            mouse_binding::MousePhase::Move,
1093            HashSet::new(),
1094            HashSet::new(),
1095            event_time,
1096            &descriptor,
1097        );
1098
1099        // Handle event.
1100        let handle_event_fut = mouse_handler.handle_input_event(input_event);
1101        let expected_position = Position {
1102            x: DISPLAY_WIDTH_IN_PHYSICAL_PX * 0.25,
1103            y: DISPLAY_WIDTH_IN_PHYSICAL_PX * 0.75,
1104        };
1105        let expected_events = vec![
1106            create_mouse_pointer_sample_event_phase_add(vec![], expected_position, event_time),
1107            create_mouse_pointer_sample_event(
1108                pointerinjector::EventPhase::Change,
1109                vec![],
1110                expected_position,
1111                None, /*relative_motion*/
1112                None, /*wheel_delta_v*/
1113                None, /*wheel_delta_h*/
1114                None, /*is_precision_scroll*/
1115                event_time,
1116            ),
1117        ];
1118
1119        // Create a channel for the the registered device's handle to be forwarded to the
1120        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1121        // handle_input_event() to continue.
1122        let (injector_stream_sender, injector_stream_receiver) =
1123            futures::channel::oneshot::channel::<pointerinjector::DeviceRequestStream>();
1124        let registry_fut = handle_registry_request_stream(
1125            injector_registry_request_stream,
1126            injector_stream_sender,
1127        );
1128        let device_fut = handle_device_request_stream(injector_stream_receiver, expected_events);
1129
1130        // Await all futures concurrently. If this completes, then the mouse event was handled and
1131        // matches `expected_events`.
1132        let (handle_result, _, _) = futures::join!(handle_event_fut, registry_fut, device_fut);
1133        match receiver.next().await {
1134            Some(CursorMessage::SetPosition(position)) => {
1135                assert_eq!(position, expected_position);
1136            }
1137            Some(CursorMessage::SetVisibility(_)) => {
1138                panic!("Received unexpected cursor visibility update.")
1139            }
1140            None => panic!("Did not receive cursor update."),
1141        }
1142
1143        // No unhandled events.
1144        assert_matches!(
1145            handle_result.as_slice(),
1146            [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
1147        );
1148    }
1149
1150    // Tests that mouse down and up events inject button press state.
1151    #[test_case(
1152      mouse_binding::MousePhase::Down,
1153      vec![1], vec![1]; "Down event injects button press state."
1154    )]
1155    #[test_case(
1156      mouse_binding::MousePhase::Up,
1157      vec![1], vec![]; "Up event injects button press state."
1158    )]
1159    #[fuchsia::test(allow_stalls = false)]
1160    async fn button_state_event(
1161        phase: mouse_binding::MousePhase,
1162        affected_buttons: Vec<mouse_binding::MouseButton>,
1163        pressed_buttons: Vec<mouse_binding::MouseButton>,
1164    ) {
1165        // Set up fidl streams.
1166        let (configuration_proxy, mut configuration_request_stream) =
1167            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1168        let (injector_registry_proxy, injector_registry_request_stream) =
1169            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
1170        let config_request_stream_fut =
1171            handle_configuration_request_stream(&mut configuration_request_stream);
1172
1173        // Create MouseInjectorHandler.
1174        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(1);
1175        let inspector = fuchsia_inspect::Inspector::default();
1176        let test_node = inspector.root().create_child("test_node");
1177        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1178            configuration_proxy,
1179            injector_registry_proxy,
1180            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1181            sender,
1182            &test_node,
1183            metrics::MetricsLogger::default(),
1184        );
1185        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1186        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1187
1188        let cursor_location = mouse_binding::MouseLocation::Absolute(Position { x: 0.0, y: 0.0 });
1189        let event_time = zx::MonotonicInstant::get();
1190
1191        let input_event = create_mouse_event(
1192            cursor_location,
1193            None, /* wheel_delta_v */
1194            None, /* wheel_delta_h */
1195            None, /* is_precision_scroll */
1196            phase,
1197            HashSet::from_iter(affected_buttons.clone()),
1198            HashSet::from_iter(pressed_buttons.clone()),
1199            event_time,
1200            &DESCRIPTOR,
1201        );
1202
1203        // Handle event.
1204        let handle_event_fut = mouse_handler.handle_input_event(input_event);
1205        let expected_position = Position { x: 0.0, y: 0.0 };
1206        let expected_events = vec![
1207            create_mouse_pointer_sample_event_phase_add(
1208                pressed_buttons.clone(),
1209                expected_position,
1210                event_time,
1211            ),
1212            create_mouse_pointer_sample_event(
1213                pointerinjector::EventPhase::Change,
1214                pressed_buttons.clone(),
1215                expected_position,
1216                None, /*relative_motion*/
1217                None, /*wheel_delta_v*/
1218                None, /*wheel_delta_h*/
1219                None, /*is_precision_scroll*/
1220                event_time,
1221            ),
1222        ];
1223
1224        // Create a channel for the the registered device's handle to be forwarded to the
1225        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1226        // handle_input_event() to continue.
1227        let (injector_stream_sender, injector_stream_receiver) =
1228            futures::channel::oneshot::channel::<pointerinjector::DeviceRequestStream>();
1229        let registry_fut = handle_registry_request_stream(
1230            injector_registry_request_stream,
1231            injector_stream_sender,
1232        );
1233        let device_fut = handle_device_request_stream(injector_stream_receiver, expected_events);
1234
1235        // Await all futures concurrently. If this completes, then the mouse event was handled and
1236        // matches `expected_events`.
1237        let (handle_result, _, _) = futures::join!(handle_event_fut, registry_fut, device_fut);
1238        match receiver.next().await {
1239            Some(CursorMessage::SetPosition(position)) => {
1240                pretty_assertions::assert_eq!(position, expected_position);
1241            }
1242            Some(CursorMessage::SetVisibility(_)) => {
1243                panic!("Received unexpected cursor visibility update.")
1244            }
1245            None => panic!("Did not receive cursor update."),
1246        }
1247
1248        // No unhandled events.
1249        assert_matches!(
1250            handle_result.as_slice(),
1251            [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
1252        );
1253    }
1254
1255    // Tests that mouse down followed by mouse up events inject button press state.
1256    #[fuchsia::test(allow_stalls = false)]
1257    async fn down_up_event() {
1258        // Set up fidl streams.
1259        let (configuration_proxy, mut configuration_request_stream) =
1260            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1261        let (injector_registry_proxy, injector_registry_request_stream) =
1262            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
1263        let config_request_stream_fut =
1264            handle_configuration_request_stream(&mut configuration_request_stream);
1265
1266        // Create MouseInjectorHandler.
1267        // Note: The size of the CursorMessage channel's buffer is 2 to allow for one cursor
1268        // update for every input event being sent.
1269        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(2);
1270        let inspector = fuchsia_inspect::Inspector::default();
1271        let test_node = inspector.root().create_child("test_node");
1272        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1273            configuration_proxy,
1274            injector_registry_proxy,
1275            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1276            sender,
1277            &test_node,
1278            metrics::MetricsLogger::default(),
1279        );
1280        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1281        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1282
1283        let cursor_location = mouse_binding::MouseLocation::Absolute(Position { x: 0.0, y: 0.0 });
1284        let event_time1 = zx::MonotonicInstant::get();
1285        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
1286
1287        let event1 = create_mouse_event(
1288            cursor_location,
1289            None, /* wheel_delta_v */
1290            None, /* wheel_delta_h */
1291            None, /* is_precision_scroll */
1292            mouse_binding::MousePhase::Down,
1293            HashSet::from_iter(vec![1]),
1294            HashSet::from_iter(vec![1]),
1295            event_time1,
1296            &DESCRIPTOR,
1297        );
1298
1299        let event2 = create_mouse_event(
1300            cursor_location,
1301            None, /* wheel_delta_v */
1302            None, /* wheel_delta_h */
1303            None, /* is_precision_scroll */
1304            mouse_binding::MousePhase::Up,
1305            HashSet::from_iter(vec![1]),
1306            HashSet::new(),
1307            event_time2,
1308            &DESCRIPTOR,
1309        );
1310
1311        let expected_position = Position { x: 0.0, y: 0.0 };
1312
1313        // Create a channel for the the registered device's handle to be forwarded to the
1314        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1315        // handle_input_event() to continue.
1316        let (injector_stream_sender, injector_stream_receiver) =
1317            mpsc::unbounded::<Vec<pointerinjector::Event>>();
1318        // Up to 2 events per handle_input_event() call.
1319        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
1320        let registry_fut = handle_registry_request_stream2(
1321            injector_registry_request_stream,
1322            injector_stream_sender,
1323        );
1324
1325        // Run future until the handler future completes.
1326        let _registry_task = fasync::Task::local(registry_fut);
1327
1328        mouse_handler.clone().handle_input_event(event1).await;
1329        assert_eq!(
1330            injector_stream_receiver
1331                .next()
1332                .await
1333                .map(|events| events.into_iter().flatten().collect()),
1334            Some(vec![
1335                create_mouse_pointer_sample_event_phase_add(
1336                    vec![1],
1337                    expected_position,
1338                    event_time1,
1339                ),
1340                create_mouse_pointer_sample_event(
1341                    pointerinjector::EventPhase::Change,
1342                    vec![1],
1343                    expected_position,
1344                    None, /*relative_motion*/
1345                    None, /*wheel_delta_v*/
1346                    None, /*wheel_delta_h*/
1347                    None, /*is_precision_scroll*/
1348                    event_time1,
1349                )
1350            ])
1351        );
1352
1353        // Send another input event.
1354        mouse_handler.clone().handle_input_event(event2).await;
1355        assert_eq!(
1356            injector_stream_receiver
1357                .next()
1358                .await
1359                .map(|events| events.into_iter().flatten().collect()),
1360            Some(vec![create_mouse_pointer_sample_event(
1361                pointerinjector::EventPhase::Change,
1362                vec![],
1363                expected_position,
1364                None, /*relative_motion*/
1365                None, /*wheel_delta_v*/
1366                None, /*wheel_delta_h*/
1367                None, /*is_precision_scroll*/
1368                event_time2,
1369            )])
1370        );
1371
1372        // Wait until validation is complete.
1373        match receiver.next().await {
1374            Some(CursorMessage::SetPosition(position)) => {
1375                assert_eq!(position, expected_position);
1376            }
1377            Some(CursorMessage::SetVisibility(_)) => {
1378                panic!("Received unexpected cursor visibility update.")
1379            }
1380            None => panic!("Did not receive cursor update."),
1381        }
1382    }
1383
1384    /// Tests that two staggered button presses followed by stagged releases generate four mouse
1385    /// events with distinct `affected_button` and `pressed_button`.
1386    /// Specifically, we test and expect the following in order:
1387    /// | Action           | MousePhase | Injected Phase | `pressed_buttons` |
1388    /// | ---------------- | ---------- | -------------- | ----------------- |
1389    /// | Press button 1   | Down       | Change         | [1]               |
1390    /// | Press button 2   | Down       | Change         | [1, 2]            |
1391    /// | Release button 1 | Up         | Change         | [2]               |
1392    /// | Release button 2 | Up         | Change         | []                |
1393    #[fuchsia::test(allow_stalls = false)]
1394    async fn down_down_up_up_event() {
1395        // Set up fidl streams.
1396        let (configuration_proxy, mut configuration_request_stream) =
1397            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1398        let (injector_registry_proxy, injector_registry_request_stream) =
1399            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
1400        let config_request_stream_fut =
1401            handle_configuration_request_stream(&mut configuration_request_stream);
1402
1403        // Create MouseInjectorHandler.
1404        // Note: The size of the CursorMessage channel's buffer is 4 to allow for one cursor
1405        // update for every input event being sent.
1406        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(4);
1407        let inspector = fuchsia_inspect::Inspector::default();
1408        let test_node = inspector.root().create_child("test_node");
1409        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1410            configuration_proxy,
1411            injector_registry_proxy,
1412            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1413            sender,
1414            &test_node,
1415            metrics::MetricsLogger::default(),
1416        );
1417        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1418        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1419
1420        let cursor_location = mouse_binding::MouseLocation::Absolute(Position { x: 0.0, y: 0.0 });
1421        let event_time1 = zx::MonotonicInstant::get();
1422        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
1423        let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
1424        let event_time4 = event_time3.add(zx::MonotonicDuration::from_micros(1));
1425
1426        let event1 = create_mouse_event(
1427            cursor_location,
1428            None, /* wheel_delta_v */
1429            None, /* wheel_delta_h */
1430            None, /* is_precision_scroll */
1431            mouse_binding::MousePhase::Down,
1432            HashSet::from_iter(vec![1]),
1433            HashSet::from_iter(vec![1]),
1434            event_time1,
1435            &DESCRIPTOR,
1436        );
1437        let event2 = create_mouse_event(
1438            cursor_location,
1439            None, /* wheel_delta_v */
1440            None, /* wheel_delta_h */
1441            None, /* is_precision_scroll */
1442            mouse_binding::MousePhase::Down,
1443            HashSet::from_iter(vec![2]),
1444            HashSet::from_iter(vec![1, 2]),
1445            event_time2,
1446            &DESCRIPTOR,
1447        );
1448        let event3 = create_mouse_event(
1449            cursor_location,
1450            None, /* wheel_delta_v */
1451            None, /* wheel_delta_h */
1452            None, /* is_precision_scroll */
1453            mouse_binding::MousePhase::Up,
1454            HashSet::from_iter(vec![1]),
1455            HashSet::from_iter(vec![2]),
1456            event_time3,
1457            &DESCRIPTOR,
1458        );
1459        let event4 = create_mouse_event(
1460            cursor_location,
1461            None, /* wheel_delta_v */
1462            None, /* wheel_delta_h */
1463            None, /* is_precision_scroll */
1464            mouse_binding::MousePhase::Up,
1465            HashSet::from_iter(vec![2]),
1466            HashSet::new(),
1467            event_time4,
1468            &DESCRIPTOR,
1469        );
1470
1471        let expected_position = Position { x: 0.0, y: 0.0 };
1472
1473        // Create a channel for the the registered device's handle to be forwarded to the
1474        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1475        // handle_input_event() to continue.
1476        let (injector_stream_sender, injector_stream_receiver) =
1477            mpsc::unbounded::<Vec<pointerinjector::Event>>();
1478        // Up to 2 events per handle_input_event() call.
1479        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
1480        let registry_fut = handle_registry_request_stream2(
1481            injector_registry_request_stream,
1482            injector_stream_sender,
1483        );
1484
1485        // Run future until the handler future completes.
1486        let _registry_task = fasync::Task::local(registry_fut);
1487        mouse_handler.clone().handle_input_event(event1).await;
1488        assert_eq!(
1489            injector_stream_receiver
1490                .next()
1491                .await
1492                .map(|events| events.into_iter().flatten().collect()),
1493            Some(vec![
1494                create_mouse_pointer_sample_event_phase_add(
1495                    vec![1],
1496                    expected_position,
1497                    event_time1,
1498                ),
1499                create_mouse_pointer_sample_event(
1500                    pointerinjector::EventPhase::Change,
1501                    vec![1],
1502                    expected_position,
1503                    None, /*relative_motion*/
1504                    None, /*wheel_delta_v*/
1505                    None, /*wheel_delta_h*/
1506                    None, /*is_precision_scroll*/
1507                    event_time1,
1508                )
1509            ])
1510        );
1511
1512        // Send another down event.
1513        mouse_handler.clone().handle_input_event(event2).await;
1514        let pointer_sample_event2: Vec<_> = injector_stream_receiver
1515            .next()
1516            .await
1517            .map(|events| events.into_iter().flatten().collect())
1518            .expect("Failed to receive pointer sample event.");
1519        let expected_event_time: i64 = event_time2.into_nanos();
1520        assert_eq!(pointer_sample_event2.len(), 1);
1521
1522        // We must break this event result apart for assertions since the
1523        // `pressed_buttons` can be given with elements in any order.
1524        match &pointer_sample_event2[0] {
1525            pointerinjector::Event {
1526                timestamp: Some(actual_event_time),
1527                data:
1528                    Some(pointerinjector::Data::PointerSample(pointerinjector::PointerSample {
1529                        pointer_id: Some(0),
1530                        phase: Some(pointerinjector::EventPhase::Change),
1531                        position_in_viewport: Some(actual_position),
1532                        scroll_v: None,
1533                        scroll_h: None,
1534                        pressed_buttons: Some(actual_buttons),
1535                        relative_motion: None,
1536                        ..
1537                    })),
1538                ..
1539            } => {
1540                assert_eq!(*actual_event_time, expected_event_time);
1541                assert_eq!(actual_position[0], expected_position.x);
1542                assert_eq!(actual_position[1], expected_position.y);
1543                assert_eq!(
1544                    HashSet::<mouse_binding::MouseButton>::from_iter(actual_buttons.clone()),
1545                    HashSet::from_iter(vec![1, 2])
1546                );
1547            }
1548            _ => panic!("Unexpected pointer sample event: {:?}", pointer_sample_event2[0]),
1549        }
1550
1551        // Send another up event.
1552        mouse_handler.clone().handle_input_event(event3).await;
1553        assert_eq!(
1554            injector_stream_receiver
1555                .next()
1556                .await
1557                .map(|events| events.into_iter().flatten().collect()),
1558            Some(vec![create_mouse_pointer_sample_event(
1559                pointerinjector::EventPhase::Change,
1560                vec![2],
1561                expected_position,
1562                None, /*relative_motion*/
1563                None, /*wheel_delta_v*/
1564                None, /*wheel_delta_h*/
1565                None, /*is_precision_scroll*/
1566                event_time3,
1567            )])
1568        );
1569
1570        // Send another up event.
1571        mouse_handler.clone().handle_input_event(event4).await;
1572        assert_eq!(
1573            injector_stream_receiver
1574                .next()
1575                .await
1576                .map(|events| events.into_iter().flatten().collect()),
1577            Some(vec![create_mouse_pointer_sample_event(
1578                pointerinjector::EventPhase::Change,
1579                vec![],
1580                expected_position,
1581                None, /*relative_motion*/
1582                None, /*wheel_delta_v*/
1583                None, /*wheel_delta_h*/
1584                None, /*is_precision_scroll*/
1585                event_time4,
1586            )])
1587        );
1588
1589        // Wait until validation is complete.
1590        match receiver.next().await {
1591            Some(CursorMessage::SetPosition(position)) => {
1592                assert_eq!(position, expected_position);
1593            }
1594            Some(CursorMessage::SetVisibility(_)) => {
1595                panic!("Received unexpected cursor visibility update.")
1596            }
1597            None => panic!("Did not receive cursor update."),
1598        }
1599    }
1600
1601    /// Tests that button press, mouse move, and button release inject changes accordingly.
1602    #[fuchsia::test(allow_stalls = false)]
1603    async fn down_move_up_event() {
1604        // Set up fidl streams.
1605        let (configuration_proxy, mut configuration_request_stream) =
1606            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1607        let (injector_registry_proxy, injector_registry_request_stream) =
1608            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
1609        let config_request_stream_fut =
1610            handle_configuration_request_stream(&mut configuration_request_stream);
1611
1612        // Create MouseInjectorHandler.
1613        // Note: The size of the CursorMessage channel's buffer is 3 to allow for one cursor
1614        // update for every input event being sent.
1615        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(3);
1616        let inspector = fuchsia_inspect::Inspector::default();
1617        let test_node = inspector.root().create_child("test_node");
1618        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1619            configuration_proxy,
1620            injector_registry_proxy,
1621            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1622            sender,
1623            &test_node,
1624            metrics::MetricsLogger::default(),
1625        );
1626        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1627        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1628
1629        let event_time1 = zx::MonotonicInstant::get();
1630        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
1631        let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
1632        let zero_position = Position { x: 0.0, y: 0.0 };
1633        let expected_position = Position {
1634            x: 10.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
1635            y: 5.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
1636        };
1637        let expected_relative_motion = [
1638            10.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
1639            5.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
1640        ];
1641        let event1 = create_mouse_event(
1642            mouse_binding::MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1643            None, /* wheel_delta_v */
1644            None, /* wheel_delta_h */
1645            None, /* is_precision_scroll */
1646            mouse_binding::MousePhase::Down,
1647            HashSet::from_iter(vec![1]),
1648            HashSet::from_iter(vec![1]),
1649            event_time1,
1650            &DESCRIPTOR,
1651        );
1652        let event2 = create_mouse_event(
1653            mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1654                millimeters: Position { x: 10.0, y: 5.0 },
1655            }),
1656            None, /* wheel_delta_v */
1657            None, /* wheel_delta_h */
1658            None, /* is_precision_scroll */
1659            mouse_binding::MousePhase::Move,
1660            HashSet::from_iter(vec![1]),
1661            HashSet::from_iter(vec![1]),
1662            event_time2,
1663            &DESCRIPTOR,
1664        );
1665        let event3 = create_mouse_event(
1666            mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1667                millimeters: Position { x: 0.0, y: 0.0 },
1668            }),
1669            None, /* wheel_delta_v */
1670            None, /* wheel_delta_h */
1671            None, /* is_precision_scroll */
1672            mouse_binding::MousePhase::Up,
1673            HashSet::from_iter(vec![1]),
1674            HashSet::from_iter(vec![]),
1675            event_time3,
1676            &DESCRIPTOR,
1677        );
1678
1679        // Create a channel for the the registered device's handle to be forwarded to the
1680        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1681        // handle_input_event() to continue.
1682        let (injector_stream_sender, injector_stream_receiver) =
1683            mpsc::unbounded::<Vec<pointerinjector::Event>>();
1684        // Up to 2 events per handle_input_event() call.
1685        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
1686        let registry_fut = handle_registry_request_stream2(
1687            injector_registry_request_stream,
1688            injector_stream_sender,
1689        );
1690
1691        // Run future until the handler future completes.
1692        let _registry_task = fasync::Task::local(registry_fut);
1693        mouse_handler.clone().handle_input_event(event1).await;
1694        assert_eq!(
1695            injector_stream_receiver
1696                .next()
1697                .await
1698                .map(|events| events.into_iter().flatten().collect()),
1699            Some(vec![
1700                create_mouse_pointer_sample_event_phase_add(vec![1], zero_position, event_time1,),
1701                create_mouse_pointer_sample_event(
1702                    pointerinjector::EventPhase::Change,
1703                    vec![1],
1704                    zero_position,
1705                    None, /*relative_motion*/
1706                    None, /*wheel_delta_v*/
1707                    None, /*wheel_delta_h*/
1708                    None, /*is_precision_scroll*/
1709                    event_time1,
1710                )
1711            ])
1712        );
1713
1714        // Wait until cursor position validation is complete.
1715        match receiver.next().await {
1716            Some(CursorMessage::SetPosition(position)) => {
1717                assert_eq!(position, zero_position);
1718            }
1719            Some(CursorMessage::SetVisibility(_)) => {
1720                panic!("Received unexpected cursor visibility update.")
1721            }
1722            None => panic!("Did not receive cursor update."),
1723        }
1724
1725        // Send a move event.
1726        mouse_handler.clone().handle_input_event(event2).await;
1727        assert_eq!(
1728            injector_stream_receiver
1729                .next()
1730                .await
1731                .map(|events| events.into_iter().flatten().collect()),
1732            Some(vec![create_mouse_pointer_sample_event(
1733                pointerinjector::EventPhase::Change,
1734                vec![1],
1735                expected_position,
1736                Some(expected_relative_motion),
1737                None, /*wheel_delta_v*/
1738                None, /*wheel_delta_h*/
1739                None, /*is_precision_scroll*/
1740                event_time2,
1741            )])
1742        );
1743
1744        // Wait until cursor position validation is complete.
1745        match receiver.next().await {
1746            Some(CursorMessage::SetPosition(position)) => {
1747                assert_eq!(position, expected_position);
1748            }
1749            Some(CursorMessage::SetVisibility(_)) => {
1750                panic!("Received unexpected cursor visibility update.")
1751            }
1752            None => panic!("Did not receive cursor update."),
1753        }
1754
1755        // Send an up event.
1756        mouse_handler.clone().handle_input_event(event3).await;
1757        assert_eq!(
1758            injector_stream_receiver
1759                .next()
1760                .await
1761                .map(|events| events.into_iter().flatten().collect()),
1762            Some(vec![create_mouse_pointer_sample_event(
1763                pointerinjector::EventPhase::Change,
1764                vec![],
1765                expected_position,
1766                None, /*relative_motion*/
1767                None, /*wheel_delta_v*/
1768                None, /*wheel_delta_h*/
1769                None, /*is_precision_scroll*/
1770                event_time3,
1771            )])
1772        );
1773
1774        // Wait until cursor position validation is complete.
1775        match receiver.next().await {
1776            Some(CursorMessage::SetPosition(position)) => {
1777                assert_eq!(position, expected_position);
1778            }
1779            Some(CursorMessage::SetVisibility(_)) => {
1780                panic!("Received unexpected cursor visibility update.")
1781            }
1782            None => panic!("Did not receive cursor update."),
1783        }
1784    }
1785
1786    // Tests that a mouse move event that has already been handled is not forwarded to scenic.
1787    #[fuchsia::test(allow_stalls = false)]
1788    async fn handler_ignores_handled_events() {
1789        // Set up fidl streams.
1790        let (configuration_proxy, mut configuration_request_stream) =
1791            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1792        let (injector_registry_proxy, injector_registry_request_stream) =
1793            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
1794        let config_request_stream_fut =
1795            handle_configuration_request_stream(&mut configuration_request_stream);
1796
1797        // Create MouseInjectorHandler.
1798        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(1);
1799        let inspector = fuchsia_inspect::Inspector::default();
1800        let test_node = inspector.root().create_child("test_node");
1801        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1802            configuration_proxy,
1803            injector_registry_proxy,
1804            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1805            sender,
1806            &test_node,
1807            metrics::MetricsLogger::default(),
1808        );
1809        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1810        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1811
1812        let cursor_relative_position = Position { x: 50.0, y: 75.0 };
1813        let cursor_location =
1814            mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1815                millimeters: Position {
1816                    x: cursor_relative_position.x / COUNTS_PER_MM as f32,
1817                    y: cursor_relative_position.y / COUNTS_PER_MM as f32,
1818                },
1819            });
1820        let event_time = zx::MonotonicInstant::get();
1821        let input_events = vec![create_mouse_event_with_handled(
1822            cursor_location,
1823            None, /* wheel_delta_v */
1824            None, /* wheel_delta_h */
1825            None, /* is_precision_scroll */
1826            mouse_binding::MousePhase::Move,
1827            HashSet::new(),
1828            HashSet::new(),
1829            event_time,
1830            &DESCRIPTOR,
1831            input_device::Handled::Yes,
1832        )];
1833
1834        assert_handler_ignores_input_event_sequence(
1835            mouse_handler,
1836            input_events,
1837            injector_registry_request_stream,
1838        )
1839        .await;
1840
1841        // The cursor location stream should not receive any position.
1842        assert!(receiver.next().await.is_none());
1843    }
1844
1845    fn zero_relative_location() -> mouse_binding::MouseLocation {
1846        mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1847            millimeters: Position { x: 0.0, y: 0.0 },
1848        })
1849    }
1850
1851    #[test_case(
1852        create_mouse_event(
1853            zero_relative_location(),
1854            wheel_delta_ticks(1, None),               /*wheel_delta_v*/
1855            None,                                     /*wheel_delta_h*/
1856            Some(mouse_binding::PrecisionScroll::No), /*is_precision_scroll*/
1857            mouse_binding::MousePhase::Wheel,
1858            HashSet::new(),
1859            HashSet::new(),
1860            zx::MonotonicInstant::ZERO,
1861            &DESCRIPTOR,
1862        ),
1863        create_mouse_pointer_sample_event(
1864            pointerinjector::EventPhase::Change,
1865            vec![],
1866            Position { x: 50.0, y: 50.0 },
1867            None,    /*relative_motion*/
1868            Some(1), /*wheel_delta_v*/
1869            None,    /*wheel_delta_h*/
1870            Some(false), /*is_precision_scroll*/
1871            zx::MonotonicInstant::ZERO,
1872        ); "v tick scroll"
1873    )]
1874    #[test_case(
1875        create_mouse_event(
1876            zero_relative_location(),
1877            None,                                     /*wheel_delta_v*/
1878            wheel_delta_ticks(1, None),               /*wheel_delta_h*/
1879            Some(mouse_binding::PrecisionScroll::No), /*is_precision_scroll*/
1880            mouse_binding::MousePhase::Wheel,
1881            HashSet::new(),
1882            HashSet::new(),
1883            zx::MonotonicInstant::ZERO,
1884            &DESCRIPTOR,
1885        ),
1886        create_mouse_pointer_sample_event(
1887            pointerinjector::EventPhase::Change,
1888            vec![],
1889            Position { x: 50.0, y: 50.0 },
1890            None,    /*relative_motion*/
1891            None,    /*wheel_delta_v*/
1892            Some(1), /*wheel_delta_h*/
1893            Some(false), /*is_precision_scroll*/
1894            zx::MonotonicInstant::ZERO,
1895        ); "h tick scroll"
1896    )]
1897    #[test_case(
1898        create_mouse_event(
1899            zero_relative_location(),
1900            wheel_delta_ticks(1, Some(120.0)),        /*wheel_delta_v*/
1901            None,                                     /*wheel_delta_h*/
1902            Some(mouse_binding::PrecisionScroll::No), /*is_precision_scroll*/
1903            mouse_binding::MousePhase::Wheel,
1904            HashSet::new(),
1905            HashSet::new(),
1906            zx::MonotonicInstant::ZERO,
1907            &DESCRIPTOR,
1908        ),
1909        create_mouse_pointer_sample_event_with_wheel_physical_pixel(
1910            pointerinjector::EventPhase::Change,
1911            vec![],
1912            Position { x: 50.0, y: 50.0 },
1913            None,        /*relative_motion*/
1914            Some(1),     /*wheel_delta_v*/
1915            None,        /*wheel_delta_h*/
1916            Some(120.0), /*wheel_delta_v_physical_pixel*/
1917            None,        /*wheel_delta_h_physical_pixel*/
1918            Some(false), /*is_precision_scroll*/
1919            zx::MonotonicInstant::ZERO,
1920        ); "v tick scroll with physical pixel"
1921    )]
1922    #[test_case(
1923        create_mouse_event(
1924            zero_relative_location(),
1925            None,                                     /*wheel_delta_v*/
1926            wheel_delta_ticks(1, Some(120.0)),        /*wheel_delta_h*/
1927            Some(mouse_binding::PrecisionScroll::No), /*is_precision_scroll*/
1928            mouse_binding::MousePhase::Wheel,
1929            HashSet::new(),
1930            HashSet::new(),
1931            zx::MonotonicInstant::ZERO,
1932            &DESCRIPTOR,
1933        ),
1934        create_mouse_pointer_sample_event_with_wheel_physical_pixel(
1935            pointerinjector::EventPhase::Change,
1936            vec![],
1937            Position { x: 50.0, y: 50.0 },
1938            None,        /*relative_motion*/
1939            None,        /*wheel_delta_v*/
1940            Some(1),     /*wheel_delta_h*/
1941            None,        /*wheel_delta_v_physical_pixel*/
1942            Some(120.0), /*wheel_delta_h_physical_pixel*/
1943            Some(false), /*is_precision_scroll*/
1944            zx::MonotonicInstant::ZERO,
1945        ); "h tick scroll with physical pixel"
1946    )]
1947    #[test_case(
1948        create_mouse_event(
1949            zero_relative_location(),
1950            wheel_delta_mm(1.0, Some(120.0)),          /*wheel_delta_v*/
1951            None,                                      /*wheel_delta_h*/
1952            Some(mouse_binding::PrecisionScroll::Yes), /*is_precision_scroll*/
1953            mouse_binding::MousePhase::Wheel,
1954            HashSet::new(),
1955            HashSet::new(),
1956            zx::MonotonicInstant::ZERO,
1957            &DESCRIPTOR,
1958        ),
1959        create_mouse_pointer_sample_event_with_wheel_physical_pixel(
1960            pointerinjector::EventPhase::Change,
1961            vec![],
1962            Position { x: 50.0, y: 50.0 },
1963            None,        /*relative_motion*/
1964            None,        /*wheel_delta_v*/
1965            None,        /*wheel_delta_h*/
1966            Some(120.0), /*wheel_delta_v_physical_pixel*/
1967            None,        /*wheel_delta_h_physical_pixel*/
1968            Some(true),  /*is_precision_scroll*/
1969            zx::MonotonicInstant::ZERO,
1970        ); "v mm scroll with physical pixel"
1971    )]
1972    #[test_case(
1973        create_mouse_event(
1974            zero_relative_location(),
1975            None,                                      /*wheel_delta_v*/
1976            wheel_delta_mm(1.0, Some(120.0)),          /*wheel_delta_h*/
1977            Some(mouse_binding::PrecisionScroll::Yes), /*is_precision_scroll*/
1978            mouse_binding::MousePhase::Wheel,
1979            HashSet::new(),
1980            HashSet::new(),
1981            zx::MonotonicInstant::ZERO,
1982            &DESCRIPTOR,
1983        ),
1984        create_mouse_pointer_sample_event_with_wheel_physical_pixel(
1985            pointerinjector::EventPhase::Change,
1986            vec![],
1987            Position { x: 50.0, y: 50.0 },
1988            None,        /*relative_motion*/
1989            None,        /*wheel_delta_v*/
1990            None,        /*wheel_delta_h*/
1991            None,        /*wheel_delta_v_physical_pixel*/
1992            Some(120.0), /*wheel_delta_h_physical_pixel*/
1993            Some(true),  /*is_precision_scroll*/
1994            zx::MonotonicInstant::ZERO,
1995        ); "h mm scroll with physical pixel"
1996    )]
1997    /// Test simple scroll in vertical and horizontal.
1998    #[fuchsia::test(allow_stalls = false)]
1999    async fn scroll(event: input_device::InputEvent, want_event: pointerinjector::Event) {
2000        // Set up fidl streams.
2001        let (configuration_proxy, mut configuration_request_stream) =
2002            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
2003        let (injector_registry_proxy, injector_registry_request_stream) =
2004            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
2005        let config_request_stream_fut =
2006            handle_configuration_request_stream(&mut configuration_request_stream);
2007
2008        // Create MouseInjectorHandler.
2009        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(1);
2010        let inspector = fuchsia_inspect::Inspector::default();
2011        let test_node = inspector.root().create_child("test_node");
2012        let mouse_handler_fut = MouseInjectorHandler::new_handler(
2013            configuration_proxy,
2014            injector_registry_proxy,
2015            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
2016            sender,
2017            &test_node,
2018            metrics::MetricsLogger::default(),
2019        );
2020        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
2021        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
2022
2023        // Create a channel for the the registered device's handle to be forwarded to the
2024        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
2025        // handle_input_event() to continue.
2026        let (injector_stream_sender, injector_stream_receiver) =
2027            mpsc::unbounded::<Vec<pointerinjector::Event>>();
2028        // Up to 2 events per handle_input_event() call.
2029        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
2030        let registry_fut = handle_registry_request_stream2(
2031            injector_registry_request_stream,
2032            injector_stream_sender,
2033        );
2034
2035        let event_time = zx::MonotonicInstant::get();
2036
2037        let event = input_device::InputEvent { event_time, ..event };
2038
2039        let want_event =
2040            pointerinjector::Event { timestamp: Some(event_time.into_nanos()), ..want_event };
2041
2042        // Run future until the handler future completes.
2043        let _registry_task = fasync::Task::local(registry_fut);
2044
2045        mouse_handler.clone().handle_input_event(event).await;
2046        let got_events: Vec<_> = injector_stream_receiver
2047            .next()
2048            .await
2049            .map(|events| events.into_iter().flatten().collect())
2050            .unwrap();
2051        pretty_assertions::assert_eq!(got_events.len(), 2);
2052        assert_matches!(
2053            got_events[0],
2054            pointerinjector::Event {
2055                data: Some(pointerinjector::Data::PointerSample(pointerinjector::PointerSample {
2056                    phase: Some(pointerinjector::EventPhase::Add),
2057                    ..
2058                })),
2059                ..
2060            }
2061        );
2062
2063        pretty_assertions::assert_eq!(got_events[1], want_event);
2064    }
2065
2066    /// Test button down -> scroll -> button up -> continue scroll.
2067    #[fuchsia::test(allow_stalls = false)]
2068    async fn down_scroll_up_scroll() {
2069        // Set up fidl streams.
2070        let (configuration_proxy, mut configuration_request_stream) =
2071            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
2072        let (injector_registry_proxy, injector_registry_request_stream) =
2073            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
2074        let config_request_stream_fut =
2075            handle_configuration_request_stream(&mut configuration_request_stream);
2076
2077        // Create MouseInjectorHandler.
2078        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(1);
2079        let inspector = fuchsia_inspect::Inspector::default();
2080        let test_node = inspector.root().create_child("test_node");
2081        let mouse_handler_fut = MouseInjectorHandler::new_handler(
2082            configuration_proxy,
2083            injector_registry_proxy,
2084            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
2085            sender,
2086            &test_node,
2087            metrics::MetricsLogger::default(),
2088        );
2089        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
2090        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
2091
2092        // Create a channel for the the registered device's handle to be forwarded to the
2093        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
2094        // handle_input_event() to continue.
2095        let (injector_stream_sender, injector_stream_receiver) =
2096            mpsc::unbounded::<Vec<pointerinjector::Event>>();
2097        // Up to 2 events per handle_input_event() call.
2098        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
2099        let registry_fut = handle_registry_request_stream2(
2100            injector_registry_request_stream,
2101            injector_stream_sender,
2102        );
2103
2104        let event_time1 = zx::MonotonicInstant::get();
2105        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
2106        let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
2107        let event_time4 = event_time3.add(zx::MonotonicDuration::from_micros(1));
2108
2109        // Run future until the handler future completes.
2110        let _registry_task = fasync::Task::local(registry_fut);
2111
2112        let zero_location =
2113            mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
2114                millimeters: Position { x: 0.0, y: 0.0 },
2115            });
2116        let expected_position = Position { x: 50.0, y: 50.0 };
2117
2118        let down_event = create_mouse_event(
2119            zero_location,
2120            None, /* wheel_delta_v */
2121            None, /* wheel_delta_h */
2122            None, /* is_precision_scroll */
2123            mouse_binding::MousePhase::Down,
2124            HashSet::from_iter(vec![1]),
2125            HashSet::from_iter(vec![1]),
2126            event_time1,
2127            &DESCRIPTOR,
2128        );
2129
2130        let wheel_event = create_mouse_event(
2131            zero_location,
2132            wheel_delta_ticks(1, None),               /* wheel_delta_v */
2133            None,                                     /* wheel_delta_h */
2134            Some(mouse_binding::PrecisionScroll::No), /* is_precision_scroll */
2135            mouse_binding::MousePhase::Wheel,
2136            HashSet::from_iter(vec![1]),
2137            HashSet::from_iter(vec![1]),
2138            event_time2,
2139            &DESCRIPTOR,
2140        );
2141
2142        let up_event = create_mouse_event(
2143            zero_location,
2144            None,
2145            None,
2146            None, /* is_precision_scroll */
2147            mouse_binding::MousePhase::Up,
2148            HashSet::from_iter(vec![1]),
2149            HashSet::new(),
2150            event_time3,
2151            &DESCRIPTOR,
2152        );
2153
2154        let continue_wheel_event = create_mouse_event(
2155            zero_location,
2156            wheel_delta_ticks(1, None),               /* wheel_delta_v */
2157            None,                                     /* wheel_delta_h */
2158            Some(mouse_binding::PrecisionScroll::No), /* is_precision_scroll */
2159            mouse_binding::MousePhase::Wheel,
2160            HashSet::new(),
2161            HashSet::new(),
2162            event_time4,
2163            &DESCRIPTOR,
2164        );
2165
2166        // Handle button down event.
2167        mouse_handler.clone().handle_input_event(down_event).await;
2168        assert_eq!(
2169            injector_stream_receiver
2170                .next()
2171                .await
2172                .map(|events| events.into_iter().flatten().collect()),
2173            Some(vec![
2174                create_mouse_pointer_sample_event_phase_add(
2175                    vec![1],
2176                    expected_position,
2177                    event_time1,
2178                ),
2179                create_mouse_pointer_sample_event(
2180                    pointerinjector::EventPhase::Change,
2181                    vec![1],
2182                    expected_position,
2183                    None, /*relative_motion*/
2184                    None, /*wheel_delta_v*/
2185                    None, /*wheel_delta_h*/
2186                    None, /*is_precision_scroll*/
2187                    event_time1,
2188                ),
2189            ])
2190        );
2191
2192        // Handle wheel event with button pressing.
2193        mouse_handler.clone().handle_input_event(wheel_event).await;
2194        assert_eq!(
2195            injector_stream_receiver
2196                .next()
2197                .await
2198                .map(|events| events.into_iter().flatten().collect()),
2199            Some(vec![create_mouse_pointer_sample_event(
2200                pointerinjector::EventPhase::Change,
2201                vec![1],
2202                expected_position,
2203                None,        /*relative_motion*/
2204                Some(1),     /*wheel_delta_v*/
2205                None,        /*wheel_delta_h*/
2206                Some(false), /*is_precision_scroll*/
2207                event_time2,
2208            )])
2209        );
2210
2211        // Handle button up event.
2212        mouse_handler.clone().handle_input_event(up_event).await;
2213        assert_eq!(
2214            injector_stream_receiver
2215                .next()
2216                .await
2217                .map(|events| events.into_iter().flatten().collect()),
2218            Some(vec![create_mouse_pointer_sample_event(
2219                pointerinjector::EventPhase::Change,
2220                vec![],
2221                expected_position,
2222                None, /*relative_motion*/
2223                None, /*wheel_delta_v*/
2224                None, /*wheel_delta_h*/
2225                None, /*is_precision_scroll*/
2226                event_time3,
2227            )])
2228        );
2229
2230        // Handle wheel event after button released.
2231        mouse_handler.clone().handle_input_event(continue_wheel_event).await;
2232        assert_eq!(
2233            injector_stream_receiver
2234                .next()
2235                .await
2236                .map(|events| events.into_iter().flatten().collect()),
2237            Some(vec![create_mouse_pointer_sample_event(
2238                pointerinjector::EventPhase::Change,
2239                vec![],
2240                expected_position,
2241                None,        /*relative_motion*/
2242                Some(1),     /*wheel_delta_v*/
2243                None,        /*wheel_delta_h*/
2244                Some(false), /*is_precision_scroll*/
2245                event_time4,
2246            )])
2247        );
2248    }
2249
2250    #[fuchsia::test(allow_stalls = false)]
2251    async fn mouse_injector_handler_initialized_with_inspect_node() {
2252        let (configuration_proxy, mut configuration_request_stream) =
2253            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
2254        let config_request_stream_fut =
2255            handle_configuration_request_stream(&mut configuration_request_stream);
2256        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(1);
2257        let inspector = fuchsia_inspect::Inspector::default();
2258        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
2259        let mouse_handler_fut = MouseInjectorHandler::new_with_config_proxy(
2260            configuration_proxy,
2261            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
2262            sender,
2263            &fake_handlers_node,
2264            metrics::MetricsLogger::default(),
2265        );
2266        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
2267        let _handler = mouse_handler_res.expect("Failed to create mouse handler");
2268
2269        diagnostics_assertions::assert_data_tree!(inspector, root: {
2270            input_handlers_node: {
2271                mouse_injector_handler: {
2272                    events_received_count: 0u64,
2273                    events_handled_count: 0u64,
2274                    last_received_timestamp_ns: 0u64,
2275                    "fuchsia.inspect.Health": {
2276                        status: "STARTING_UP",
2277                        // Timestamp value is unpredictable and not relevant in this context,
2278                        // so we only assert that the property is present.
2279                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
2280                    },
2281                }
2282            }
2283        });
2284    }
2285
2286    #[fuchsia::test(allow_stalls = false)]
2287    async fn mouse_injector_handler_inspect_counts_events() {
2288        // Set up fidl streams.
2289        let (configuration_proxy, mut configuration_request_stream) =
2290            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
2291        let (injector_registry_proxy, injector_registry_request_stream) =
2292            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
2293        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(1);
2294
2295        let inspector = fuchsia_inspect::Inspector::default();
2296        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
2297
2298        // Create mouse handler.
2299        let mouse_handler_fut = MouseInjectorHandler::new_handler(
2300            configuration_proxy,
2301            injector_registry_proxy,
2302            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
2303            sender,
2304            &fake_handlers_node,
2305            metrics::MetricsLogger::default(),
2306        );
2307        let config_request_stream_fut =
2308            handle_configuration_request_stream(&mut configuration_request_stream);
2309
2310        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
2311        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
2312
2313        let cursor_location = mouse_binding::MouseLocation::Absolute(Position { x: 0.0, y: 0.0 });
2314        let event_time1 = zx::MonotonicInstant::get();
2315        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
2316        let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
2317
2318        let input_events = vec![
2319            create_mouse_event(
2320                cursor_location,
2321                None, /* wheel_delta_v */
2322                None, /* wheel_delta_h */
2323                None, /* is_precision_scroll */
2324                mouse_binding::MousePhase::Down,
2325                HashSet::from_iter(vec![1]),
2326                HashSet::from_iter(vec![1]),
2327                event_time1,
2328                &DESCRIPTOR,
2329            ),
2330            create_mouse_event(
2331                cursor_location,
2332                None, /* wheel_delta_v */
2333                None, /* wheel_delta_h */
2334                None, /* is_precision_scroll */
2335                mouse_binding::MousePhase::Up,
2336                HashSet::from_iter(vec![1]),
2337                HashSet::new(),
2338                event_time2,
2339                &DESCRIPTOR,
2340            ),
2341            create_mouse_event_with_handled(
2342                cursor_location,
2343                None, /* wheel_delta_v */
2344                None, /* wheel_delta_h */
2345                None, /* is_precision_scroll */
2346                mouse_binding::MousePhase::Down,
2347                HashSet::from_iter(vec![1]),
2348                HashSet::from_iter(vec![1]),
2349                event_time3,
2350                &DESCRIPTOR,
2351                input_device::Handled::Yes,
2352            ),
2353        ];
2354
2355        // Create a channel for the the registered device's handle to be forwarded to the
2356        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
2357        // handle_input_event() to continue.
2358        let (injector_stream_sender, _) = mpsc::unbounded::<Vec<pointerinjector::Event>>();
2359        let registry_fut = handle_registry_request_stream2(
2360            injector_registry_request_stream,
2361            injector_stream_sender,
2362        );
2363
2364        // Run future until the handler future completes.
2365        let _registry_task = fasync::Task::local(registry_fut);
2366        for input_event in input_events {
2367            mouse_handler.clone().handle_input_event(input_event).await;
2368        }
2369
2370        let last_received_event_time: u64 = event_time2.into_nanos().try_into().unwrap();
2371
2372        diagnostics_assertions::assert_data_tree!(inspector, root: {
2373            input_handlers_node: {
2374                mouse_injector_handler: {
2375                    events_received_count: 2u64,
2376                    events_handled_count: 2u64,
2377                    last_received_timestamp_ns: last_received_event_time,
2378                    "fuchsia.inspect.Health": {
2379                        status: "STARTING_UP",
2380                        // Timestamp value is unpredictable and not relevant in this context,
2381                        // so we only assert that the property is present.
2382                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
2383                    },
2384                }
2385            }
2386        });
2387    }
2388}