input_pipeline/
mouse_injector_handler.rs

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