1use crate::input_device::{self, Handled, InputDeviceBinding, InputDeviceStatus, InputEvent};
6use crate::metrics;
7use anyhow::{Error, Result, format_err};
8use async_trait::async_trait;
9use fidl_fuchsia_input_report::{InputDeviceProxy, InputReport};
10use fidl_fuchsia_ui_input3::KeyEventType;
11use fuchsia_inspect::health::Reporter;
12use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
13use metrics_registry::*;
14use {fidl_fuchsia_ui_input3 as fidl_ui_input3, fuchsia_async as fasync};
15
16#[derive(Clone, Debug, PartialEq)]
32pub struct KeyboardEvent {
33 key: fidl_fuchsia_input::Key,
35
36 event_type: KeyEventType,
38
39 modifiers: Option<fidl_ui_input3::Modifiers>,
41
42 lock_state: Option<fidl_ui_input3::LockState>,
44
45 keymap: Option<String>,
48
49 key_meaning: Option<fidl_fuchsia_ui_input3::KeyMeaning>,
54
55 repeat_sequence: u32,
61}
62
63impl KeyboardEvent {
64 pub fn new(key: fidl_fuchsia_input::Key, event_type: KeyEventType) -> Self {
67 KeyboardEvent {
68 key,
69 event_type,
70 modifiers: None,
71 lock_state: None,
72 keymap: None,
73 key_meaning: None,
74 repeat_sequence: 0,
75 }
76 }
77
78 pub fn get_key(&self) -> fidl_fuchsia_input::Key {
79 self.key
80 }
81
82 pub fn into_with_key(self, key: fidl_fuchsia_input::Key) -> Self {
84 Self { key, ..self }
85 }
86
87 pub fn get_event_type(&self) -> KeyEventType {
88 self.event_type
89 }
90
91 pub fn into_with_event_type(self, event_type: KeyEventType) -> Self {
93 Self { event_type, ..self }
94 }
95
96 pub fn into_with_folded_event(self) -> Self {
98 Self { event_type: self.get_event_type_folded(), ..self }
99 }
100
101 pub fn get_event_type_folded(&self) -> KeyEventType {
103 match self.event_type {
104 KeyEventType::Pressed | KeyEventType::Sync => KeyEventType::Pressed,
105 KeyEventType::Released | KeyEventType::Cancel => KeyEventType::Released,
106 }
107 }
108
109 pub fn into_with_modifiers(self, modifiers: Option<fidl_ui_input3::Modifiers>) -> Self {
111 Self { modifiers, ..self }
112 }
113
114 pub fn get_modifiers(&self) -> Option<fidl_ui_input3::Modifiers> {
116 self.modifiers
117 }
118
119 pub fn get_unsided_modifiers(&self) -> fidl_fuchsia_ui_input3::Modifiers {
123 use fidl_fuchsia_ui_input3::Modifiers;
124 let mut modifiers = self.modifiers.unwrap_or(Modifiers::empty());
125 modifiers.set(
126 Modifiers::LEFT_ALT
127 | Modifiers::LEFT_CTRL
128 | Modifiers::LEFT_SHIFT
129 | Modifiers::LEFT_META
130 | Modifiers::RIGHT_ALT
131 | Modifiers::RIGHT_CTRL
132 | Modifiers::RIGHT_SHIFT
133 | Modifiers::RIGHT_META,
134 false,
135 );
136 modifiers
137 }
138
139 pub fn into_with_lock_state(self, lock_state: Option<fidl_ui_input3::LockState>) -> Self {
141 Self { lock_state, ..self }
142 }
143
144 pub fn get_lock_state(&self) -> Option<fidl_ui_input3::LockState> {
146 self.lock_state
147 }
148
149 pub fn into_with_keymap(self, keymap: Option<String>) -> Self {
152 Self { keymap, ..self }
153 }
154
155 pub fn get_keymap(&self) -> Option<String> {
157 self.keymap.clone()
158 }
159
160 pub fn into_with_key_meaning(
162 self,
163 key_meaning: Option<fidl_fuchsia_ui_input3::KeyMeaning>,
164 ) -> Self {
165 Self { key_meaning, ..self }
166 }
167
168 pub fn get_key_meaning(&self) -> Option<fidl_fuchsia_ui_input3::KeyMeaning> {
170 self.key_meaning
171 }
172
173 pub fn get_repeat_sequence(&self) -> u32 {
177 self.repeat_sequence
178 }
179
180 pub fn into_with_repeat_sequence(self, repeat_sequence: u32) -> Self {
183 Self { repeat_sequence, ..self }
184 }
185
186 #[cfg(test)]
188 pub(crate) fn from_key_event_at_time(
189 &self,
190 event_time: zx::MonotonicInstant,
191 ) -> fidl_ui_input3::KeyEvent {
192 fidl_ui_input3::KeyEvent {
193 timestamp: Some(event_time.into_nanos()),
194 type_: Some(self.event_type),
195 key: Some(self.key),
196 modifiers: self.modifiers,
197 lock_state: self.lock_state,
198 repeat_sequence: Some(self.repeat_sequence),
199 key_meaning: self.key_meaning,
200 ..Default::default()
201 }
202 }
203}
204
205impl KeyboardEvent {
206 pub fn same_key(this: &KeyboardEvent, that: &KeyboardEvent) -> bool {
208 this.get_key() == that.get_key()
209 }
210}
211
212#[derive(Clone, Debug, PartialEq)]
214pub struct KeyboardDeviceDescriptor {
215 pub keys: Vec<fidl_fuchsia_input::Key>,
217
218 pub device_information: fidl_fuchsia_input_report::DeviceInformation,
220
221 pub device_id: u32,
223}
224
225#[cfg(test)]
226impl Default for KeyboardDeviceDescriptor {
227 fn default() -> Self {
228 KeyboardDeviceDescriptor {
229 keys: vec![],
230 device_information: fidl_fuchsia_input_report::DeviceInformation {
231 vendor_id: Some(0),
232 product_id: Some(0),
233 version: Some(0),
234 polling_rate: Some(0),
235 ..Default::default()
236 },
237 device_id: 0,
238 }
239 }
240}
241
242pub struct KeyboardBinding {
248 event_sender: UnboundedSender<input_device::InputEvent>,
250
251 device_descriptor: KeyboardDeviceDescriptor,
253}
254
255#[async_trait]
256impl input_device::InputDeviceBinding for KeyboardBinding {
257 fn input_event_sender(&self) -> UnboundedSender<input_device::InputEvent> {
258 self.event_sender.clone()
259 }
260
261 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
262 input_device::InputDeviceDescriptor::Keyboard(self.device_descriptor.clone())
263 }
264}
265
266impl KeyboardBinding {
267 pub async fn new(
282 device_proxy: InputDeviceProxy,
283 device_id: u32,
284 input_event_sender: UnboundedSender<input_device::InputEvent>,
285 device_node: fuchsia_inspect::Node,
286 metrics_logger: metrics::MetricsLogger,
287 ) -> Result<Self, Error> {
288 let (device_binding, mut inspect_status) = Self::bind_device(
289 &device_proxy,
290 input_event_sender,
291 device_id,
292 device_node,
293 metrics_logger.clone(),
294 )
295 .await?;
296 inspect_status.health_node.set_ok();
297 input_device::initialize_report_stream(
298 device_proxy,
299 device_binding.get_device_descriptor(),
300 device_binding.input_event_sender(),
301 inspect_status,
302 metrics_logger,
303 Self::process_reports,
304 );
305
306 Ok(device_binding)
307 }
308
309 pub fn to_modifiers(keys: &[&fidl_fuchsia_input::Key]) -> Option<fidl_ui_input3::Modifiers> {
320 let mut modifiers = fidl_ui_input3::Modifiers::empty();
321 for key in keys {
322 let modifier = match key {
323 fidl_fuchsia_input::Key::CapsLock => Some(fidl_ui_input3::Modifiers::CAPS_LOCK),
324 fidl_fuchsia_input::Key::NumLock => Some(fidl_ui_input3::Modifiers::NUM_LOCK),
325 fidl_fuchsia_input::Key::ScrollLock => Some(fidl_ui_input3::Modifiers::SCROLL_LOCK),
326 _ => None,
327 };
328 if let Some(modifier) = modifier {
329 modifiers.insert(modifier);
330 };
331 }
332 if modifiers.is_empty() {
333 return None;
334 }
335 Some(modifiers)
336 }
337
338 async fn bind_device(
350 device: &InputDeviceProxy,
351 input_event_sender: UnboundedSender<input_device::InputEvent>,
352 device_id: u32,
353 device_node: fuchsia_inspect::Node,
354 metrics_logger: metrics::MetricsLogger,
355 ) -> Result<(Self, InputDeviceStatus), Error> {
356 let mut input_device_status = InputDeviceStatus::new(device_node);
357 let descriptor = match device.get_descriptor().await {
358 Ok(descriptor) => descriptor,
359 Err(_) => {
360 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
361 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
362 }
363 };
364
365 let device_info = descriptor.device_information.ok_or_else(|| {
366 input_device_status.health_node.set_unhealthy("Empty device_information in descriptor");
367 metrics_logger.log_error(
370 InputPipelineErrorMetricDimensionEvent::KeyboardEmptyDeviceInfo,
371 std::format!("DRIVER BUG: empty device_information for device_id: {}", device_id),
372 );
373 format_err!("empty device info for device_id: {}", device_id)
374 })?;
375 match descriptor.keyboard {
376 Some(fidl_fuchsia_input_report::KeyboardDescriptor {
377 input: Some(fidl_fuchsia_input_report::KeyboardInputDescriptor { keys3, .. }),
378 output: _,
379 ..
380 }) => Ok((
381 KeyboardBinding {
382 event_sender: input_event_sender,
383 device_descriptor: KeyboardDeviceDescriptor {
384 keys: keys3.unwrap_or_default(),
385 device_information: device_info,
386 device_id,
387 },
388 },
389 input_device_status,
390 )),
391 device_descriptor => {
392 input_device_status
393 .health_node
394 .set_unhealthy("Keyboard Device Descriptor failed to parse.");
395 Err(format_err!(
396 "Keyboard Device Descriptor failed to parse: \n {:?}",
397 device_descriptor
398 ))
399 }
400 }
401 }
402
403 fn process_reports(
423 report: InputReport,
424 previous_report: Option<InputReport>,
425 device_descriptor: &input_device::InputDeviceDescriptor,
426 input_event_sender: &mut UnboundedSender<input_device::InputEvent>,
427 inspect_status: &InputDeviceStatus,
428 metrics_logger: &metrics::MetricsLogger,
429 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
430 fuchsia_trace::duration!("input", "keyboard-binding-process-report");
431 if let Some(trace_id) = report.trace_id {
432 fuchsia_trace::flow_end!("input", "input_report", trace_id.into());
433 }
434
435 let tracing_id = fuchsia_trace::Id::random();
436 fuchsia_trace::flow_begin!("input", "key_event_thread", tracing_id);
437
438 inspect_status.count_received_report(&report);
439 match &report.keyboard {
441 None => {
442 inspect_status.count_filtered_report();
443 return (previous_report, None);
444 }
445 _ => (),
446 };
447
448 let new_keys = match KeyboardBinding::parse_pressed_keys(&report) {
449 Some(keys) => keys,
450 None => {
451 metrics_logger.log_error(
457 InputPipelineErrorMetricDimensionEvent::KeyboardFailedToParse,
458 std::format!("Failed to parse keyboard keys: {:?}", report),
459 );
460 inspect_status.count_filtered_report();
461 return (previous_report, None);
462 }
463 };
464
465 let previous_keys: Vec<fidl_fuchsia_input::Key> = previous_report
466 .as_ref()
467 .and_then(|unwrapped_report| KeyboardBinding::parse_pressed_keys(&unwrapped_report))
468 .unwrap_or_default();
469
470 let (inspect_sender, inspect_receiver) = futures::channel::mpsc::unbounded();
471
472 KeyboardBinding::send_key_events(
473 &new_keys,
474 &previous_keys,
475 device_descriptor.clone(),
476 zx::MonotonicInstant::get(),
477 input_event_sender.clone(),
478 inspect_sender,
479 metrics_logger,
480 tracing_id,
481 );
482
483 (Some(report), Some(inspect_receiver))
484 }
485
486 fn parse_pressed_keys(input_report: &InputReport) -> Option<Vec<fidl_fuchsia_input::Key>> {
496 input_report
497 .keyboard
498 .as_ref()
499 .and_then(|unwrapped_keyboard| unwrapped_keyboard.pressed_keys3.as_ref())
500 .and_then(|unwrapped_keys| Some(unwrapped_keys.iter().cloned().collect()))
501 }
502
503 fn send_key_events(
512 new_keys: &Vec<fidl_fuchsia_input::Key>,
513 previous_keys: &Vec<fidl_fuchsia_input::Key>,
514 device_descriptor: input_device::InputDeviceDescriptor,
515 event_time: zx::MonotonicInstant,
516 input_event_sender: UnboundedSender<input_device::InputEvent>,
517 inspect_sender: UnboundedSender<input_device::InputEvent>,
518 metrics_logger: &metrics::MetricsLogger,
519 tracing_id: fuchsia_trace::Id,
520 ) {
521 fn dispatch_events(
525 key_events: Vec<(fidl_fuchsia_input::Key, fidl_fuchsia_ui_input3::KeyEventType)>,
526 device_descriptor: input_device::InputDeviceDescriptor,
527 event_time: zx::MonotonicInstant,
528 input_event_sender: UnboundedSender<input_device::InputEvent>,
529 inspect_sender: UnboundedSender<input_device::InputEvent>,
530 metrics_logger: metrics::MetricsLogger,
531 tracing_id: fuchsia_trace::Id,
532 ) {
533 fasync::Task::local(async move {
534 fuchsia_trace::duration!("input", "key_event_thread");
535 fuchsia_trace::flow_end!("input", "key_event_thread", tracing_id);
536
537 let mut event_time = event_time;
538 for (key, event_type) in key_events.into_iter() {
539 let trace_id = fuchsia_trace::Id::random();
540 fuchsia_trace::duration!("input", "keyboard_event_in_binding");
541 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
542
543 let event = input_device::InputEvent {
544 device_event: input_device::InputDeviceEvent::Keyboard(
545 KeyboardEvent::new(key, event_type),
546 ),
547 device_descriptor: device_descriptor.clone(),
548 event_time,
549 handled: Handled::No,
550 trace_id: Some(trace_id),
551 };
552 match input_event_sender.unbounded_send(event.clone()) {
553 Err(error) => {
554 metrics_logger.log_error(
555 InputPipelineErrorMetricDimensionEvent::KeyboardFailedToSendKeyboardEvent,
556 std::format!(
557 "Failed to send KeyboardEvent for key: {:?}, event_type: {:?}: {:?}",
558 &key,
559 &event_type,
560 error));
561 }
562 _ => { let _ = inspect_sender.unbounded_send(event).expect("Failed to count generated KeyboardEvent in Input Pipeline Inspect tree."); },
563 }
564 event_time = event_time + zx::MonotonicDuration::from_nanos(1);
569 }
570 })
571 .detach();
572 }
573
574 let pressed_keys = new_keys
577 .iter()
578 .cloned()
579 .filter(|key| !previous_keys.contains(key))
580 .map(|k| (k, fidl_fuchsia_ui_input3::KeyEventType::Pressed));
581
582 let released_keys = previous_keys
585 .iter()
586 .cloned()
587 .filter(|key| !new_keys.contains(key))
588 .map(|k| (k, fidl_fuchsia_ui_input3::KeyEventType::Released));
589
590 let all_keys = released_keys.chain(pressed_keys).collect::<Vec<_>>();
595
596 dispatch_events(
597 all_keys,
598 device_descriptor,
599 event_time,
600 input_event_sender,
601 inspect_sender,
602 metrics_logger.clone(),
603 tracing_id,
604 );
605 }
606}
607
608#[cfg(test)]
609mod tests {
610 use super::*;
611 use crate::testing_utilities;
612 use fuchsia_async as fasync;
613 use futures::StreamExt;
614
615 #[fasync::run_singlethreaded(test)]
618 async fn pressed_key() {
619 let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
620 keys: vec![fidl_fuchsia_input::Key::A],
621 ..Default::default()
622 });
623 let (event_time_i64, _) = testing_utilities::event_times();
624
625 let reports = vec![testing_utilities::create_keyboard_input_report(
626 vec![fidl_fuchsia_input::Key::A],
627 event_time_i64,
628 )];
629 let expected_events = vec![testing_utilities::create_keyboard_event(
630 fidl_fuchsia_input::Key::A,
631 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
632 None,
633 &descriptor,
634 None,
635 )];
636
637 assert_input_report_sequence_generates_events!(
638 input_reports: reports,
639 expected_events: expected_events,
640 device_descriptor: descriptor,
641 device_type: KeyboardBinding,
642 );
643 }
644
645 #[fasync::run_singlethreaded(test)]
648 async fn released_key() {
649 let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
650 keys: vec![fidl_fuchsia_input::Key::A],
651 ..Default::default()
652 });
653 let (event_time_i64, _) = testing_utilities::event_times();
654
655 let reports = vec![
656 testing_utilities::create_keyboard_input_report(
657 vec![fidl_fuchsia_input::Key::A],
658 event_time_i64,
659 ),
660 testing_utilities::create_keyboard_input_report(vec![], event_time_i64),
661 ];
662
663 let expected_events = vec![
664 testing_utilities::create_keyboard_event(
665 fidl_fuchsia_input::Key::A,
666 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
667 None,
668 &descriptor,
669 None,
670 ),
671 testing_utilities::create_keyboard_event(
672 fidl_fuchsia_input::Key::A,
673 fidl_fuchsia_ui_input3::KeyEventType::Released,
674 None,
675 &descriptor,
676 None,
677 ),
678 ];
679
680 assert_input_report_sequence_generates_events!(
681 input_reports: reports,
682 expected_events: expected_events,
683 device_descriptor: descriptor.clone(),
684 device_type: KeyboardBinding,
685 );
686 }
687
688 #[fasync::run_singlethreaded(test)]
691 async fn multiple_pressed_event_filtering() {
692 let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
693 keys: vec![fidl_fuchsia_input::Key::A],
694 ..Default::default()
695 });
696 let (event_time_i64, _) = testing_utilities::event_times();
697
698 let reports = vec![
699 testing_utilities::create_keyboard_input_report(
700 vec![fidl_fuchsia_input::Key::A],
701 event_time_i64,
702 ),
703 testing_utilities::create_keyboard_input_report(
704 vec![fidl_fuchsia_input::Key::A],
705 event_time_i64,
706 ),
707 ];
708
709 let expected_events = vec![testing_utilities::create_keyboard_event(
710 fidl_fuchsia_input::Key::A,
711 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
712 None,
713 &descriptor,
714 None,
715 )];
716
717 assert_input_report_sequence_generates_events!(
718 input_reports: reports,
719 expected_events: expected_events,
720 device_descriptor: descriptor,
721 device_type: KeyboardBinding,
722 );
723 }
724
725 #[fasync::run_singlethreaded(test)]
727 async fn pressed_and_released_keys() {
728 let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
729 keys: vec![fidl_fuchsia_input::Key::A, fidl_fuchsia_input::Key::B],
730 ..Default::default()
731 });
732 let (event_time_i64, _) = testing_utilities::event_times();
733
734 let reports = vec![
735 testing_utilities::create_keyboard_input_report(
736 vec![fidl_fuchsia_input::Key::A],
737 event_time_i64,
738 ),
739 testing_utilities::create_keyboard_input_report(
740 vec![fidl_fuchsia_input::Key::B],
741 event_time_i64,
742 ),
743 ];
744
745 let expected_events = vec![
746 testing_utilities::create_keyboard_event(
747 fidl_fuchsia_input::Key::A,
748 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
749 None,
750 &descriptor,
751 None,
752 ),
753 testing_utilities::create_keyboard_event(
754 fidl_fuchsia_input::Key::A,
755 fidl_fuchsia_ui_input3::KeyEventType::Released,
756 None,
757 &descriptor,
758 None,
759 ),
760 testing_utilities::create_keyboard_event(
761 fidl_fuchsia_input::Key::B,
762 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
763 None,
764 &descriptor,
765 None,
766 ),
767 ];
768
769 assert_input_report_sequence_generates_events!(
770 input_reports: reports,
771 expected_events: expected_events,
772 device_descriptor: descriptor,
773 device_type: KeyboardBinding,
774 );
775 }
776
777 #[fuchsia::test]
778 fn get_unsided_modifiers() {
779 use fidl_ui_input3::Modifiers;
780 let event = KeyboardEvent::new(fidl_fuchsia_input::Key::A, KeyEventType::Pressed)
781 .into_with_modifiers(Some(Modifiers::all()));
782 assert_eq!(
783 event.get_unsided_modifiers(),
784 Modifiers::CAPS_LOCK
785 | Modifiers::NUM_LOCK
786 | Modifiers::SCROLL_LOCK
787 | Modifiers::FUNCTION
788 | Modifiers::SYMBOL
789 | Modifiers::SHIFT
790 | Modifiers::ALT
791 | Modifiers::ALT_GRAPH
792 | Modifiers::META
793 | Modifiers::CTRL
794 )
795 }
796
797 #[fuchsia::test]
798 fn conversion_fills_out_all_fields() {
799 use fidl_fuchsia_input::Key;
800 use fidl_ui_input3::{KeyMeaning, LockState, Modifiers, NonPrintableKey};
801 let event = KeyboardEvent::new(Key::A, KeyEventType::Pressed)
802 .into_with_modifiers(Some(Modifiers::all()))
803 .into_with_lock_state(Some(LockState::all()))
804 .into_with_repeat_sequence(42)
805 .into_with_key_meaning(Some(KeyMeaning::NonPrintableKey(NonPrintableKey::Tab)));
806
807 let actual = event.from_key_event_at_time(zx::MonotonicInstant::from_nanos(42));
808 assert_eq!(
809 actual,
810 fidl_fuchsia_ui_input3::KeyEvent {
811 timestamp: Some(42),
812 type_: Some(KeyEventType::Pressed),
813 key: Some(Key::A),
814 modifiers: Some(Modifiers::all()),
815 key_meaning: Some(KeyMeaning::NonPrintableKey(NonPrintableKey::Tab)),
816 repeat_sequence: Some(42),
817 lock_state: Some(LockState::all()),
818 ..Default::default()
819 }
820 );
821 }
822}