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