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::{anyhow, Context, Error, Result};
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::channel::mpsc::Sender;
18use futures::stream::StreamExt;
19use futures::SinkExt;
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 = &[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 = &[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 = &[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.next().await.map(|events| events.concat()),
1314            Some(vec![
1315                create_mouse_pointer_sample_event_phase_add(
1316                    vec![1],
1317                    expected_position,
1318                    event_time1,
1319                ),
1320                create_mouse_pointer_sample_event(
1321                    pointerinjector::EventPhase::Change,
1322                    vec![1],
1323                    expected_position,
1324                    None, /*relative_motion*/
1325                    None, /*wheel_delta_v*/
1326                    None, /*wheel_delta_h*/
1327                    None, /*is_precision_scroll*/
1328                    event_time1,
1329                )
1330            ])
1331        );
1332
1333        // Send another input event.
1334        mouse_handler.clone().handle_input_event(event2).await;
1335        assert_eq!(
1336            injector_stream_receiver.next().await.map(|events| events.concat()),
1337            Some(vec![create_mouse_pointer_sample_event(
1338                pointerinjector::EventPhase::Change,
1339                vec![],
1340                expected_position,
1341                None, /*relative_motion*/
1342                None, /*wheel_delta_v*/
1343                None, /*wheel_delta_h*/
1344                None, /*is_precision_scroll*/
1345                event_time2,
1346            )])
1347        );
1348
1349        // Wait until validation is complete.
1350        match receiver.next().await {
1351            Some(CursorMessage::SetPosition(position)) => {
1352                assert_eq!(position, expected_position);
1353            }
1354            Some(CursorMessage::SetVisibility(_)) => {
1355                panic!("Received unexpected cursor visibility update.")
1356            }
1357            None => panic!("Did not receive cursor update."),
1358        }
1359    }
1360
1361    /// Tests that two staggered button presses followed by stagged releases generate four mouse
1362    /// events with distinct `affected_button` and `pressed_button`.
1363    /// Specifically, we test and expect the following in order:
1364    /// | Action           | MousePhase | Injected Phase | `pressed_buttons` |
1365    /// | ---------------- | ---------- | -------------- | ----------------- |
1366    /// | Press button 1   | Down       | Change         | [1]               |
1367    /// | Press button 2   | Down       | Change         | [1, 2]            |
1368    /// | Release button 1 | Up         | Change         | [2]               |
1369    /// | Release button 2 | Up         | Change         | []                |
1370    #[fuchsia::test(allow_stalls = false)]
1371    async fn down_down_up_up_event() {
1372        // Set up fidl streams.
1373        let (configuration_proxy, mut configuration_request_stream) =
1374            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1375        let (injector_registry_proxy, injector_registry_request_stream) =
1376            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
1377        let config_request_stream_fut =
1378            handle_configuration_request_stream(&mut configuration_request_stream);
1379
1380        // Create MouseInjectorHandler.
1381        // Note: The size of the CursorMessage channel's buffer is 4 to allow for one cursor
1382        // update for every input event being sent.
1383        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(4);
1384        let inspector = fuchsia_inspect::Inspector::default();
1385        let test_node = inspector.root().create_child("test_node");
1386        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1387            configuration_proxy,
1388            injector_registry_proxy,
1389            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1390            sender,
1391            &test_node,
1392            metrics::MetricsLogger::default(),
1393        );
1394        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1395        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1396
1397        let cursor_location = mouse_binding::MouseLocation::Absolute(Position { x: 0.0, y: 0.0 });
1398        let event_time1 = zx::MonotonicInstant::get();
1399        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
1400        let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
1401        let event_time4 = event_time3.add(zx::MonotonicDuration::from_micros(1));
1402
1403        let event1 = create_mouse_event(
1404            cursor_location,
1405            None, /* wheel_delta_v */
1406            None, /* wheel_delta_h */
1407            None, /* is_precision_scroll */
1408            mouse_binding::MousePhase::Down,
1409            HashSet::from_iter(vec![1]),
1410            HashSet::from_iter(vec![1]),
1411            event_time1,
1412            &DESCRIPTOR,
1413        );
1414        let event2 = create_mouse_event(
1415            cursor_location,
1416            None, /* wheel_delta_v */
1417            None, /* wheel_delta_h */
1418            None, /* is_precision_scroll */
1419            mouse_binding::MousePhase::Down,
1420            HashSet::from_iter(vec![2]),
1421            HashSet::from_iter(vec![1, 2]),
1422            event_time2,
1423            &DESCRIPTOR,
1424        );
1425        let event3 = create_mouse_event(
1426            cursor_location,
1427            None, /* wheel_delta_v */
1428            None, /* wheel_delta_h */
1429            None, /* is_precision_scroll */
1430            mouse_binding::MousePhase::Up,
1431            HashSet::from_iter(vec![1]),
1432            HashSet::from_iter(vec![2]),
1433            event_time3,
1434            &DESCRIPTOR,
1435        );
1436        let event4 = create_mouse_event(
1437            cursor_location,
1438            None, /* wheel_delta_v */
1439            None, /* wheel_delta_h */
1440            None, /* is_precision_scroll */
1441            mouse_binding::MousePhase::Up,
1442            HashSet::from_iter(vec![2]),
1443            HashSet::new(),
1444            event_time4,
1445            &DESCRIPTOR,
1446        );
1447
1448        let expected_position = Position { x: 0.0, y: 0.0 };
1449
1450        // Create a channel for the the registered device's handle to be forwarded to the
1451        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1452        // handle_input_event() to continue.
1453        let (injector_stream_sender, injector_stream_receiver) =
1454            mpsc::unbounded::<Vec<pointerinjector::Event>>();
1455        // Up to 2 events per handle_input_event() call.
1456        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
1457        let registry_fut = handle_registry_request_stream2(
1458            injector_registry_request_stream,
1459            injector_stream_sender,
1460        );
1461
1462        // Run future until the handler future completes.
1463        let _registry_task = fasync::Task::local(registry_fut);
1464        mouse_handler.clone().handle_input_event(event1).await;
1465        assert_eq!(
1466            injector_stream_receiver.next().await.map(|events| events.concat()),
1467            Some(vec![
1468                create_mouse_pointer_sample_event_phase_add(
1469                    vec![1],
1470                    expected_position,
1471                    event_time1,
1472                ),
1473                create_mouse_pointer_sample_event(
1474                    pointerinjector::EventPhase::Change,
1475                    vec![1],
1476                    expected_position,
1477                    None, /*relative_motion*/
1478                    None, /*wheel_delta_v*/
1479                    None, /*wheel_delta_h*/
1480                    None, /*is_precision_scroll*/
1481                    event_time1,
1482                )
1483            ])
1484        );
1485
1486        // Send another down event.
1487        mouse_handler.clone().handle_input_event(event2).await;
1488        let pointer_sample_event2 = injector_stream_receiver
1489            .next()
1490            .await
1491            .map(|events| events.concat())
1492            .expect("Failed to receive pointer sample event.");
1493        let expected_event_time: i64 = event_time2.into_nanos();
1494        assert_eq!(pointer_sample_event2.len(), 1);
1495
1496        // We must break this event result apart for assertions since the
1497        // `pressed_buttons` can be given with elements in any order.
1498        match &pointer_sample_event2[0] {
1499            pointerinjector::Event {
1500                timestamp: Some(actual_event_time),
1501                data:
1502                    Some(pointerinjector::Data::PointerSample(pointerinjector::PointerSample {
1503                        pointer_id: Some(0),
1504                        phase: Some(pointerinjector::EventPhase::Change),
1505                        position_in_viewport: Some(actual_position),
1506                        scroll_v: None,
1507                        scroll_h: None,
1508                        pressed_buttons: Some(actual_buttons),
1509                        relative_motion: None,
1510                        ..
1511                    })),
1512                ..
1513            } => {
1514                assert_eq!(actual_event_time, &expected_event_time);
1515                assert_eq!(actual_position[0], expected_position.x);
1516                assert_eq!(actual_position[1], expected_position.y);
1517                assert_eq!(
1518                    HashSet::<mouse_binding::MouseButton>::from_iter(actual_buttons.clone()),
1519                    HashSet::from_iter(vec![1, 2])
1520                );
1521            }
1522            _ => panic!("Unexpected pointer sample event: {:?}", pointer_sample_event2[0]),
1523        }
1524
1525        // Send another up event.
1526        mouse_handler.clone().handle_input_event(event3).await;
1527        assert_eq!(
1528            injector_stream_receiver.next().await.map(|events| events.concat()),
1529            Some(vec![create_mouse_pointer_sample_event(
1530                pointerinjector::EventPhase::Change,
1531                vec![2],
1532                expected_position,
1533                None, /*relative_motion*/
1534                None, /*wheel_delta_v*/
1535                None, /*wheel_delta_h*/
1536                None, /*is_precision_scroll*/
1537                event_time3,
1538            )])
1539        );
1540
1541        // Send another up event.
1542        mouse_handler.clone().handle_input_event(event4).await;
1543        assert_eq!(
1544            injector_stream_receiver.next().await.map(|events| events.concat()),
1545            Some(vec![create_mouse_pointer_sample_event(
1546                pointerinjector::EventPhase::Change,
1547                vec![],
1548                expected_position,
1549                None, /*relative_motion*/
1550                None, /*wheel_delta_v*/
1551                None, /*wheel_delta_h*/
1552                None, /*is_precision_scroll*/
1553                event_time4,
1554            )])
1555        );
1556
1557        // Wait until validation is complete.
1558        match receiver.next().await {
1559            Some(CursorMessage::SetPosition(position)) => {
1560                assert_eq!(position, expected_position);
1561            }
1562            Some(CursorMessage::SetVisibility(_)) => {
1563                panic!("Received unexpected cursor visibility update.")
1564            }
1565            None => panic!("Did not receive cursor update."),
1566        }
1567    }
1568
1569    /// Tests that button press, mouse move, and button release inject changes accordingly.
1570    #[fuchsia::test(allow_stalls = false)]
1571    async fn down_move_up_event() {
1572        // Set up fidl streams.
1573        let (configuration_proxy, mut configuration_request_stream) =
1574            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1575        let (injector_registry_proxy, injector_registry_request_stream) =
1576            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
1577        let config_request_stream_fut =
1578            handle_configuration_request_stream(&mut configuration_request_stream);
1579
1580        // Create MouseInjectorHandler.
1581        // Note: The size of the CursorMessage channel's buffer is 3 to allow for one cursor
1582        // update for every input event being sent.
1583        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(3);
1584        let inspector = fuchsia_inspect::Inspector::default();
1585        let test_node = inspector.root().create_child("test_node");
1586        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1587            configuration_proxy,
1588            injector_registry_proxy,
1589            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1590            sender,
1591            &test_node,
1592            metrics::MetricsLogger::default(),
1593        );
1594        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1595        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1596
1597        let event_time1 = zx::MonotonicInstant::get();
1598        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
1599        let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
1600        let zero_position = Position { x: 0.0, y: 0.0 };
1601        let expected_position = Position {
1602            x: 10.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
1603            y: 5.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
1604        };
1605        let expected_relative_motion = [
1606            10.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
1607            5.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
1608        ];
1609        let event1 = create_mouse_event(
1610            mouse_binding::MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1611            None, /* wheel_delta_v */
1612            None, /* wheel_delta_h */
1613            None, /* is_precision_scroll */
1614            mouse_binding::MousePhase::Down,
1615            HashSet::from_iter(vec![1]),
1616            HashSet::from_iter(vec![1]),
1617            event_time1,
1618            &DESCRIPTOR,
1619        );
1620        let event2 = create_mouse_event(
1621            mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1622                millimeters: Position { x: 10.0, y: 5.0 },
1623            }),
1624            None, /* wheel_delta_v */
1625            None, /* wheel_delta_h */
1626            None, /* is_precision_scroll */
1627            mouse_binding::MousePhase::Move,
1628            HashSet::from_iter(vec![1]),
1629            HashSet::from_iter(vec![1]),
1630            event_time2,
1631            &DESCRIPTOR,
1632        );
1633        let event3 = create_mouse_event(
1634            mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1635                millimeters: Position { x: 0.0, y: 0.0 },
1636            }),
1637            None, /* wheel_delta_v */
1638            None, /* wheel_delta_h */
1639            None, /* is_precision_scroll */
1640            mouse_binding::MousePhase::Up,
1641            HashSet::from_iter(vec![1]),
1642            HashSet::from_iter(vec![]),
1643            event_time3,
1644            &DESCRIPTOR,
1645        );
1646
1647        // Create a channel for the the registered device's handle to be forwarded to the
1648        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1649        // handle_input_event() to continue.
1650        let (injector_stream_sender, injector_stream_receiver) =
1651            mpsc::unbounded::<Vec<pointerinjector::Event>>();
1652        // Up to 2 events per handle_input_event() call.
1653        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
1654        let registry_fut = handle_registry_request_stream2(
1655            injector_registry_request_stream,
1656            injector_stream_sender,
1657        );
1658
1659        // Run future until the handler future completes.
1660        let _registry_task = fasync::Task::local(registry_fut);
1661        mouse_handler.clone().handle_input_event(event1).await;
1662        assert_eq!(
1663            injector_stream_receiver.next().await.map(|events| events.concat()),
1664            Some(vec![
1665                create_mouse_pointer_sample_event_phase_add(vec![1], zero_position, event_time1,),
1666                create_mouse_pointer_sample_event(
1667                    pointerinjector::EventPhase::Change,
1668                    vec![1],
1669                    zero_position,
1670                    None, /*relative_motion*/
1671                    None, /*wheel_delta_v*/
1672                    None, /*wheel_delta_h*/
1673                    None, /*is_precision_scroll*/
1674                    event_time1,
1675                )
1676            ])
1677        );
1678
1679        // Wait until cursor position validation is complete.
1680        match receiver.next().await {
1681            Some(CursorMessage::SetPosition(position)) => {
1682                assert_eq!(position, zero_position);
1683            }
1684            Some(CursorMessage::SetVisibility(_)) => {
1685                panic!("Received unexpected cursor visibility update.")
1686            }
1687            None => panic!("Did not receive cursor update."),
1688        }
1689
1690        // Send a move event.
1691        mouse_handler.clone().handle_input_event(event2).await;
1692        assert_eq!(
1693            injector_stream_receiver.next().await.map(|events| events.concat()),
1694            Some(vec![create_mouse_pointer_sample_event(
1695                pointerinjector::EventPhase::Change,
1696                vec![1],
1697                expected_position,
1698                Some(expected_relative_motion),
1699                None, /*wheel_delta_v*/
1700                None, /*wheel_delta_h*/
1701                None, /*is_precision_scroll*/
1702                event_time2,
1703            )])
1704        );
1705
1706        // Wait until cursor position validation is complete.
1707        match receiver.next().await {
1708            Some(CursorMessage::SetPosition(position)) => {
1709                assert_eq!(position, expected_position);
1710            }
1711            Some(CursorMessage::SetVisibility(_)) => {
1712                panic!("Received unexpected cursor visibility update.")
1713            }
1714            None => panic!("Did not receive cursor update."),
1715        }
1716
1717        // Send an up event.
1718        mouse_handler.clone().handle_input_event(event3).await;
1719        assert_eq!(
1720            injector_stream_receiver.next().await.map(|events| events.concat()),
1721            Some(vec![create_mouse_pointer_sample_event(
1722                pointerinjector::EventPhase::Change,
1723                vec![],
1724                expected_position,
1725                None, /*relative_motion*/
1726                None, /*wheel_delta_v*/
1727                None, /*wheel_delta_h*/
1728                None, /*is_precision_scroll*/
1729                event_time3,
1730            )])
1731        );
1732
1733        // Wait until cursor position validation is complete.
1734        match receiver.next().await {
1735            Some(CursorMessage::SetPosition(position)) => {
1736                assert_eq!(position, expected_position);
1737            }
1738            Some(CursorMessage::SetVisibility(_)) => {
1739                panic!("Received unexpected cursor visibility update.")
1740            }
1741            None => panic!("Did not receive cursor update."),
1742        }
1743    }
1744
1745    // Tests that a mouse move event that has already been handled is not forwarded to scenic.
1746    #[fuchsia::test(allow_stalls = false)]
1747    async fn handler_ignores_handled_events() {
1748        // Set up fidl streams.
1749        let (configuration_proxy, mut configuration_request_stream) =
1750            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1751        let (injector_registry_proxy, injector_registry_request_stream) =
1752            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
1753        let config_request_stream_fut =
1754            handle_configuration_request_stream(&mut configuration_request_stream);
1755
1756        // Create MouseInjectorHandler.
1757        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(1);
1758        let inspector = fuchsia_inspect::Inspector::default();
1759        let test_node = inspector.root().create_child("test_node");
1760        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1761            configuration_proxy,
1762            injector_registry_proxy,
1763            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1764            sender,
1765            &test_node,
1766            metrics::MetricsLogger::default(),
1767        );
1768        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1769        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1770
1771        let cursor_relative_position = Position { x: 50.0, y: 75.0 };
1772        let cursor_location =
1773            mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1774                millimeters: Position {
1775                    x: cursor_relative_position.x / COUNTS_PER_MM as f32,
1776                    y: cursor_relative_position.y / COUNTS_PER_MM as f32,
1777                },
1778            });
1779        let event_time = zx::MonotonicInstant::get();
1780        let input_events = vec![create_mouse_event_with_handled(
1781            cursor_location,
1782            None, /* wheel_delta_v */
1783            None, /* wheel_delta_h */
1784            None, /* is_precision_scroll */
1785            mouse_binding::MousePhase::Move,
1786            HashSet::new(),
1787            HashSet::new(),
1788            event_time,
1789            &DESCRIPTOR,
1790            input_device::Handled::Yes,
1791        )];
1792
1793        assert_handler_ignores_input_event_sequence(
1794            mouse_handler,
1795            input_events,
1796            injector_registry_request_stream,
1797        )
1798        .await;
1799
1800        // The cursor location stream should not receive any position.
1801        assert!(receiver.next().await.is_none());
1802    }
1803
1804    fn zero_relative_location() -> mouse_binding::MouseLocation {
1805        mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1806            millimeters: Position { x: 0.0, y: 0.0 },
1807        })
1808    }
1809
1810    #[test_case(
1811        create_mouse_event(
1812            zero_relative_location(),
1813            wheel_delta_ticks(1, None),               /*wheel_delta_v*/
1814            None,                                     /*wheel_delta_h*/
1815            Some(mouse_binding::PrecisionScroll::No), /*is_precision_scroll*/
1816            mouse_binding::MousePhase::Wheel,
1817            HashSet::new(),
1818            HashSet::new(),
1819            zx::MonotonicInstant::ZERO,
1820            &DESCRIPTOR,
1821        ),
1822        create_mouse_pointer_sample_event(
1823            pointerinjector::EventPhase::Change,
1824            vec![],
1825            Position { x: 50.0, y: 50.0 },
1826            None,    /*relative_motion*/
1827            Some(1), /*wheel_delta_v*/
1828            None,    /*wheel_delta_h*/
1829            Some(false), /*is_precision_scroll*/
1830            zx::MonotonicInstant::ZERO,
1831        ); "v tick scroll"
1832    )]
1833    #[test_case(
1834        create_mouse_event(
1835            zero_relative_location(),
1836            None,                                     /*wheel_delta_v*/
1837            wheel_delta_ticks(1, None),               /*wheel_delta_h*/
1838            Some(mouse_binding::PrecisionScroll::No), /*is_precision_scroll*/
1839            mouse_binding::MousePhase::Wheel,
1840            HashSet::new(),
1841            HashSet::new(),
1842            zx::MonotonicInstant::ZERO,
1843            &DESCRIPTOR,
1844        ),
1845        create_mouse_pointer_sample_event(
1846            pointerinjector::EventPhase::Change,
1847            vec![],
1848            Position { x: 50.0, y: 50.0 },
1849            None,    /*relative_motion*/
1850            None,    /*wheel_delta_v*/
1851            Some(1), /*wheel_delta_h*/
1852            Some(false), /*is_precision_scroll*/
1853            zx::MonotonicInstant::ZERO,
1854        ); "h tick scroll"
1855    )]
1856    #[test_case(
1857        create_mouse_event(
1858            zero_relative_location(),
1859            wheel_delta_ticks(1, Some(120.0)),        /*wheel_delta_v*/
1860            None,                                     /*wheel_delta_h*/
1861            Some(mouse_binding::PrecisionScroll::No), /*is_precision_scroll*/
1862            mouse_binding::MousePhase::Wheel,
1863            HashSet::new(),
1864            HashSet::new(),
1865            zx::MonotonicInstant::ZERO,
1866            &DESCRIPTOR,
1867        ),
1868        create_mouse_pointer_sample_event_with_wheel_physical_pixel(
1869            pointerinjector::EventPhase::Change,
1870            vec![],
1871            Position { x: 50.0, y: 50.0 },
1872            None,        /*relative_motion*/
1873            Some(1),     /*wheel_delta_v*/
1874            None,        /*wheel_delta_h*/
1875            Some(120.0), /*wheel_delta_v_physical_pixel*/
1876            None,        /*wheel_delta_h_physical_pixel*/
1877            Some(false), /*is_precision_scroll*/
1878            zx::MonotonicInstant::ZERO,
1879        ); "v tick scroll with physical pixel"
1880    )]
1881    #[test_case(
1882        create_mouse_event(
1883            zero_relative_location(),
1884            None,                                     /*wheel_delta_v*/
1885            wheel_delta_ticks(1, Some(120.0)),        /*wheel_delta_h*/
1886            Some(mouse_binding::PrecisionScroll::No), /*is_precision_scroll*/
1887            mouse_binding::MousePhase::Wheel,
1888            HashSet::new(),
1889            HashSet::new(),
1890            zx::MonotonicInstant::ZERO,
1891            &DESCRIPTOR,
1892        ),
1893        create_mouse_pointer_sample_event_with_wheel_physical_pixel(
1894            pointerinjector::EventPhase::Change,
1895            vec![],
1896            Position { x: 50.0, y: 50.0 },
1897            None,        /*relative_motion*/
1898            None,        /*wheel_delta_v*/
1899            Some(1),     /*wheel_delta_h*/
1900            None,        /*wheel_delta_v_physical_pixel*/
1901            Some(120.0), /*wheel_delta_h_physical_pixel*/
1902            Some(false), /*is_precision_scroll*/
1903            zx::MonotonicInstant::ZERO,
1904        ); "h tick scroll with physical pixel"
1905    )]
1906    #[test_case(
1907        create_mouse_event(
1908            zero_relative_location(),
1909            wheel_delta_mm(1.0, Some(120.0)),          /*wheel_delta_v*/
1910            None,                                      /*wheel_delta_h*/
1911            Some(mouse_binding::PrecisionScroll::Yes), /*is_precision_scroll*/
1912            mouse_binding::MousePhase::Wheel,
1913            HashSet::new(),
1914            HashSet::new(),
1915            zx::MonotonicInstant::ZERO,
1916            &DESCRIPTOR,
1917        ),
1918        create_mouse_pointer_sample_event_with_wheel_physical_pixel(
1919            pointerinjector::EventPhase::Change,
1920            vec![],
1921            Position { x: 50.0, y: 50.0 },
1922            None,        /*relative_motion*/
1923            None,        /*wheel_delta_v*/
1924            None,        /*wheel_delta_h*/
1925            Some(120.0), /*wheel_delta_v_physical_pixel*/
1926            None,        /*wheel_delta_h_physical_pixel*/
1927            Some(true),  /*is_precision_scroll*/
1928            zx::MonotonicInstant::ZERO,
1929        ); "v mm scroll with physical pixel"
1930    )]
1931    #[test_case(
1932        create_mouse_event(
1933            zero_relative_location(),
1934            None,                                      /*wheel_delta_v*/
1935            wheel_delta_mm(1.0, Some(120.0)),          /*wheel_delta_h*/
1936            Some(mouse_binding::PrecisionScroll::Yes), /*is_precision_scroll*/
1937            mouse_binding::MousePhase::Wheel,
1938            HashSet::new(),
1939            HashSet::new(),
1940            zx::MonotonicInstant::ZERO,
1941            &DESCRIPTOR,
1942        ),
1943        create_mouse_pointer_sample_event_with_wheel_physical_pixel(
1944            pointerinjector::EventPhase::Change,
1945            vec![],
1946            Position { x: 50.0, y: 50.0 },
1947            None,        /*relative_motion*/
1948            None,        /*wheel_delta_v*/
1949            None,        /*wheel_delta_h*/
1950            None,        /*wheel_delta_v_physical_pixel*/
1951            Some(120.0), /*wheel_delta_h_physical_pixel*/
1952            Some(true),  /*is_precision_scroll*/
1953            zx::MonotonicInstant::ZERO,
1954        ); "h mm scroll with physical pixel"
1955    )]
1956    /// Test simple scroll in vertical and horizontal.
1957    #[fuchsia::test(allow_stalls = false)]
1958    async fn scroll(event: input_device::InputEvent, want_event: pointerinjector::Event) {
1959        // Set up fidl streams.
1960        let (configuration_proxy, mut configuration_request_stream) =
1961            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1962        let (injector_registry_proxy, injector_registry_request_stream) =
1963            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
1964        let config_request_stream_fut =
1965            handle_configuration_request_stream(&mut configuration_request_stream);
1966
1967        // Create MouseInjectorHandler.
1968        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(1);
1969        let inspector = fuchsia_inspect::Inspector::default();
1970        let test_node = inspector.root().create_child("test_node");
1971        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1972            configuration_proxy,
1973            injector_registry_proxy,
1974            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1975            sender,
1976            &test_node,
1977            metrics::MetricsLogger::default(),
1978        );
1979        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1980        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1981
1982        // Create a channel for the the registered device's handle to be forwarded to the
1983        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1984        // handle_input_event() to continue.
1985        let (injector_stream_sender, injector_stream_receiver) =
1986            mpsc::unbounded::<Vec<pointerinjector::Event>>();
1987        // Up to 2 events per handle_input_event() call.
1988        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
1989        let registry_fut = handle_registry_request_stream2(
1990            injector_registry_request_stream,
1991            injector_stream_sender,
1992        );
1993
1994        let event_time = zx::MonotonicInstant::get();
1995
1996        let event = input_device::InputEvent { event_time, ..event };
1997
1998        let want_event =
1999            pointerinjector::Event { timestamp: Some(event_time.into_nanos()), ..want_event };
2000
2001        // Run future until the handler future completes.
2002        let _registry_task = fasync::Task::local(registry_fut);
2003
2004        mouse_handler.clone().handle_input_event(event).await;
2005        let got_events =
2006            injector_stream_receiver.next().await.map(|events| events.concat()).unwrap();
2007        pretty_assertions::assert_eq!(got_events.len(), 2);
2008        assert_matches!(
2009            got_events[0],
2010            pointerinjector::Event {
2011                data: Some(pointerinjector::Data::PointerSample(pointerinjector::PointerSample {
2012                    phase: Some(pointerinjector::EventPhase::Add),
2013                    ..
2014                })),
2015                ..
2016            }
2017        );
2018
2019        pretty_assertions::assert_eq!(got_events[1], want_event);
2020    }
2021
2022    /// Test button down -> scroll -> button up -> continue scroll.
2023    #[fuchsia::test(allow_stalls = false)]
2024    async fn down_scroll_up_scroll() {
2025        // Set up fidl streams.
2026        let (configuration_proxy, mut configuration_request_stream) =
2027            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
2028        let (injector_registry_proxy, injector_registry_request_stream) =
2029            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
2030        let config_request_stream_fut =
2031            handle_configuration_request_stream(&mut configuration_request_stream);
2032
2033        // Create MouseInjectorHandler.
2034        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(1);
2035        let inspector = fuchsia_inspect::Inspector::default();
2036        let test_node = inspector.root().create_child("test_node");
2037        let mouse_handler_fut = MouseInjectorHandler::new_handler(
2038            configuration_proxy,
2039            injector_registry_proxy,
2040            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
2041            sender,
2042            &test_node,
2043            metrics::MetricsLogger::default(),
2044        );
2045        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
2046        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
2047
2048        // Create a channel for the the registered device's handle to be forwarded to the
2049        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
2050        // handle_input_event() to continue.
2051        let (injector_stream_sender, injector_stream_receiver) =
2052            mpsc::unbounded::<Vec<pointerinjector::Event>>();
2053        // Up to 2 events per handle_input_event() call.
2054        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
2055        let registry_fut = handle_registry_request_stream2(
2056            injector_registry_request_stream,
2057            injector_stream_sender,
2058        );
2059
2060        let event_time1 = zx::MonotonicInstant::get();
2061        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
2062        let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
2063        let event_time4 = event_time3.add(zx::MonotonicDuration::from_micros(1));
2064
2065        // Run future until the handler future completes.
2066        let _registry_task = fasync::Task::local(registry_fut);
2067
2068        let zero_location =
2069            mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
2070                millimeters: Position { x: 0.0, y: 0.0 },
2071            });
2072        let expected_position = Position { x: 50.0, y: 50.0 };
2073
2074        let down_event = create_mouse_event(
2075            zero_location,
2076            None, /* wheel_delta_v */
2077            None, /* wheel_delta_h */
2078            None, /* is_precision_scroll */
2079            mouse_binding::MousePhase::Down,
2080            HashSet::from_iter(vec![1]),
2081            HashSet::from_iter(vec![1]),
2082            event_time1,
2083            &DESCRIPTOR,
2084        );
2085
2086        let wheel_event = create_mouse_event(
2087            zero_location,
2088            wheel_delta_ticks(1, None),               /* wheel_delta_v */
2089            None,                                     /* wheel_delta_h */
2090            Some(mouse_binding::PrecisionScroll::No), /* is_precision_scroll */
2091            mouse_binding::MousePhase::Wheel,
2092            HashSet::from_iter(vec![1]),
2093            HashSet::from_iter(vec![1]),
2094            event_time2,
2095            &DESCRIPTOR,
2096        );
2097
2098        let up_event = create_mouse_event(
2099            zero_location,
2100            None,
2101            None,
2102            None, /* is_precision_scroll */
2103            mouse_binding::MousePhase::Up,
2104            HashSet::from_iter(vec![1]),
2105            HashSet::new(),
2106            event_time3,
2107            &DESCRIPTOR,
2108        );
2109
2110        let continue_wheel_event = create_mouse_event(
2111            zero_location,
2112            wheel_delta_ticks(1, None),               /* wheel_delta_v */
2113            None,                                     /* wheel_delta_h */
2114            Some(mouse_binding::PrecisionScroll::No), /* is_precision_scroll */
2115            mouse_binding::MousePhase::Wheel,
2116            HashSet::new(),
2117            HashSet::new(),
2118            event_time4,
2119            &DESCRIPTOR,
2120        );
2121
2122        // Handle button down event.
2123        mouse_handler.clone().handle_input_event(down_event).await;
2124        assert_eq!(
2125            injector_stream_receiver.next().await.map(|events| events.concat()),
2126            Some(vec![
2127                create_mouse_pointer_sample_event_phase_add(
2128                    vec![1],
2129                    expected_position,
2130                    event_time1,
2131                ),
2132                create_mouse_pointer_sample_event(
2133                    pointerinjector::EventPhase::Change,
2134                    vec![1],
2135                    expected_position,
2136                    None, /*relative_motion*/
2137                    None, /*wheel_delta_v*/
2138                    None, /*wheel_delta_h*/
2139                    None, /*is_precision_scroll*/
2140                    event_time1,
2141                ),
2142            ])
2143        );
2144
2145        // Handle wheel event with button pressing.
2146        mouse_handler.clone().handle_input_event(wheel_event).await;
2147        assert_eq!(
2148            injector_stream_receiver.next().await.map(|events| events.concat()),
2149            Some(vec![create_mouse_pointer_sample_event(
2150                pointerinjector::EventPhase::Change,
2151                vec![1],
2152                expected_position,
2153                None,        /*relative_motion*/
2154                Some(1),     /*wheel_delta_v*/
2155                None,        /*wheel_delta_h*/
2156                Some(false), /*is_precision_scroll*/
2157                event_time2,
2158            )])
2159        );
2160
2161        // Handle button up event.
2162        mouse_handler.clone().handle_input_event(up_event).await;
2163        assert_eq!(
2164            injector_stream_receiver.next().await.map(|events| events.concat()),
2165            Some(vec![create_mouse_pointer_sample_event(
2166                pointerinjector::EventPhase::Change,
2167                vec![],
2168                expected_position,
2169                None, /*relative_motion*/
2170                None, /*wheel_delta_v*/
2171                None, /*wheel_delta_h*/
2172                None, /*is_precision_scroll*/
2173                event_time3,
2174            )])
2175        );
2176
2177        // Handle wheel event after button released.
2178        mouse_handler.clone().handle_input_event(continue_wheel_event).await;
2179        assert_eq!(
2180            injector_stream_receiver.next().await.map(|events| events.concat()),
2181            Some(vec![create_mouse_pointer_sample_event(
2182                pointerinjector::EventPhase::Change,
2183                vec![],
2184                expected_position,
2185                None,        /*relative_motion*/
2186                Some(1),     /*wheel_delta_v*/
2187                None,        /*wheel_delta_h*/
2188                Some(false), /*is_precision_scroll*/
2189                event_time4,
2190            )])
2191        );
2192    }
2193
2194    #[fuchsia::test(allow_stalls = false)]
2195    async fn mouse_injector_handler_initialized_with_inspect_node() {
2196        let (configuration_proxy, mut configuration_request_stream) =
2197            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
2198        let config_request_stream_fut =
2199            handle_configuration_request_stream(&mut configuration_request_stream);
2200        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(1);
2201        let inspector = fuchsia_inspect::Inspector::default();
2202        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
2203        let mouse_handler_fut = MouseInjectorHandler::new_with_config_proxy(
2204            configuration_proxy,
2205            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
2206            sender,
2207            &fake_handlers_node,
2208            metrics::MetricsLogger::default(),
2209        );
2210        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
2211        let _handler = mouse_handler_res.expect("Failed to create mouse handler");
2212
2213        diagnostics_assertions::assert_data_tree!(inspector, root: {
2214            input_handlers_node: {
2215                mouse_injector_handler: {
2216                    events_received_count: 0u64,
2217                    events_handled_count: 0u64,
2218                    last_received_timestamp_ns: 0u64,
2219                    "fuchsia.inspect.Health": {
2220                        status: "STARTING_UP",
2221                        // Timestamp value is unpredictable and not relevant in this context,
2222                        // so we only assert that the property is present.
2223                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
2224                    },
2225                }
2226            }
2227        });
2228    }
2229
2230    #[fuchsia::test(allow_stalls = false)]
2231    async fn mouse_injector_handler_inspect_counts_events() {
2232        // Set up fidl streams.
2233        let (configuration_proxy, mut configuration_request_stream) =
2234            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
2235        let (injector_registry_proxy, injector_registry_request_stream) =
2236            fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
2237        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(1);
2238
2239        let inspector = fuchsia_inspect::Inspector::default();
2240        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
2241
2242        // Create mouse handler.
2243        let mouse_handler_fut = MouseInjectorHandler::new_handler(
2244            configuration_proxy,
2245            injector_registry_proxy,
2246            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
2247            sender,
2248            &fake_handlers_node,
2249            metrics::MetricsLogger::default(),
2250        );
2251        let config_request_stream_fut =
2252            handle_configuration_request_stream(&mut configuration_request_stream);
2253
2254        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
2255        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
2256
2257        let cursor_location = mouse_binding::MouseLocation::Absolute(Position { x: 0.0, y: 0.0 });
2258        let event_time1 = zx::MonotonicInstant::get();
2259        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
2260        let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
2261
2262        let input_events = vec![
2263            create_mouse_event(
2264                cursor_location,
2265                None, /* wheel_delta_v */
2266                None, /* wheel_delta_h */
2267                None, /* is_precision_scroll */
2268                mouse_binding::MousePhase::Down,
2269                HashSet::from_iter(vec![1]),
2270                HashSet::from_iter(vec![1]),
2271                event_time1,
2272                &DESCRIPTOR,
2273            ),
2274            create_mouse_event(
2275                cursor_location,
2276                None, /* wheel_delta_v */
2277                None, /* wheel_delta_h */
2278                None, /* is_precision_scroll */
2279                mouse_binding::MousePhase::Up,
2280                HashSet::from_iter(vec![1]),
2281                HashSet::new(),
2282                event_time2,
2283                &DESCRIPTOR,
2284            ),
2285            create_mouse_event_with_handled(
2286                cursor_location,
2287                None, /* wheel_delta_v */
2288                None, /* wheel_delta_h */
2289                None, /* is_precision_scroll */
2290                mouse_binding::MousePhase::Down,
2291                HashSet::from_iter(vec![1]),
2292                HashSet::from_iter(vec![1]),
2293                event_time3,
2294                &DESCRIPTOR,
2295                input_device::Handled::Yes,
2296            ),
2297        ];
2298
2299        // Create a channel for the the registered device's handle to be forwarded to the
2300        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
2301        // handle_input_event() to continue.
2302        let (injector_stream_sender, _) = mpsc::unbounded::<Vec<pointerinjector::Event>>();
2303        let registry_fut = handle_registry_request_stream2(
2304            injector_registry_request_stream,
2305            injector_stream_sender,
2306        );
2307
2308        // Run future until the handler future completes.
2309        let _registry_task = fasync::Task::local(registry_fut);
2310        for input_event in input_events {
2311            mouse_handler.clone().handle_input_event(input_event).await;
2312        }
2313
2314        let last_received_event_time: u64 = event_time2.into_nanos().try_into().unwrap();
2315
2316        diagnostics_assertions::assert_data_tree!(inspector, root: {
2317            input_handlers_node: {
2318                mouse_injector_handler: {
2319                    events_received_count: 2u64,
2320                    events_handled_count: 2u64,
2321                    last_received_timestamp_ns: last_received_event_time,
2322                    "fuchsia.inspect.Health": {
2323                        status: "STARTING_UP",
2324                        // Timestamp value is unpredictable and not relevant in this context,
2325                        // so we only assert that the property is present.
2326                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
2327                    },
2328                }
2329            }
2330        });
2331    }
2332}