1use crate::{
6 consumer_controls_binding, keyboard_binding, light_sensor_binding, metrics, mouse_binding,
7 touch_binding,
8};
9use anyhow::{Error, format_err};
10use async_trait::async_trait;
11use async_utils::hanging_get::client::HangingGetStream;
12use fidl::endpoints::Proxy;
13use fidl_fuchsia_input_report::{InputDeviceMarker, InputReport};
14use fuchsia_inspect::health::Reporter;
15use fuchsia_inspect::{
16 ExponentialHistogramParams, HistogramProperty as _, NumericProperty, Property,
17};
18use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
19use futures::stream::StreamExt;
20use metrics_registry::*;
21use std::path::PathBuf;
22use {
23 fidl_fuchsia_input_report as fidl_input_report, fidl_fuchsia_io as fio,
24 fuchsia_async as fasync, fuchsia_trace as ftrace,
25};
26
27pub use input_device_constants::InputDeviceType;
28
29pub static INPUT_REPORT_PATH: &str = "/dev/class/input-report";
31
32const LATENCY_HISTOGRAM_PROPERTIES: ExponentialHistogramParams<i64> = ExponentialHistogramParams {
33 floor: 0,
34 initial_step: 1,
35 step_multiplier: 10,
36 buckets: 7,
47};
48
49pub struct InputDeviceStatus {
52 now: Box<dyn Fn() -> zx::MonotonicInstant>,
55
56 _node: fuchsia_inspect::Node,
58
59 reports_received_count: fuchsia_inspect::UintProperty,
61
62 reports_filtered_count: fuchsia_inspect::UintProperty,
65
66 events_generated: fuchsia_inspect::UintProperty,
69
70 last_received_timestamp_ns: fuchsia_inspect::UintProperty,
72
73 last_generated_timestamp_ns: fuchsia_inspect::UintProperty,
75
76 pub health_node: fuchsia_inspect::health::Node,
78
79 driver_to_binding_latency_ms: fuchsia_inspect::IntExponentialHistogramProperty,
84}
85
86impl InputDeviceStatus {
87 pub fn new(device_node: fuchsia_inspect::Node) -> Self {
88 Self::new_internal(device_node, Box::new(zx::MonotonicInstant::get))
89 }
90
91 fn new_internal(
92 device_node: fuchsia_inspect::Node,
93 now: Box<dyn Fn() -> zx::MonotonicInstant>,
94 ) -> Self {
95 let mut health_node = fuchsia_inspect::health::Node::new(&device_node);
96 health_node.set_starting_up();
97
98 let reports_received_count = device_node.create_uint("reports_received_count", 0);
99 let reports_filtered_count = device_node.create_uint("reports_filtered_count", 0);
100 let events_generated = device_node.create_uint("events_generated", 0);
101 let last_received_timestamp_ns = device_node.create_uint("last_received_timestamp_ns", 0);
102 let last_generated_timestamp_ns = device_node.create_uint("last_generated_timestamp_ns", 0);
103 let driver_to_binding_latency_ms = device_node.create_int_exponential_histogram(
104 "driver_to_binding_latency_ms",
105 LATENCY_HISTOGRAM_PROPERTIES,
106 );
107
108 Self {
109 now,
110 _node: device_node,
111 reports_received_count,
112 reports_filtered_count,
113 events_generated,
114 last_received_timestamp_ns,
115 last_generated_timestamp_ns,
116 health_node,
117 driver_to_binding_latency_ms,
118 }
119 }
120
121 pub fn count_received_report(&self, report: &InputReport) {
122 self.reports_received_count.add(1);
123 match report.event_time {
124 Some(event_time) => {
125 self.driver_to_binding_latency_ms.insert(
126 ((self.now)() - zx::MonotonicInstant::from_nanos(event_time)).into_millis(),
127 );
128 self.last_received_timestamp_ns.set(event_time.try_into().unwrap());
129 }
130 None => (),
131 }
132 }
133
134 pub fn count_filtered_report(&self) {
135 self.reports_filtered_count.add(1);
136 }
137
138 pub fn count_generated_event(&self, event: InputEvent) {
139 self.events_generated.add(1);
140 self.last_generated_timestamp_ns.set(event.event_time.into_nanos().try_into().unwrap());
141 }
142}
143
144#[derive(Clone, Debug, PartialEq)]
146pub struct InputEvent {
147 pub device_event: InputDeviceEvent,
149
150 pub device_descriptor: InputDeviceDescriptor,
153
154 pub event_time: zx::MonotonicInstant,
156
157 pub handled: Handled,
159
160 pub trace_id: Option<ftrace::Id>,
161}
162
163#[derive(Clone, Debug, PartialEq)]
169pub struct UnhandledInputEvent {
170 pub device_event: InputDeviceEvent,
172
173 pub device_descriptor: InputDeviceDescriptor,
176
177 pub event_time: zx::MonotonicInstant,
179
180 pub trace_id: Option<ftrace::Id>,
181}
182
183#[derive(Clone, Debug, PartialEq)]
192pub enum InputDeviceEvent {
193 Keyboard(keyboard_binding::KeyboardEvent),
194 LightSensor(light_sensor_binding::LightSensorEvent),
195 ConsumerControls(consumer_controls_binding::ConsumerControlsEvent),
196 Mouse(mouse_binding::MouseEvent),
197 TouchScreen(touch_binding::TouchScreenEvent),
198 Touchpad(touch_binding::TouchpadEvent),
199 #[cfg(test)]
200 Fake,
201}
202
203#[derive(Clone, Debug, PartialEq)]
213pub enum InputDeviceDescriptor {
214 Keyboard(keyboard_binding::KeyboardDeviceDescriptor),
215 LightSensor(light_sensor_binding::LightSensorDeviceDescriptor),
216 ConsumerControls(consumer_controls_binding::ConsumerControlsDeviceDescriptor),
217 Mouse(mouse_binding::MouseDeviceDescriptor),
218 TouchScreen(touch_binding::TouchScreenDeviceDescriptor),
219 Touchpad(touch_binding::TouchpadDeviceDescriptor),
220 #[cfg(test)]
221 Fake,
222}
223
224impl From<keyboard_binding::KeyboardDeviceDescriptor> for InputDeviceDescriptor {
225 fn from(b: keyboard_binding::KeyboardDeviceDescriptor) -> Self {
226 InputDeviceDescriptor::Keyboard(b)
227 }
228}
229
230#[derive(Copy, Clone, Debug, PartialEq)]
232pub enum Handled {
233 Yes,
235 No,
237}
238
239#[async_trait]
248pub trait InputDeviceBinding: Send {
249 fn get_device_descriptor(&self) -> InputDeviceDescriptor;
251
252 fn input_event_sender(&self) -> UnboundedSender<InputEvent>;
254}
255
256pub fn initialize_report_stream<InputDeviceProcessReportsFn>(
271 device_proxy: fidl_input_report::InputDeviceProxy,
272 device_descriptor: InputDeviceDescriptor,
273 mut event_sender: UnboundedSender<InputEvent>,
274 inspect_status: InputDeviceStatus,
275 metrics_logger: metrics::MetricsLogger,
276 mut process_reports: InputDeviceProcessReportsFn,
277) where
278 InputDeviceProcessReportsFn: 'static
279 + Send
280 + FnMut(
281 InputReport,
282 Option<InputReport>,
283 &InputDeviceDescriptor,
284 &mut UnboundedSender<InputEvent>,
285 &InputDeviceStatus,
286 &metrics::MetricsLogger,
287 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>),
288{
289 fasync::Task::local(async move {
290 let mut previous_report: Option<InputReport> = None;
291 let (report_reader, server_end) = fidl::endpoints::create_proxy();
292 let result = device_proxy.get_input_reports_reader(server_end);
293 if result.is_err() {
294 metrics_logger.log_error(
295 InputPipelineErrorMetricDimensionEvent::InputDeviceGetInputReportsReaderError,
296 std::format!("error on GetInputReportsReader: {:?}", &result),
297 );
298 return; }
300 let mut report_stream = HangingGetStream::new(
301 report_reader,
302 fidl_input_report::InputReportsReaderProxy::read_input_reports,
303 );
304 loop {
305 match report_stream.next().await {
306 Some(Ok(Ok(input_reports))) => {
307 fuchsia_trace::duration!(c"input", c"input-device-process-reports");
308 let mut inspect_receiver: Option<UnboundedReceiver<InputEvent>>;
309 for report in input_reports {
310 (previous_report, inspect_receiver) = process_reports(
311 report,
312 previous_report,
313 &device_descriptor,
314 &mut event_sender,
315 &inspect_status,
316 &metrics_logger,
317 );
318 match inspect_receiver {
322 Some(mut receiver) => {
323 while let Some(event) = receiver.next().await {
324 inspect_status.count_generated_event(event);
325 }
326 }
327 None => (),
328 };
329 }
330 }
331 Some(Ok(Err(_service_error))) => break,
332 Some(Err(_fidl_error)) => break,
333 None => break,
334 }
335 }
336 log::warn!("initialize_report_stream exited - device binding no longer works");
339 })
340 .detach();
341}
342
343pub async fn is_device_type(
349 device_descriptor: &fidl_input_report::DeviceDescriptor,
350 device_type: InputDeviceType,
351) -> bool {
352 match device_type {
354 InputDeviceType::ConsumerControls => device_descriptor.consumer_control.is_some(),
355 InputDeviceType::Mouse => device_descriptor.mouse.is_some(),
356 InputDeviceType::Touch => device_descriptor.touch.is_some(),
357 InputDeviceType::Keyboard => device_descriptor.keyboard.is_some(),
358 InputDeviceType::LightSensor => device_descriptor.sensor.is_some(),
359 }
360}
361
362pub async fn get_device_binding(
370 device_type: InputDeviceType,
371 device_proxy: fidl_input_report::InputDeviceProxy,
372 device_id: u32,
373 input_event_sender: UnboundedSender<InputEvent>,
374 device_node: fuchsia_inspect::Node,
375 metrics_logger: metrics::MetricsLogger,
376) -> Result<Box<dyn InputDeviceBinding>, Error> {
377 match device_type {
378 InputDeviceType::ConsumerControls => {
379 let binding = consumer_controls_binding::ConsumerControlsBinding::new(
380 device_proxy,
381 device_id,
382 input_event_sender,
383 device_node,
384 metrics_logger,
385 )
386 .await?;
387 Ok(Box::new(binding))
388 }
389 InputDeviceType::Mouse => {
390 let binding = mouse_binding::MouseBinding::new(
391 device_proxy,
392 device_id,
393 input_event_sender,
394 device_node,
395 metrics_logger,
396 )
397 .await?;
398 Ok(Box::new(binding))
399 }
400 InputDeviceType::Touch => {
401 let binding = touch_binding::TouchBinding::new(
402 device_proxy,
403 device_id,
404 input_event_sender,
405 device_node,
406 metrics_logger,
407 )
408 .await?;
409 Ok(Box::new(binding))
410 }
411 InputDeviceType::Keyboard => {
412 let binding = keyboard_binding::KeyboardBinding::new(
413 device_proxy,
414 device_id,
415 input_event_sender,
416 device_node,
417 metrics_logger,
418 )
419 .await?;
420 Ok(Box::new(binding))
421 }
422 InputDeviceType::LightSensor => {
423 let binding = light_sensor_binding::LightSensorBinding::new(
424 device_proxy,
425 device_id,
426 input_event_sender,
427 device_node,
428 metrics_logger,
429 )
430 .await?;
431 Ok(Box::new(binding))
432 }
433 }
434}
435
436pub fn get_device_from_dir_entry_path(
445 dir_proxy: &fio::DirectoryProxy,
446 entry_path: &PathBuf,
447) -> Result<fidl_input_report::InputDeviceProxy, Error> {
448 let input_device_path = entry_path.to_str();
449 if input_device_path.is_none() {
450 return Err(format_err!("Failed to get entry path as a string."));
451 }
452
453 let (input_device, server) = fidl::endpoints::create_proxy::<InputDeviceMarker>();
454 fdio::service_connect_at(
455 dir_proxy.as_channel().as_ref(),
456 input_device_path.unwrap(),
457 server.into_channel(),
458 )
459 .expect("Failed to connect to InputDevice.");
460 Ok(input_device)
461}
462
463pub fn event_time_or_now(event_time: Option<i64>) -> zx::MonotonicInstant {
468 match event_time {
469 Some(time) => zx::MonotonicInstant::from_nanos(time),
470 None => zx::MonotonicInstant::get(),
471 }
472}
473
474impl std::convert::From<UnhandledInputEvent> for InputEvent {
475 fn from(event: UnhandledInputEvent) -> Self {
476 Self {
477 device_event: event.device_event,
478 device_descriptor: event.device_descriptor,
479 event_time: event.event_time,
480 handled: Handled::No,
481 trace_id: event.trace_id,
482 }
483 }
484}
485
486#[cfg(test)]
493impl std::convert::TryFrom<InputEvent> for UnhandledInputEvent {
494 type Error = anyhow::Error;
495 fn try_from(event: InputEvent) -> Result<UnhandledInputEvent, Self::Error> {
496 match event.handled {
497 Handled::Yes => {
498 Err(format_err!("Attempted to treat a handled InputEvent as unhandled"))
499 }
500 Handled::No => Ok(UnhandledInputEvent {
501 device_event: event.device_event,
502 device_descriptor: event.device_descriptor,
503 event_time: event.event_time,
504 trace_id: event.trace_id,
505 }),
506 }
507 }
508}
509
510impl InputEvent {
511 pub fn clone_with_wake_lease(&self) -> Self {
512 let device_event = match &self.device_event {
513 InputDeviceEvent::ConsumerControls(event) => {
514 InputDeviceEvent::ConsumerControls(event.clone_with_wake_lease())
515 }
516 InputDeviceEvent::Mouse(event) => {
517 InputDeviceEvent::Mouse(event.clone_with_wake_lease())
518 }
519 InputDeviceEvent::TouchScreen(event) => {
520 InputDeviceEvent::TouchScreen(event.clone_with_wake_lease())
521 }
522 _ => self.device_event.clone(),
523 };
524 Self {
525 device_event,
526 device_descriptor: self.device_descriptor.clone(),
527 event_time: self.event_time,
528 handled: self.handled,
529 trace_id: self.trace_id,
530 }
531 }
532
533 pub(crate) fn into_handled_if(self, predicate: bool) -> Self {
536 if predicate { Self { handled: Handled::Yes, ..self } } else { self }
537 }
538
539 pub(crate) fn into_handled(self) -> Self {
541 Self { handled: Handled::Yes, ..self }
542 }
543
544 pub fn into_with_event_time(self, event_time: zx::MonotonicInstant) -> Self {
546 Self { event_time, ..self }
547 }
548
549 #[cfg(test)]
551 pub fn into_with_device_descriptor(self, device_descriptor: InputDeviceDescriptor) -> Self {
552 Self { device_descriptor, ..self }
553 }
554
555 pub fn is_handled(&self) -> bool {
557 self.handled == Handled::Yes
558 }
559
560 pub fn get_event_type(&self) -> &'static str {
562 match self.device_event {
563 InputDeviceEvent::Keyboard(_) => "keyboard_event",
564 InputDeviceEvent::LightSensor(_) => "light_sensor_event",
565 InputDeviceEvent::ConsumerControls(_) => "consumer_controls_event",
566 InputDeviceEvent::Mouse(_) => "mouse_event",
567 InputDeviceEvent::TouchScreen(_) => "touch_screen_event",
568 InputDeviceEvent::Touchpad(_) => "touchpad_event",
569 #[cfg(test)]
570 InputDeviceEvent::Fake => "fake_event",
571 }
572 }
573
574 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
575 node.record_int("event_time", self.event_time.into_nanos());
576 match &self.device_event {
577 InputDeviceEvent::LightSensor(e) => e.record_inspect(node),
578 InputDeviceEvent::ConsumerControls(e) => e.record_inspect(node),
579 InputDeviceEvent::Mouse(e) => e.record_inspect(node),
580 InputDeviceEvent::TouchScreen(e) => e.record_inspect(node),
581 InputDeviceEvent::Touchpad(e) => e.record_inspect(node),
582 InputDeviceEvent::Keyboard(_) => (),
584 #[cfg(test)] InputDeviceEvent::Fake => (),
586 }
587 }
588}
589
590#[cfg(test)]
591mod tests {
592 use super::*;
593 use assert_matches::assert_matches;
594 use diagnostics_assertions::AnyProperty;
595 use fidl_test_util::spawn_stream_handler;
596
597 use pretty_assertions::assert_eq;
598 use std::convert::TryFrom as _;
599 use test_case::test_case;
600
601 #[test]
602 fn max_event_time() {
603 let event_time = event_time_or_now(Some(i64::MAX));
604 assert_eq!(event_time, zx::MonotonicInstant::INFINITE);
605 }
606
607 #[test]
608 fn min_event_time() {
609 let event_time = event_time_or_now(Some(std::i64::MIN));
610 assert_eq!(event_time, zx::MonotonicInstant::INFINITE_PAST);
611 }
612
613 #[fasync::run_singlethreaded(test)]
614 async fn input_device_status_initialized_with_correct_properties() {
615 let inspector = fuchsia_inspect::Inspector::default();
616 let input_pipeline_node = inspector.root().create_child("input_pipeline");
617 let input_devices_node = input_pipeline_node.create_child("input_devices");
618 let device_node = input_devices_node.create_child("001_keyboard");
619 let _input_device_status = InputDeviceStatus::new(device_node);
620 diagnostics_assertions::assert_data_tree!(inspector, root: {
621 input_pipeline: {
622 input_devices: {
623 "001_keyboard": {
624 reports_received_count: 0u64,
625 reports_filtered_count: 0u64,
626 events_generated: 0u64,
627 last_received_timestamp_ns: 0u64,
628 last_generated_timestamp_ns: 0u64,
629 "fuchsia.inspect.Health": {
630 status: "STARTING_UP",
631 start_timestamp_nanos: AnyProperty
634 },
635 driver_to_binding_latency_ms: diagnostics_assertions::HistogramAssertion::exponential(super::LATENCY_HISTOGRAM_PROPERTIES),
636 }
637 }
638 }
639 });
640 }
641
642 #[test_case(i64::MIN; "min value")]
643 #[test_case(-1; "negative value")]
644 #[test_case(0; "zero")]
645 #[test_case(1; "positive value")]
646 #[test_case(i64::MAX; "max value")]
647 #[fuchsia::test(allow_stalls = false)]
648 async fn input_device_status_updates_latency_histogram_on_count_received_report(
649 latency_nsec: i64,
650 ) {
651 let mut expected_histogram = diagnostics_assertions::HistogramAssertion::exponential(
652 super::LATENCY_HISTOGRAM_PROPERTIES,
653 );
654 let inspector = fuchsia_inspect::Inspector::default();
655 let input_device_status = InputDeviceStatus::new_internal(
656 inspector.root().clone_weak(),
657 Box::new(move || zx::MonotonicInstant::from_nanos(latency_nsec)),
658 );
659 input_device_status
660 .count_received_report(&InputReport { event_time: Some(0), ..InputReport::default() });
661 expected_histogram.insert_values([latency_nsec / 1000 / 1000]);
662 diagnostics_assertions::assert_data_tree!(inspector, root: contains {
663 driver_to_binding_latency_ms: expected_histogram,
664 });
665 }
666
667 #[fasync::run_singlethreaded(test)]
670 async fn consumer_controls_input_device_exists() {
671 let input_device_proxy: fidl_input_report::InputDeviceProxy =
672 spawn_stream_handler(move |input_device_request| async move {
673 match input_device_request {
674 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
675 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
676 device_information: None,
677 mouse: None,
678 sensor: None,
679 touch: None,
680 keyboard: None,
681 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
682 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
683 buttons: Some(vec![
684 fidl_input_report::ConsumerControlButton::VolumeUp,
685 fidl_input_report::ConsumerControlButton::VolumeDown,
686 ]),
687 ..Default::default()
688 }),
689 ..Default::default()
690 }),
691 ..Default::default()
692 });
693 }
694 _ => panic!("InputDevice handler received an unexpected request"),
695 }
696 });
697
698 assert!(
699 is_device_type(
700 &input_device_proxy
701 .get_descriptor()
702 .await
703 .expect("Failed to get device descriptor"),
704 InputDeviceType::ConsumerControls
705 )
706 .await
707 );
708 }
709
710 #[fasync::run_singlethreaded(test)]
712 async fn mouse_input_device_exists() {
713 let input_device_proxy: fidl_input_report::InputDeviceProxy =
714 spawn_stream_handler(move |input_device_request| async move {
715 match input_device_request {
716 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
717 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
718 device_information: None,
719 mouse: Some(fidl_input_report::MouseDescriptor {
720 input: Some(fidl_input_report::MouseInputDescriptor {
721 movement_x: None,
722 movement_y: None,
723 position_x: None,
724 position_y: None,
725 scroll_v: None,
726 scroll_h: None,
727 buttons: None,
728 ..Default::default()
729 }),
730 ..Default::default()
731 }),
732 sensor: None,
733 touch: None,
734 keyboard: None,
735 consumer_control: None,
736 ..Default::default()
737 });
738 }
739 _ => panic!("InputDevice handler received an unexpected request"),
740 }
741 });
742
743 assert!(
744 is_device_type(
745 &input_device_proxy
746 .get_descriptor()
747 .await
748 .expect("Failed to get device descriptor"),
749 InputDeviceType::Mouse
750 )
751 .await
752 );
753 }
754
755 #[fasync::run_singlethreaded(test)]
758 async fn mouse_input_device_doesnt_exist() {
759 let input_device_proxy: fidl_input_report::InputDeviceProxy =
760 spawn_stream_handler(move |input_device_request| async move {
761 match input_device_request {
762 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
763 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
764 device_information: None,
765 mouse: None,
766 sensor: None,
767 touch: None,
768 keyboard: None,
769 consumer_control: None,
770 ..Default::default()
771 });
772 }
773 _ => panic!("InputDevice handler received an unexpected request"),
774 }
775 });
776
777 assert!(
778 !is_device_type(
779 &input_device_proxy
780 .get_descriptor()
781 .await
782 .expect("Failed to get device descriptor"),
783 InputDeviceType::Mouse
784 )
785 .await
786 );
787 }
788
789 #[fasync::run_singlethreaded(test)]
792 async fn touch_input_device_exists() {
793 let input_device_proxy: fidl_input_report::InputDeviceProxy =
794 spawn_stream_handler(move |input_device_request| async move {
795 match input_device_request {
796 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
797 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
798 device_information: None,
799 mouse: None,
800 sensor: None,
801 touch: Some(fidl_input_report::TouchDescriptor {
802 input: Some(fidl_input_report::TouchInputDescriptor {
803 contacts: None,
804 max_contacts: None,
805 touch_type: None,
806 buttons: None,
807 ..Default::default()
808 }),
809 ..Default::default()
810 }),
811 keyboard: None,
812 consumer_control: None,
813 ..Default::default()
814 });
815 }
816 _ => panic!("InputDevice handler received an unexpected request"),
817 }
818 });
819
820 assert!(
821 is_device_type(
822 &input_device_proxy
823 .get_descriptor()
824 .await
825 .expect("Failed to get device descriptor"),
826 InputDeviceType::Touch
827 )
828 .await
829 );
830 }
831
832 #[fasync::run_singlethreaded(test)]
835 async fn touch_input_device_doesnt_exist() {
836 let input_device_proxy: fidl_input_report::InputDeviceProxy =
837 spawn_stream_handler(move |input_device_request| async move {
838 match input_device_request {
839 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
840 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
841 device_information: None,
842 mouse: None,
843 sensor: None,
844 touch: None,
845 keyboard: None,
846 consumer_control: None,
847 ..Default::default()
848 });
849 }
850 _ => panic!("InputDevice handler received an unexpected request"),
851 }
852 });
853
854 assert!(
855 !is_device_type(
856 &input_device_proxy
857 .get_descriptor()
858 .await
859 .expect("Failed to get device descriptor"),
860 InputDeviceType::Touch
861 )
862 .await
863 );
864 }
865
866 #[fasync::run_singlethreaded(test)]
869 async fn keyboard_input_device_exists() {
870 let input_device_proxy: fidl_input_report::InputDeviceProxy =
871 spawn_stream_handler(move |input_device_request| async move {
872 match input_device_request {
873 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
874 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
875 device_information: None,
876 mouse: None,
877 sensor: None,
878 touch: None,
879 keyboard: Some(fidl_input_report::KeyboardDescriptor {
880 input: Some(fidl_input_report::KeyboardInputDescriptor {
881 keys3: None,
882 ..Default::default()
883 }),
884 output: None,
885 ..Default::default()
886 }),
887 consumer_control: None,
888 ..Default::default()
889 });
890 }
891 _ => panic!("InputDevice handler received an unexpected request"),
892 }
893 });
894
895 assert!(
896 is_device_type(
897 &input_device_proxy
898 .get_descriptor()
899 .await
900 .expect("Failed to get device descriptor"),
901 InputDeviceType::Keyboard
902 )
903 .await
904 );
905 }
906
907 #[fasync::run_singlethreaded(test)]
910 async fn keyboard_input_device_doesnt_exist() {
911 let input_device_proxy: fidl_input_report::InputDeviceProxy =
912 spawn_stream_handler(move |input_device_request| async move {
913 match input_device_request {
914 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
915 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
916 device_information: None,
917 mouse: None,
918 sensor: None,
919 touch: None,
920 keyboard: None,
921 consumer_control: None,
922 ..Default::default()
923 });
924 }
925 _ => panic!("InputDevice handler received an unexpected request"),
926 }
927 });
928
929 assert!(
930 !is_device_type(
931 &input_device_proxy
932 .get_descriptor()
933 .await
934 .expect("Failed to get device descriptor"),
935 InputDeviceType::Keyboard
936 )
937 .await
938 );
939 }
940
941 #[fasync::run_singlethreaded(test)]
943 async fn no_input_device_match() {
944 let input_device_proxy: fidl_input_report::InputDeviceProxy =
945 spawn_stream_handler(move |input_device_request| async move {
946 match input_device_request {
947 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
948 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
949 device_information: None,
950 mouse: Some(fidl_input_report::MouseDescriptor {
951 input: Some(fidl_input_report::MouseInputDescriptor {
952 movement_x: None,
953 movement_y: None,
954 position_x: None,
955 position_y: None,
956 scroll_v: None,
957 scroll_h: None,
958 buttons: None,
959 ..Default::default()
960 }),
961 ..Default::default()
962 }),
963 sensor: None,
964 touch: Some(fidl_input_report::TouchDescriptor {
965 input: Some(fidl_input_report::TouchInputDescriptor {
966 contacts: None,
967 max_contacts: None,
968 touch_type: None,
969 buttons: None,
970 ..Default::default()
971 }),
972 ..Default::default()
973 }),
974 keyboard: Some(fidl_input_report::KeyboardDescriptor {
975 input: Some(fidl_input_report::KeyboardInputDescriptor {
976 keys3: None,
977 ..Default::default()
978 }),
979 output: None,
980 ..Default::default()
981 }),
982 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
983 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
984 buttons: Some(vec![
985 fidl_input_report::ConsumerControlButton::VolumeUp,
986 fidl_input_report::ConsumerControlButton::VolumeDown,
987 ]),
988 ..Default::default()
989 }),
990 ..Default::default()
991 }),
992 ..Default::default()
993 });
994 }
995 _ => panic!("InputDevice handler received an unexpected request"),
996 }
997 });
998
999 let device_descriptor =
1000 &input_device_proxy.get_descriptor().await.expect("Failed to get device descriptor");
1001 assert!(is_device_type(&device_descriptor, InputDeviceType::ConsumerControls).await);
1002 assert!(is_device_type(&device_descriptor, InputDeviceType::Mouse).await);
1003 assert!(is_device_type(&device_descriptor, InputDeviceType::Touch).await);
1004 assert!(is_device_type(&device_descriptor, InputDeviceType::Keyboard).await);
1005 }
1006
1007 #[fuchsia::test]
1008 fn unhandled_to_generic_conversion_sets_handled_flag_to_no() {
1009 assert_eq!(
1010 InputEvent::from(UnhandledInputEvent {
1011 device_event: InputDeviceEvent::Fake,
1012 device_descriptor: InputDeviceDescriptor::Fake,
1013 event_time: zx::MonotonicInstant::from_nanos(1),
1014 trace_id: None,
1015 })
1016 .handled,
1017 Handled::No
1018 );
1019 }
1020
1021 #[fuchsia::test]
1022 fn unhandled_to_generic_conversion_preserves_fields() {
1023 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1024 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1025 assert_eq!(
1026 InputEvent::from(UnhandledInputEvent {
1027 device_event: InputDeviceEvent::Fake,
1028 device_descriptor: InputDeviceDescriptor::Fake,
1029 event_time: EVENT_TIME,
1030 trace_id: expected_trace_id,
1031 }),
1032 InputEvent {
1033 device_event: InputDeviceEvent::Fake,
1034 device_descriptor: InputDeviceDescriptor::Fake,
1035 event_time: EVENT_TIME,
1036 handled: Handled::No,
1037 trace_id: expected_trace_id,
1038 },
1039 );
1040 }
1041
1042 #[fuchsia::test]
1043 fn generic_to_unhandled_conversion_fails_for_handled_events() {
1044 assert_matches!(
1045 UnhandledInputEvent::try_from(InputEvent {
1046 device_event: InputDeviceEvent::Fake,
1047 device_descriptor: InputDeviceDescriptor::Fake,
1048 event_time: zx::MonotonicInstant::from_nanos(1),
1049 handled: Handled::Yes,
1050 trace_id: None,
1051 }),
1052 Err(_)
1053 )
1054 }
1055
1056 #[fuchsia::test]
1057 fn generic_to_unhandled_conversion_preserves_fields_for_unhandled_events() {
1058 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1059 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1060 assert_eq!(
1061 UnhandledInputEvent::try_from(InputEvent {
1062 device_event: InputDeviceEvent::Fake,
1063 device_descriptor: InputDeviceDescriptor::Fake,
1064 event_time: EVENT_TIME,
1065 handled: Handled::No,
1066 trace_id: expected_trace_id,
1067 })
1068 .unwrap(),
1069 UnhandledInputEvent {
1070 device_event: InputDeviceEvent::Fake,
1071 device_descriptor: InputDeviceDescriptor::Fake,
1072 event_time: EVENT_TIME,
1073 trace_id: expected_trace_id,
1074 },
1075 )
1076 }
1077
1078 #[test_case(Handled::No; "initially not handled")]
1079 #[test_case(Handled::Yes; "initially handled")]
1080 fn into_handled_if_yields_handled_yes_on_true(initially_handled: Handled) {
1081 let event = InputEvent {
1082 device_event: InputDeviceEvent::Fake,
1083 device_descriptor: InputDeviceDescriptor::Fake,
1084 event_time: zx::MonotonicInstant::from_nanos(1),
1085 handled: initially_handled,
1086 trace_id: None,
1087 };
1088 pretty_assertions::assert_eq!(event.into_handled_if(true).handled, Handled::Yes);
1089 }
1090
1091 #[test_case(Handled::No; "initially not handled")]
1092 #[test_case(Handled::Yes; "initially handled")]
1093 fn into_handled_if_leaves_handled_unchanged_on_false(initially_handled: Handled) {
1094 let event = InputEvent {
1095 device_event: InputDeviceEvent::Fake,
1096 device_descriptor: InputDeviceDescriptor::Fake,
1097 event_time: zx::MonotonicInstant::from_nanos(1),
1098 handled: initially_handled.clone(),
1099 trace_id: None,
1100 };
1101 pretty_assertions::assert_eq!(event.into_handled_if(false).handled, initially_handled);
1102 }
1103
1104 #[test_case(Handled::No; "initially not handled")]
1105 #[test_case(Handled::Yes; "initially handled")]
1106 fn into_handled_yields_handled_yes(initially_handled: Handled) {
1107 let event = InputEvent {
1108 device_event: InputDeviceEvent::Fake,
1109 device_descriptor: InputDeviceDescriptor::Fake,
1110 event_time: zx::MonotonicInstant::from_nanos(1),
1111 handled: initially_handled,
1112 trace_id: None,
1113 };
1114 pretty_assertions::assert_eq!(event.into_handled().handled, Handled::Yes);
1115 }
1116}