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