Skip to main content

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