1use crate::{
6 Dispatcher, Incoming, Transport, consumer_controls_binding, keyboard_binding,
7 light_sensor_binding, metrics, mouse_binding, touch_binding,
8};
9use anyhow::{Error, format_err};
10use async_trait::async_trait;
11use fidl_fuchsia_io as fio;
12use fidl_next_fuchsia_input_report::InputDevice;
13use fuchsia_inspect::health::Reporter;
14use fuchsia_inspect::{
15 ExponentialHistogramParams, HistogramProperty as _, NumericProperty, Property,
16};
17use fuchsia_trace as ftrace;
18use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
19use futures::stream::StreamExt;
20use metrics_registry::*;
21use sorted_vec_map::SortedVecSet;
22use std::path::PathBuf;
23use strum_macros::{Display, EnumCount};
24
25pub use input_device_constants::InputDeviceType;
26
27#[derive(Debug, Clone, Default)]
28pub struct InputPipelineFeatureFlags {
29 pub enable_merge_touch_events: bool,
31}
32
33pub static INPUT_REPORT_PATH: &str = "/dev/class/input-report";
35
36const LATENCY_HISTOGRAM_PROPERTIES: ExponentialHistogramParams<i64> = ExponentialHistogramParams {
37 floor: 0,
38 initial_step: 1,
39 step_multiplier: 10,
40 buckets: 7,
51};
52
53pub struct InputDeviceStatus {
56 now: Box<dyn Fn() -> zx::MonotonicInstant>,
59
60 _node: fuchsia_inspect::Node,
62
63 reports_received_count: fuchsia_inspect::UintProperty,
65
66 reports_filtered_count: fuchsia_inspect::UintProperty,
69
70 events_generated: fuchsia_inspect::UintProperty,
73
74 last_received_timestamp_ns: fuchsia_inspect::UintProperty,
76
77 last_generated_timestamp_ns: fuchsia_inspect::UintProperty,
79
80 pub health_node: fuchsia_inspect::health::Node,
82
83 driver_to_binding_latency_ms: fuchsia_inspect::IntExponentialHistogramProperty,
88
89 wake_lease_leak_count: fuchsia_inspect::UintProperty,
91}
92
93impl InputDeviceStatus {
94 pub fn new(device_node: fuchsia_inspect::Node) -> Self {
95 Self::new_internal(device_node, Box::new(zx::MonotonicInstant::get))
96 }
97
98 fn new_internal(
99 device_node: fuchsia_inspect::Node,
100 now: Box<dyn Fn() -> zx::MonotonicInstant>,
101 ) -> Self {
102 let mut health_node = fuchsia_inspect::health::Node::new(&device_node);
103 health_node.set_starting_up();
104
105 let reports_received_count = device_node.create_uint("reports_received_count", 0);
106 let reports_filtered_count = device_node.create_uint("reports_filtered_count", 0);
107 let events_generated = device_node.create_uint("events_generated", 0);
108 let last_received_timestamp_ns = device_node.create_uint("last_received_timestamp_ns", 0);
109 let last_generated_timestamp_ns = device_node.create_uint("last_generated_timestamp_ns", 0);
110 let driver_to_binding_latency_ms = device_node.create_int_exponential_histogram(
111 "driver_to_binding_latency_ms",
112 LATENCY_HISTOGRAM_PROPERTIES,
113 );
114 let wake_lease_leak_count = device_node.create_uint("wake_lease_leak_count", 0);
115
116 Self {
117 now,
118 _node: device_node,
119 reports_received_count,
120 reports_filtered_count,
121 events_generated,
122 last_received_timestamp_ns,
123 last_generated_timestamp_ns,
124 health_node,
125 driver_to_binding_latency_ms,
126 wake_lease_leak_count,
127 }
128 }
129
130 pub fn count_received_report_wire(
131 &self,
132 report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
133 ) {
134 self.reports_received_count.add(1);
135 match report.event_time() {
136 Some(event_time) => {
137 self.driver_to_binding_latency_ms.insert(
138 ((self.now)() - zx::MonotonicInstant::from_nanos(event_time.0)).into_millis(),
139 );
140 self.last_received_timestamp_ns.set(event_time.0.try_into().unwrap());
141 }
142 None => (),
143 }
144 }
145
146 pub fn count_filtered_report(&self) {
147 self.reports_filtered_count.add(1);
148 }
149
150 pub fn count_generated_event(&self, event: InputEvent) {
151 self.events_generated.add(1);
152 self.last_generated_timestamp_ns.set(event.event_time.into_nanos().try_into().unwrap());
153 }
154
155 pub fn count_generated_events(&self, events: &Vec<InputEvent>) {
156 self.events_generated.add(events.len() as u64);
157 if let Some(last_event) = events.last() {
158 self.last_generated_timestamp_ns
159 .set(last_event.event_time.into_nanos().try_into().unwrap());
160 }
161 }
162
163 pub fn count_wake_lease_leak(&self) {
164 self.wake_lease_leak_count.add(1);
165 }
166}
167
168#[derive(Clone, Debug, PartialEq)]
169pub enum PreviousDeviceState {
170 Keyboard {
171 pressed_keys: Vec<fidl_fuchsia_input::Key>,
172 },
173 Mouse {
174 pressed_buttons: SortedVecSet<mouse_binding::MouseButton>,
175 },
176 TouchScreen {
177 active_contacts: Vec<touch_binding::TouchContact>,
178 pressed_buttons: Vec<fidl_next_fuchsia_input_report::TouchButton>,
179 },
180 ConsumerControls {
181 pressed_buttons: Vec<fidl_fuchsia_input_report::ConsumerControlButton>,
182 },
183 LightSensor,
184 #[cfg(test)]
185 Fake,
186}
187
188#[derive(Clone, Debug, PartialEq)]
190pub struct InputEvent {
191 pub device_event: InputDeviceEvent,
193
194 pub device_descriptor: InputDeviceDescriptor,
197
198 pub event_time: zx::MonotonicInstant,
200
201 pub handled: Handled,
203
204 pub trace_id: Option<ftrace::Id>,
205}
206
207#[derive(Clone, Debug, PartialEq)]
213pub struct UnhandledInputEvent {
214 pub device_event: InputDeviceEvent,
216
217 pub device_descriptor: InputDeviceDescriptor,
220
221 pub event_time: zx::MonotonicInstant,
223
224 pub trace_id: Option<ftrace::Id>,
225}
226
227impl UnhandledInputEvent {
228 pub fn get_event_type(&self) -> &'static str {
230 match self.device_event {
231 InputDeviceEvent::Keyboard(_) => "keyboard_event",
232 InputDeviceEvent::LightSensor(_) => "light_sensor_event",
233 InputDeviceEvent::ConsumerControls(_) => "consumer_controls_event",
234 InputDeviceEvent::Mouse(_) => "mouse_event",
235 InputDeviceEvent::TouchScreen(_) => "touch_screen_event",
236 InputDeviceEvent::Touchpad(_) => "touchpad_event",
237 #[cfg(test)]
238 InputDeviceEvent::Fake => "fake_event",
239 }
240 }
241}
242
243#[derive(Clone, Debug, PartialEq)]
252pub enum InputDeviceEvent {
253 Keyboard(keyboard_binding::KeyboardEvent),
254 LightSensor(light_sensor_binding::LightSensorEvent),
255 ConsumerControls(consumer_controls_binding::ConsumerControlsEvent),
256 Mouse(mouse_binding::MouseEvent),
257 TouchScreen(touch_binding::TouchScreenEvent),
258 Touchpad(touch_binding::TouchpadEvent),
259 #[cfg(test)]
260 Fake,
261}
262
263#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumCount, Display)]
265#[strum(serialize_all = "snake_case")]
266pub enum InputEventType {
267 Keyboard = 0,
268 LightSensor = 1,
269 ConsumerControls = 2,
270 Mouse = 3,
271 TouchScreen = 4,
272 Touchpad = 5,
273 #[cfg(test)]
274 Fake = 6,
275}
276
277impl From<&InputDeviceEvent> for InputEventType {
278 fn from(event: &InputDeviceEvent) -> Self {
279 match event {
280 InputDeviceEvent::Keyboard(_) => InputEventType::Keyboard,
281 InputDeviceEvent::LightSensor(_) => InputEventType::LightSensor,
282 InputDeviceEvent::ConsumerControls(_) => InputEventType::ConsumerControls,
283 InputDeviceEvent::Mouse(_) => InputEventType::Mouse,
284 InputDeviceEvent::TouchScreen(_) => InputEventType::TouchScreen,
285 InputDeviceEvent::Touchpad(_) => InputEventType::Touchpad,
286 #[cfg(test)]
287 InputDeviceEvent::Fake => InputEventType::Fake,
288 }
289 }
290}
291
292#[derive(Clone, Debug, PartialEq)]
302pub enum InputDeviceDescriptor {
303 Keyboard(keyboard_binding::KeyboardDeviceDescriptor),
304 LightSensor(light_sensor_binding::LightSensorDeviceDescriptor),
305 ConsumerControls(consumer_controls_binding::ConsumerControlsDeviceDescriptor),
306 Mouse(mouse_binding::MouseDeviceDescriptor),
307 TouchScreen(touch_binding::TouchScreenDeviceDescriptor),
308 Touchpad(touch_binding::TouchpadDeviceDescriptor),
309 #[cfg(test)]
310 Fake,
311}
312
313impl From<keyboard_binding::KeyboardDeviceDescriptor> for InputDeviceDescriptor {
314 fn from(b: keyboard_binding::KeyboardDeviceDescriptor) -> Self {
315 InputDeviceDescriptor::Keyboard(b)
316 }
317}
318
319impl InputDeviceDescriptor {
320 pub fn device_id(&self) -> u32 {
321 match self {
322 InputDeviceDescriptor::Keyboard(b) => b.device_id,
323 InputDeviceDescriptor::LightSensor(b) => b.device_id,
324 InputDeviceDescriptor::ConsumerControls(b) => b.device_id,
325 InputDeviceDescriptor::Mouse(b) => b.device_id,
326 InputDeviceDescriptor::TouchScreen(b) => b.device_id,
327 InputDeviceDescriptor::Touchpad(b) => b.device_id,
328 #[cfg(test)]
329 InputDeviceDescriptor::Fake => 0,
330 }
331 }
332}
333
334#[derive(Copy, Clone, Debug, PartialEq)]
336pub enum Handled {
337 Yes,
339 No,
341}
342
343#[async_trait]
352pub trait InputDeviceBinding: Send {
353 fn get_device_descriptor(&self) -> InputDeviceDescriptor;
355
356 fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>>;
358}
359
360pub fn initialize_report_stream<InputDeviceProcessReportsFn>(
377 device_proxy: fidl_next::Client<InputDevice, Transport>,
378 device_descriptor: InputDeviceDescriptor,
379 mut event_sender: UnboundedSender<Vec<InputEvent>>,
380 inspect_status: InputDeviceStatus,
381 metrics_logger: metrics::MetricsLogger,
382 feature_flags: InputPipelineFeatureFlags,
383 mut process_reports: InputDeviceProcessReportsFn,
384) where
385 InputDeviceProcessReportsFn: 'static
386 + Send
387 + for<'de> FnMut(
388 &[fidl_next_fuchsia_input_report::wire::InputReport<'_>],
389 Option<PreviousDeviceState>,
390 &InputDeviceDescriptor,
391 &mut UnboundedSender<Vec<InputEvent>>,
392 &InputDeviceStatus,
393 &metrics::MetricsLogger,
394 &InputPipelineFeatureFlags,
395 )
396 -> (Option<PreviousDeviceState>, Option<UnboundedReceiver<InputEvent>>),
397{
398 Dispatcher::spawn_local(async move {
399 let mut previous_state: Option<PreviousDeviceState> = None;
400 let (report_reader, server_end) = fidl_next::fuchsia::create_channel();
401 let report_reader = Dispatcher::client_from_zx_channel(report_reader);
402 let result = device_proxy.get_input_reports_reader(server_end).await;
403 if result.is_err() {
404 metrics_logger.log_error(
405 InputPipelineErrorMetricDimensionEvent::InputDeviceGetInputReportsReaderError,
406 std::format!("error on GetInputReportsReader: {:?}", result),
407 );
408 return; }
410 let report_reader = report_reader.spawn();
411 loop {
412 let read_result = {
413 fuchsia_trace::duration!("input", "read_input_reports");
414 report_reader.read_input_reports().wire().await
415 };
416 match read_result {
417 Err(_fidl_error) => break,
418 Ok(decoded) => match decoded.as_ref() {
419 Err(_service_error) => break,
420 Ok(response) => {
421 fuchsia_trace::duration!("input", "input-device-process-reports");
422 let (prev_state, inspect_receiver) = process_reports(
425 response.reports.as_slice(),
426 previous_state,
427 &device_descriptor,
428 &mut event_sender,
429 &inspect_status,
430 &metrics_logger,
431 &feature_flags,
432 );
433 previous_state = prev_state;
434
435 match inspect_receiver {
439 Some(mut receiver) => {
440 while let Some(event) = receiver.next().await {
441 inspect_status.count_generated_event(event);
442 }
443 }
444 None => (),
445 };
446 }
447 },
448 }
449 }
450 log::warn!("initialize_report_stream exited - device binding no longer works");
453 })
454 .detach();
455}
456
457pub async fn is_device_type(
463 device_descriptor: &fidl_next_fuchsia_input_report::DeviceDescriptor,
464 device_type: InputDeviceType,
465) -> bool {
466 match device_type {
468 InputDeviceType::ConsumerControls => device_descriptor.consumer_control.is_some(),
469 InputDeviceType::Mouse => device_descriptor.mouse.is_some(),
470 InputDeviceType::Touch => device_descriptor.touch.is_some(),
471 InputDeviceType::Keyboard => device_descriptor.keyboard.is_some(),
472 InputDeviceType::LightSensor => device_descriptor.sensor.is_some(),
473 }
474}
475
476pub async fn get_device_binding(
484 device_type: InputDeviceType,
485 device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
486 device_id: u32,
487 input_event_sender: UnboundedSender<Vec<InputEvent>>,
488 device_node: fuchsia_inspect::Node,
489 feature_flags: InputPipelineFeatureFlags,
490 metrics_logger: metrics::MetricsLogger,
491) -> Result<Box<dyn InputDeviceBinding>, Error> {
492 match device_type {
493 InputDeviceType::ConsumerControls => {
494 let binding = consumer_controls_binding::ConsumerControlsBinding::new(
495 device_proxy,
496 device_id,
497 input_event_sender,
498 device_node,
499 feature_flags.clone(),
500 metrics_logger,
501 )
502 .await?;
503 Ok(Box::new(binding))
504 }
505 InputDeviceType::Mouse => {
506 let binding = mouse_binding::MouseBinding::new(
507 device_proxy,
508 device_id,
509 input_event_sender,
510 device_node,
511 feature_flags.clone(),
512 metrics_logger,
513 )
514 .await?;
515 Ok(Box::new(binding))
516 }
517 InputDeviceType::Touch => {
518 let binding = touch_binding::TouchBinding::new(
519 device_proxy,
520 device_id,
521 input_event_sender,
522 device_node,
523 feature_flags.clone(),
524 metrics_logger,
525 )
526 .await?;
527 Ok(Box::new(binding))
528 }
529 InputDeviceType::Keyboard => {
530 let binding = keyboard_binding::KeyboardBinding::new(
531 device_proxy,
532 device_id,
533 input_event_sender,
534 device_node,
535 feature_flags.clone(),
536 metrics_logger,
537 )
538 .await?;
539 Ok(Box::new(binding))
540 }
541 InputDeviceType::LightSensor => {
542 let binding = light_sensor_binding::LightSensorBinding::new(
543 device_proxy,
544 device_id,
545 input_event_sender,
546 device_node,
547 feature_flags.clone(),
548 metrics_logger,
549 )
550 .await?;
551 Ok(Box::new(binding))
552 }
553 }
554}
555
556pub fn get_device_from_dir_entry_path(
565 dir_proxy: &fio::DirectoryProxy,
566 entry_path: &PathBuf,
567) -> Result<fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>, Error> {
568 let input_device_path = entry_path.to_str();
569 if input_device_path.is_none() {
570 return Err(format_err!("Failed to get entry path as a string."));
571 }
572
573 let input_device = Incoming::connect_protocol_next_at(dir_proxy, input_device_path.unwrap())
574 .expect("Failed to connect to InputDevice.");
575 Ok(input_device.spawn())
576}
577
578pub fn event_time_or_now(event_time: Option<i64>) -> zx::MonotonicInstant {
583 match event_time {
584 Some(time) => zx::MonotonicInstant::from_nanos(time),
585 None => zx::MonotonicInstant::get(),
586 }
587}
588
589impl std::convert::From<UnhandledInputEvent> for InputEvent {
590 fn from(event: UnhandledInputEvent) -> Self {
591 Self {
592 device_event: event.device_event,
593 device_descriptor: event.device_descriptor,
594 event_time: event.event_time,
595 handled: Handled::No,
596 trace_id: event.trace_id,
597 }
598 }
599}
600
601#[cfg(test)]
608impl std::convert::TryFrom<InputEvent> for UnhandledInputEvent {
609 type Error = anyhow::Error;
610 fn try_from(event: InputEvent) -> Result<UnhandledInputEvent, Self::Error> {
611 match event.handled {
612 Handled::Yes => {
613 Err(format_err!("Attempted to treat a handled InputEvent as unhandled"))
614 }
615 Handled::No => Ok(UnhandledInputEvent {
616 device_event: event.device_event,
617 device_descriptor: event.device_descriptor,
618 event_time: event.event_time,
619 trace_id: event.trace_id,
620 }),
621 }
622 }
623}
624
625impl InputEvent {
626 pub(crate) fn into_handled_if(self, predicate: bool) -> Self {
629 if predicate { Self { handled: Handled::Yes, ..self } } else { self }
630 }
631
632 pub(crate) fn into_handled(self) -> Self {
634 Self { handled: Handled::Yes, ..self }
635 }
636
637 pub fn into_with_event_time(self, event_time: zx::MonotonicInstant) -> Self {
639 Self { event_time, ..self }
640 }
641
642 #[cfg(test)]
644 pub fn into_with_device_descriptor(self, device_descriptor: InputDeviceDescriptor) -> Self {
645 Self { device_descriptor, ..self }
646 }
647
648 pub fn is_handled(&self) -> bool {
650 self.handled == Handled::Yes
651 }
652
653 pub fn get_event_type(&self) -> &'static str {
655 match self.device_event {
656 InputDeviceEvent::Keyboard(_) => "keyboard_event",
657 InputDeviceEvent::LightSensor(_) => "light_sensor_event",
658 InputDeviceEvent::ConsumerControls(_) => "consumer_controls_event",
659 InputDeviceEvent::Mouse(_) => "mouse_event",
660 InputDeviceEvent::TouchScreen(_) => "touch_screen_event",
661 InputDeviceEvent::Touchpad(_) => "touchpad_event",
662 #[cfg(test)]
663 InputDeviceEvent::Fake => "fake_event",
664 }
665 }
666
667 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
668 node.record_int("event_time", self.event_time.into_nanos());
669 match &self.device_event {
670 InputDeviceEvent::LightSensor(e) => e.record_inspect(node),
671 InputDeviceEvent::ConsumerControls(e) => e.record_inspect(node),
672 InputDeviceEvent::Mouse(e) => e.record_inspect(node),
673 InputDeviceEvent::TouchScreen(e) => e.record_inspect(node),
674 InputDeviceEvent::Touchpad(e) => e.record_inspect(node),
675 InputDeviceEvent::Keyboard(_) => (),
677 #[cfg(test)] InputDeviceEvent::Fake => (),
679 }
680 }
681}
682
683#[cfg(test)]
684mod tests {
685 use super::*;
686 use crate::testing_utilities::spawn_input_stream_handler;
687 use assert_matches::assert_matches;
688 use diagnostics_assertions::AnyProperty;
689 use fidl_fuchsia_input_report as fidl_input_report;
690 use fidl_next_fuchsia_input_report::InputReport;
691 use fuchsia_async as fasync;
692 use pretty_assertions::assert_eq;
693 use std::convert::TryFrom as _;
694 use test_case::test_case;
695
696 #[test]
697 fn max_event_time() {
698 let event_time = event_time_or_now(Some(i64::MAX));
699 assert_eq!(event_time, zx::MonotonicInstant::INFINITE);
700 }
701
702 #[test]
703 fn min_event_time() {
704 let event_time = event_time_or_now(Some(std::i64::MIN));
705 assert_eq!(event_time, zx::MonotonicInstant::INFINITE_PAST);
706 }
707
708 #[fasync::run_singlethreaded(test)]
709 async fn input_device_status_initialized_with_correct_properties() {
710 let inspector = fuchsia_inspect::Inspector::default();
711 let input_pipeline_node = inspector.root().create_child("input_pipeline");
712 let input_devices_node = input_pipeline_node.create_child("input_devices");
713 let device_node = input_devices_node.create_child("001_keyboard");
714 let _input_device_status = InputDeviceStatus::new(device_node);
715 diagnostics_assertions::assert_data_tree!(inspector, root: {
716 input_pipeline: {
717 input_devices: {
718 "001_keyboard": {
719 reports_received_count: 0u64,
720 reports_filtered_count: 0u64,
721 events_generated: 0u64,
722 last_received_timestamp_ns: 0u64,
723 last_generated_timestamp_ns: 0u64,
724 "fuchsia.inspect.Health": {
725 status: "STARTING_UP",
726 start_timestamp_nanos: AnyProperty
729 },
730 driver_to_binding_latency_ms: diagnostics_assertions::HistogramAssertion::exponential(super::LATENCY_HISTOGRAM_PROPERTIES),
731 wake_lease_leak_count: 0u64,
732 }
733 }
734 }
735 });
736 }
737
738 #[test_case(i64::MIN; "min value")]
739 #[test_case(-1; "negative value")]
740 #[test_case(0; "zero")]
741 #[test_case(1; "positive value")]
742 #[test_case(i64::MAX; "max value")]
743 #[fuchsia::test(allow_stalls = false)]
744 async fn input_device_status_updates_latency_histogram_on_count_received_report_wire(
745 latency_nsec: i64,
746 ) {
747 let mut expected_histogram = diagnostics_assertions::HistogramAssertion::exponential(
748 super::LATENCY_HISTOGRAM_PROPERTIES,
749 );
750 let inspector = fuchsia_inspect::Inspector::default();
751 let input_device_status = InputDeviceStatus::new_internal(
752 inspector.root().clone_weak(),
753 Box::new(move || zx::MonotonicInstant::from_nanos(latency_nsec)),
754 );
755 let decoded = crate::testing_utilities::report_to_wire(InputReport {
756 event_time: Some(0),
757 ..InputReport::default()
758 });
759 input_device_status.count_received_report_wire(&decoded);
760 expected_histogram.insert_values([latency_nsec / 1000 / 1000]);
761 diagnostics_assertions::assert_data_tree!(inspector, root: contains {
762 driver_to_binding_latency_ms: expected_histogram,
763 });
764 }
765
766 #[fasync::run_singlethreaded(test)]
769 async fn consumer_controls_input_device_exists() {
770 let input_device_proxy =
771 spawn_input_stream_handler(move |input_device_request| async move {
772 match input_device_request {
773 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
774 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
775 device_information: None,
776 mouse: None,
777 sensor: None,
778 touch: None,
779 keyboard: None,
780 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
781 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
782 buttons: Some(vec![
783 fidl_input_report::ConsumerControlButton::VolumeUp,
784 fidl_input_report::ConsumerControlButton::VolumeDown,
785 ]),
786 ..Default::default()
787 }),
788 ..Default::default()
789 }),
790 ..Default::default()
791 });
792 }
793 _ => panic!("InputDevice handler received an unexpected request"),
794 }
795 });
796
797 assert!(
798 is_device_type(
799 &input_device_proxy
800 .get_descriptor()
801 .await
802 .expect("Failed to get device descriptor")
803 .descriptor,
804 InputDeviceType::ConsumerControls
805 )
806 .await
807 );
808 }
809
810 #[fasync::run_singlethreaded(test)]
812 async fn mouse_input_device_exists() {
813 let input_device_proxy =
814 spawn_input_stream_handler(move |input_device_request| async move {
815 match input_device_request {
816 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
817 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
818 device_information: None,
819 mouse: Some(fidl_input_report::MouseDescriptor {
820 input: Some(fidl_input_report::MouseInputDescriptor {
821 movement_x: None,
822 movement_y: None,
823 position_x: None,
824 position_y: None,
825 scroll_v: None,
826 scroll_h: None,
827 buttons: None,
828 ..Default::default()
829 }),
830 ..Default::default()
831 }),
832 sensor: None,
833 touch: None,
834 keyboard: None,
835 consumer_control: None,
836 ..Default::default()
837 });
838 }
839 _ => panic!("InputDevice handler received an unexpected request"),
840 }
841 });
842
843 assert!(
844 is_device_type(
845 &input_device_proxy
846 .get_descriptor()
847 .await
848 .expect("Failed to get device descriptor")
849 .descriptor,
850 InputDeviceType::Mouse
851 )
852 .await
853 );
854 }
855
856 #[fasync::run_singlethreaded(test)]
859 async fn mouse_input_device_doesnt_exist() {
860 let input_device_proxy =
861 spawn_input_stream_handler(move |input_device_request| async move {
862 match input_device_request {
863 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
864 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
865 device_information: None,
866 mouse: None,
867 sensor: None,
868 touch: None,
869 keyboard: None,
870 consumer_control: None,
871 ..Default::default()
872 });
873 }
874 _ => panic!("InputDevice handler received an unexpected request"),
875 }
876 });
877
878 assert!(
879 !is_device_type(
880 &input_device_proxy
881 .get_descriptor()
882 .await
883 .expect("Failed to get device descriptor")
884 .descriptor,
885 InputDeviceType::Mouse
886 )
887 .await
888 );
889 }
890
891 #[fasync::run_singlethreaded(test)]
894 async fn touch_input_device_exists() {
895 let input_device_proxy =
896 spawn_input_stream_handler(move |input_device_request| async move {
897 match input_device_request {
898 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
899 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
900 device_information: None,
901 mouse: None,
902 sensor: None,
903 touch: Some(fidl_input_report::TouchDescriptor {
904 input: Some(fidl_input_report::TouchInputDescriptor {
905 contacts: None,
906 max_contacts: None,
907 touch_type: None,
908 buttons: None,
909 ..Default::default()
910 }),
911 ..Default::default()
912 }),
913 keyboard: None,
914 consumer_control: None,
915 ..Default::default()
916 });
917 }
918 _ => panic!("InputDevice handler received an unexpected request"),
919 }
920 });
921
922 assert!(
923 is_device_type(
924 &input_device_proxy
925 .get_descriptor()
926 .await
927 .expect("Failed to get device descriptor")
928 .descriptor,
929 InputDeviceType::Touch
930 )
931 .await
932 );
933 }
934
935 #[fasync::run_singlethreaded(test)]
938 async fn touch_input_device_doesnt_exist() {
939 let input_device_proxy =
940 spawn_input_stream_handler(move |input_device_request| async move {
941 match input_device_request {
942 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
943 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
944 device_information: None,
945 mouse: None,
946 sensor: None,
947 touch: None,
948 keyboard: None,
949 consumer_control: None,
950 ..Default::default()
951 });
952 }
953 _ => panic!("InputDevice handler received an unexpected request"),
954 }
955 });
956
957 assert!(
958 !is_device_type(
959 &input_device_proxy
960 .get_descriptor()
961 .await
962 .expect("Failed to get device descriptor")
963 .descriptor,
964 InputDeviceType::Touch
965 )
966 .await
967 );
968 }
969
970 #[fasync::run_singlethreaded(test)]
973 async fn keyboard_input_device_exists() {
974 let input_device_proxy =
975 spawn_input_stream_handler(move |input_device_request| async move {
976 match input_device_request {
977 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
978 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
979 device_information: None,
980 mouse: None,
981 sensor: None,
982 touch: None,
983 keyboard: Some(fidl_input_report::KeyboardDescriptor {
984 input: Some(fidl_input_report::KeyboardInputDescriptor {
985 keys3: None,
986 ..Default::default()
987 }),
988 output: None,
989 ..Default::default()
990 }),
991 consumer_control: None,
992 ..Default::default()
993 });
994 }
995 _ => panic!("InputDevice handler received an unexpected request"),
996 }
997 });
998
999 assert!(
1000 is_device_type(
1001 &input_device_proxy
1002 .get_descriptor()
1003 .await
1004 .expect("Failed to get device descriptor")
1005 .descriptor,
1006 InputDeviceType::Keyboard
1007 )
1008 .await
1009 );
1010 }
1011
1012 #[fasync::run_singlethreaded(test)]
1015 async fn keyboard_input_device_doesnt_exist() {
1016 let input_device_proxy =
1017 spawn_input_stream_handler(move |input_device_request| async move {
1018 match input_device_request {
1019 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1020 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1021 device_information: None,
1022 mouse: None,
1023 sensor: None,
1024 touch: None,
1025 keyboard: None,
1026 consumer_control: None,
1027 ..Default::default()
1028 });
1029 }
1030 _ => panic!("InputDevice handler received an unexpected request"),
1031 }
1032 });
1033
1034 assert!(
1035 !is_device_type(
1036 &input_device_proxy
1037 .get_descriptor()
1038 .await
1039 .expect("Failed to get device descriptor")
1040 .descriptor,
1041 InputDeviceType::Keyboard
1042 )
1043 .await
1044 );
1045 }
1046
1047 #[fasync::run_singlethreaded(test)]
1049 async fn no_input_device_match() {
1050 let input_device_proxy =
1051 spawn_input_stream_handler(move |input_device_request| async move {
1052 match input_device_request {
1053 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1054 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1055 device_information: None,
1056 mouse: Some(fidl_input_report::MouseDescriptor {
1057 input: Some(fidl_input_report::MouseInputDescriptor {
1058 movement_x: None,
1059 movement_y: None,
1060 position_x: None,
1061 position_y: None,
1062 scroll_v: None,
1063 scroll_h: None,
1064 buttons: None,
1065 ..Default::default()
1066 }),
1067 ..Default::default()
1068 }),
1069 sensor: None,
1070 touch: Some(fidl_input_report::TouchDescriptor {
1071 input: Some(fidl_input_report::TouchInputDescriptor {
1072 contacts: None,
1073 max_contacts: None,
1074 touch_type: None,
1075 buttons: None,
1076 ..Default::default()
1077 }),
1078 ..Default::default()
1079 }),
1080 keyboard: Some(fidl_input_report::KeyboardDescriptor {
1081 input: Some(fidl_input_report::KeyboardInputDescriptor {
1082 keys3: None,
1083 ..Default::default()
1084 }),
1085 output: None,
1086 ..Default::default()
1087 }),
1088 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
1089 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
1090 buttons: Some(vec![
1091 fidl_input_report::ConsumerControlButton::VolumeUp,
1092 fidl_input_report::ConsumerControlButton::VolumeDown,
1093 ]),
1094 ..Default::default()
1095 }),
1096 ..Default::default()
1097 }),
1098 ..Default::default()
1099 });
1100 }
1101 _ => panic!("InputDevice handler received an unexpected request"),
1102 }
1103 });
1104
1105 let device_descriptor = &input_device_proxy
1106 .get_descriptor()
1107 .await
1108 .expect("Failed to get device descriptor")
1109 .descriptor;
1110 assert!(is_device_type(&device_descriptor, InputDeviceType::ConsumerControls).await);
1111 assert!(is_device_type(&device_descriptor, InputDeviceType::Mouse).await);
1112 assert!(is_device_type(&device_descriptor, InputDeviceType::Touch).await);
1113 assert!(is_device_type(&device_descriptor, InputDeviceType::Keyboard).await);
1114 }
1115
1116 #[fuchsia::test]
1117 fn unhandled_to_generic_conversion_sets_handled_flag_to_no() {
1118 assert_eq!(
1119 InputEvent::from(UnhandledInputEvent {
1120 device_event: InputDeviceEvent::Fake,
1121 device_descriptor: InputDeviceDescriptor::Fake,
1122 event_time: zx::MonotonicInstant::from_nanos(1),
1123 trace_id: None,
1124 })
1125 .handled,
1126 Handled::No
1127 );
1128 }
1129
1130 #[fuchsia::test]
1131 fn unhandled_to_generic_conversion_preserves_fields() {
1132 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1133 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1134 assert_eq!(
1135 InputEvent::from(UnhandledInputEvent {
1136 device_event: InputDeviceEvent::Fake,
1137 device_descriptor: InputDeviceDescriptor::Fake,
1138 event_time: EVENT_TIME,
1139 trace_id: expected_trace_id,
1140 }),
1141 InputEvent {
1142 device_event: InputDeviceEvent::Fake,
1143 device_descriptor: InputDeviceDescriptor::Fake,
1144 event_time: EVENT_TIME,
1145 handled: Handled::No,
1146 trace_id: expected_trace_id,
1147 },
1148 );
1149 }
1150
1151 #[fuchsia::test]
1152 fn generic_to_unhandled_conversion_fails_for_handled_events() {
1153 assert_matches!(
1154 UnhandledInputEvent::try_from(InputEvent {
1155 device_event: InputDeviceEvent::Fake,
1156 device_descriptor: InputDeviceDescriptor::Fake,
1157 event_time: zx::MonotonicInstant::from_nanos(1),
1158 handled: Handled::Yes,
1159 trace_id: None,
1160 }),
1161 Err(_)
1162 )
1163 }
1164
1165 #[fuchsia::test]
1166 fn generic_to_unhandled_conversion_preserves_fields_for_unhandled_events() {
1167 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1168 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1169 assert_eq!(
1170 UnhandledInputEvent::try_from(InputEvent {
1171 device_event: InputDeviceEvent::Fake,
1172 device_descriptor: InputDeviceDescriptor::Fake,
1173 event_time: EVENT_TIME,
1174 handled: Handled::No,
1175 trace_id: expected_trace_id,
1176 })
1177 .unwrap(),
1178 UnhandledInputEvent {
1179 device_event: InputDeviceEvent::Fake,
1180 device_descriptor: InputDeviceDescriptor::Fake,
1181 event_time: EVENT_TIME,
1182 trace_id: expected_trace_id,
1183 },
1184 )
1185 }
1186
1187 #[test_case(Handled::No; "initially not handled")]
1188 #[test_case(Handled::Yes; "initially handled")]
1189 fn into_handled_if_yields_handled_yes_on_true(initially_handled: Handled) {
1190 let event = InputEvent {
1191 device_event: InputDeviceEvent::Fake,
1192 device_descriptor: InputDeviceDescriptor::Fake,
1193 event_time: zx::MonotonicInstant::from_nanos(1),
1194 handled: initially_handled,
1195 trace_id: None,
1196 };
1197 pretty_assertions::assert_eq!(event.into_handled_if(true).handled, Handled::Yes);
1198 }
1199
1200 #[test_case(Handled::No; "initially not handled")]
1201 #[test_case(Handled::Yes; "initially handled")]
1202 fn into_handled_if_leaves_handled_unchanged_on_false(initially_handled: Handled) {
1203 let event = InputEvent {
1204 device_event: InputDeviceEvent::Fake,
1205 device_descriptor: InputDeviceDescriptor::Fake,
1206 event_time: zx::MonotonicInstant::from_nanos(1),
1207 handled: initially_handled.clone(),
1208 trace_id: None,
1209 };
1210 pretty_assertions::assert_eq!(event.into_handled_if(false).handled, initially_handled);
1211 }
1212
1213 #[test_case(Handled::No; "initially not handled")]
1214 #[test_case(Handled::Yes; "initially handled")]
1215 fn into_handled_yields_handled_yes(initially_handled: Handled) {
1216 let event = InputEvent {
1217 device_event: InputDeviceEvent::Fake,
1218 device_descriptor: InputDeviceDescriptor::Fake,
1219 event_time: zx::MonotonicInstant::from_nanos(1),
1220 handled: initially_handled,
1221 trace_id: None,
1222 };
1223 pretty_assertions::assert_eq!(event.into_handled().handled, Handled::Yes);
1224 }
1225}