Skip to main content

input_pipeline/
mouse_injector_handler.rs

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