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