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