1use crate::input_device::{self, Handled, InputDeviceBinding, InputDeviceStatus, InputEvent};
6use crate::{Dispatcher, Transport, metrics, utils};
7use anyhow::{Error, Result, format_err};
8use async_trait::async_trait;
9use fidl_fuchsia_ui_input3 as fidl_ui_input3;
10use fidl_fuchsia_ui_input3::KeyEventType;
11use fuchsia_inspect::health::Reporter;
12use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
13use metrics_registry::*;
14
15#[derive(Clone, Debug, PartialEq)]
31pub struct KeyboardEvent {
32 key: fidl_fuchsia_input::Key,
34
35 event_type: KeyEventType,
37
38 modifiers: Option<fidl_ui_input3::Modifiers>,
40
41 lock_state: Option<fidl_ui_input3::LockState>,
43
44 keymap: Option<String>,
47
48 key_meaning: Option<fidl_fuchsia_ui_input3::KeyMeaning>,
53
54 repeat_sequence: u32,
60}
61
62impl KeyboardEvent {
63 pub fn new(key: fidl_fuchsia_input::Key, event_type: KeyEventType) -> Self {
66 KeyboardEvent {
67 key,
68 event_type,
69 modifiers: None,
70 lock_state: None,
71 keymap: None,
72 key_meaning: None,
73 repeat_sequence: 0,
74 }
75 }
76
77 pub fn get_key(&self) -> fidl_fuchsia_input::Key {
78 self.key
79 }
80
81 pub fn into_with_key(self, key: fidl_fuchsia_input::Key) -> Self {
83 Self { key, ..self }
84 }
85
86 pub fn get_event_type(&self) -> KeyEventType {
87 self.event_type
88 }
89
90 pub fn into_with_event_type(self, event_type: KeyEventType) -> Self {
92 Self { event_type, ..self }
93 }
94
95 pub fn into_with_folded_event(self) -> Self {
97 Self { event_type: self.get_event_type_folded(), ..self }
98 }
99
100 pub fn get_event_type_folded(&self) -> KeyEventType {
102 match self.event_type {
103 KeyEventType::Pressed | KeyEventType::Sync => KeyEventType::Pressed,
104 KeyEventType::Released | KeyEventType::Cancel => KeyEventType::Released,
105 }
106 }
107
108 pub fn into_with_modifiers(self, modifiers: Option<fidl_ui_input3::Modifiers>) -> Self {
110 Self { modifiers, ..self }
111 }
112
113 pub fn get_modifiers(&self) -> Option<fidl_ui_input3::Modifiers> {
115 self.modifiers
116 }
117
118 pub fn get_unsided_modifiers(&self) -> fidl_fuchsia_ui_input3::Modifiers {
122 use fidl_fuchsia_ui_input3::Modifiers;
123 let mut modifiers = self.modifiers.unwrap_or(Modifiers::empty());
124 modifiers.set(
125 Modifiers::LEFT_ALT
126 | Modifiers::LEFT_CTRL
127 | Modifiers::LEFT_SHIFT
128 | Modifiers::LEFT_META
129 | Modifiers::RIGHT_ALT
130 | Modifiers::RIGHT_CTRL
131 | Modifiers::RIGHT_SHIFT
132 | Modifiers::RIGHT_META,
133 false,
134 );
135 modifiers
136 }
137
138 pub fn into_with_lock_state(self, lock_state: Option<fidl_ui_input3::LockState>) -> Self {
140 Self { lock_state, ..self }
141 }
142
143 pub fn get_lock_state(&self) -> Option<fidl_ui_input3::LockState> {
145 self.lock_state
146 }
147
148 pub fn into_with_keymap(self, keymap: Option<String>) -> Self {
151 Self { keymap, ..self }
152 }
153
154 pub fn get_keymap(&self) -> Option<String> {
156 self.keymap.clone()
157 }
158
159 pub fn into_with_key_meaning(
161 self,
162 key_meaning: Option<fidl_fuchsia_ui_input3::KeyMeaning>,
163 ) -> Self {
164 Self { key_meaning, ..self }
165 }
166
167 pub fn get_key_meaning(&self) -> Option<fidl_fuchsia_ui_input3::KeyMeaning> {
169 self.key_meaning
170 }
171
172 pub fn get_repeat_sequence(&self) -> u32 {
176 self.repeat_sequence
177 }
178
179 pub fn into_with_repeat_sequence(self, repeat_sequence: u32) -> Self {
182 Self { repeat_sequence, ..self }
183 }
184
185 #[cfg(test)]
187 pub(crate) fn from_key_event_at_time(
188 &self,
189 event_time: zx::MonotonicInstant,
190 ) -> fidl_ui_input3::KeyEvent {
191 fidl_ui_input3::KeyEvent {
192 timestamp: Some(event_time.into_nanos()),
193 type_: Some(self.event_type),
194 key: Some(self.key),
195 modifiers: self.modifiers,
196 lock_state: self.lock_state,
197 repeat_sequence: Some(self.repeat_sequence),
198 key_meaning: self.key_meaning,
199 ..Default::default()
200 }
201 }
202}
203
204impl KeyboardEvent {
205 pub fn same_key(this: &KeyboardEvent, that: &KeyboardEvent) -> bool {
207 this.get_key() == that.get_key()
208 }
209}
210
211#[derive(Clone, Debug, PartialEq)]
213pub struct KeyboardDeviceDescriptor {
214 pub keys: Vec<fidl_fuchsia_input::Key>,
216
217 pub device_information: fidl_fuchsia_input_report::DeviceInformation,
219
220 pub device_id: u32,
222}
223
224#[cfg(test)]
225impl Default for KeyboardDeviceDescriptor {
226 fn default() -> Self {
227 KeyboardDeviceDescriptor {
228 keys: vec![],
229 device_information: fidl_fuchsia_input_report::DeviceInformation {
230 vendor_id: Some(0),
231 product_id: Some(0),
232 version: Some(0),
233 polling_rate: Some(0),
234 ..Default::default()
235 },
236 device_id: 0,
237 }
238 }
239}
240
241pub struct KeyboardBinding {
247 event_sender: UnboundedSender<Vec<InputEvent>>,
249
250 device_descriptor: KeyboardDeviceDescriptor,
252}
253
254#[async_trait]
255impl input_device::InputDeviceBinding for KeyboardBinding {
256 fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>> {
257 self.event_sender.clone()
258 }
259
260 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
261 input_device::InputDeviceDescriptor::Keyboard(self.device_descriptor.clone())
262 }
263}
264
265impl KeyboardBinding {
266 pub async fn new(
281 device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
282 device_id: u32,
283 input_event_sender: UnboundedSender<Vec<InputEvent>>,
284 device_node: fuchsia_inspect::Node,
285 feature_flags: input_device::InputPipelineFeatureFlags,
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.clone(),
303 feature_flags,
304 Self::process_reports,
305 );
306
307 Ok(device_binding)
308 }
309
310 pub fn to_modifiers(keys: &[&fidl_fuchsia_input::Key]) -> Option<fidl_ui_input3::Modifiers> {
321 let mut modifiers = fidl_ui_input3::Modifiers::empty();
322 for key in keys {
323 let modifier = match key {
324 fidl_fuchsia_input::Key::CapsLock => Some(fidl_ui_input3::Modifiers::CAPS_LOCK),
325 fidl_fuchsia_input::Key::NumLock => Some(fidl_ui_input3::Modifiers::NUM_LOCK),
326 fidl_fuchsia_input::Key::ScrollLock => Some(fidl_ui_input3::Modifiers::SCROLL_LOCK),
327 _ => None,
328 };
329 if let Some(modifier) = modifier {
330 modifiers.insert(modifier);
331 };
332 }
333 if modifiers.is_empty() {
334 return None;
335 }
336 Some(modifiers)
337 }
338
339 async fn bind_device(
351 device: &fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
352 input_event_sender: UnboundedSender<Vec<InputEvent>>,
353 device_id: u32,
354 device_node: fuchsia_inspect::Node,
355 metrics_logger: metrics::MetricsLogger,
356 ) -> Result<(Self, InputDeviceStatus), Error> {
357 let mut input_device_status = InputDeviceStatus::new(device_node);
358 let descriptor = match device.get_descriptor().await {
359 Ok(descriptor) => descriptor.descriptor,
360 Err(_) => {
361 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
362 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
363 }
364 };
365
366 let device_info = descriptor.device_information.ok_or_else(|| {
367 input_device_status.health_node.set_unhealthy("Empty device_information in descriptor");
368 metrics_logger.log_error(
371 InputPipelineErrorMetricDimensionEvent::KeyboardEmptyDeviceInfo,
372 std::format!("DRIVER BUG: empty device_information for device_id: {}", device_id),
373 );
374 format_err!("empty device info for device_id: {}", device_id)
375 })?;
376 match descriptor.keyboard {
377 Some(fidl_next_fuchsia_input_report::KeyboardDescriptor {
378 input: Some(fidl_next_fuchsia_input_report::KeyboardInputDescriptor { keys3, .. }),
379 output: _,
380 ..
381 }) => Ok((
382 KeyboardBinding {
383 event_sender: input_event_sender,
384 device_descriptor: KeyboardDeviceDescriptor {
385 keys: keys3
386 .unwrap_or_default()
387 .into_iter()
388 .map(|k| utils::key_to_old(&k))
389 .collect(),
390 device_information: fidl_fuchsia_input_report::DeviceInformation {
391 vendor_id: device_info.vendor_id,
392 product_id: device_info.product_id,
393 version: device_info.version,
394 polling_rate: device_info.polling_rate,
395 ..Default::default()
396 },
397 device_id,
398 },
399 },
400 input_device_status,
401 )),
402 device_descriptor => {
403 input_device_status
404 .health_node
405 .set_unhealthy("Keyboard Device Descriptor failed to parse.");
406 Err(format_err!(
407 "Keyboard Device Descriptor failed to parse: \n {:?}",
408 device_descriptor
409 ))
410 }
411 }
412 }
413
414 fn process_reports(
436 reports: &[fidl_next_fuchsia_input_report::wire::InputReport<'_>],
437 mut previous_state: Option<input_device::PreviousDeviceState>,
438 device_descriptor: &input_device::InputDeviceDescriptor,
439 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
440 inspect_status: &InputDeviceStatus,
441 metrics_logger: &metrics::MetricsLogger,
442 _feature_flags: &input_device::InputPipelineFeatureFlags,
443 ) -> (Option<input_device::PreviousDeviceState>, Option<UnboundedReceiver<InputEvent>>) {
444 fuchsia_trace::duration!("input", "keyboard-binding-process-report", "num_reports" => reports.len());
445 let (inspect_sender, inspect_receiver) = futures::channel::mpsc::unbounded();
446
447 for report in reports {
448 previous_state = Self::process_report(
449 report,
450 previous_state,
451 device_descriptor,
452 input_event_sender,
453 inspect_status,
454 metrics_logger,
455 inspect_sender.clone(),
456 );
457 }
458 (previous_state, Some(inspect_receiver))
459 }
460
461 fn process_report(
462 report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
463 previous_state: Option<input_device::PreviousDeviceState>,
464 device_descriptor: &input_device::InputDeviceDescriptor,
465 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
466 inspect_status: &InputDeviceStatus,
467 metrics_logger: &metrics::MetricsLogger,
468 inspect_sender: UnboundedSender<InputEvent>,
469 ) -> Option<input_device::PreviousDeviceState> {
470 if let Some(trace_id) = report.trace_id() {
471 fuchsia_trace::flow_end!("input", "input_report", trace_id.0.into());
472 }
473
474 let tracing_id = fuchsia_trace::Id::new();
475 fuchsia_trace::flow_begin!("input", "key_event_thread", tracing_id);
476
477 inspect_status.count_received_report_wire(report);
478 match report.keyboard() {
480 None => {
481 inspect_status.count_filtered_report();
482 return previous_state;
483 }
484 _ => (),
485 };
486
487 let new_keys = match KeyboardBinding::parse_pressed_keys_wire(report) {
488 Some(keys) => keys,
489 None => {
490 metrics_logger.log_error(
496 InputPipelineErrorMetricDimensionEvent::KeyboardFailedToParse,
497 std::format!("Failed to parse keyboard keys: {:?}", report),
498 );
499 inspect_status.count_filtered_report();
500 return previous_state;
501 }
502 };
503
504 let previous_keys: Vec<fidl_fuchsia_input::Key> = match previous_state {
505 Some(input_device::PreviousDeviceState::Keyboard { pressed_keys }) => pressed_keys,
506 _ => vec![],
507 };
508
509 KeyboardBinding::send_key_events(
510 &new_keys,
511 &previous_keys,
512 device_descriptor.clone(),
513 zx::MonotonicInstant::get(),
514 input_event_sender.clone(),
515 inspect_sender,
516 metrics_logger,
517 tracing_id,
518 );
519
520 Some(input_device::PreviousDeviceState::Keyboard { pressed_keys: new_keys })
521 }
522
523 fn parse_pressed_keys_wire(
524 input_report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
525 ) -> Option<Vec<fidl_fuchsia_input::Key>> {
526 input_report
527 .keyboard()
528 .and_then(|unwrapped_keyboard| unwrapped_keyboard.pressed_keys3())
529 .map(|unwrapped_keys| {
530 unwrapped_keys
531 .iter()
532 .map(|&k| {
533 let natural_key = fidl_next::FromWire::from_wire(k);
534 utils::key_to_old(&natural_key)
535 })
536 .collect()
537 })
538 }
539
540 fn send_key_events(
549 new_keys: &Vec<fidl_fuchsia_input::Key>,
550 previous_keys: &Vec<fidl_fuchsia_input::Key>,
551 device_descriptor: input_device::InputDeviceDescriptor,
552 event_time: zx::MonotonicInstant,
553 input_event_sender: UnboundedSender<Vec<InputEvent>>,
554 inspect_sender: UnboundedSender<input_device::InputEvent>,
555 metrics_logger: &metrics::MetricsLogger,
556 tracing_id: fuchsia_trace::Id,
557 ) {
558 fn dispatch_events(
562 key_events: Vec<(fidl_fuchsia_input::Key, fidl_fuchsia_ui_input3::KeyEventType)>,
563 device_descriptor: input_device::InputDeviceDescriptor,
564 event_time: zx::MonotonicInstant,
565 input_event_sender: UnboundedSender<Vec<input_device::InputEvent>>,
566 inspect_sender: UnboundedSender<input_device::InputEvent>,
567 metrics_logger: metrics::MetricsLogger,
568 tracing_id: fuchsia_trace::Id,
569 ) {
570 Dispatcher::spawn_local(async move {
571 fuchsia_trace::duration!("input", "key_event_thread");
572 fuchsia_trace::flow_end!("input", "key_event_thread", tracing_id);
573
574 let mut event_time = event_time;
575 for (key, event_type) in key_events.into_iter() {
576 let trace_id = fuchsia_trace::Id::new();
577 fuchsia_trace::duration!("input", "keyboard_event_in_binding");
578 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
579
580 let event = input_device::InputEvent {
581 device_event: input_device::InputDeviceEvent::Keyboard(KeyboardEvent::new(
582 key, event_type,
583 )),
584 device_descriptor: device_descriptor.clone(),
585 event_time,
586 handled: Handled::No,
587 trace_id: Some(trace_id),
588 };
589 match input_event_sender.unbounded_send(vec![event.clone()]) {
590 Err(error) => {
591 metrics_logger.log_error(
592 InputPipelineErrorMetricDimensionEvent::KeyboardFailedToSendKeyboardEvent,
593 std::format!(
594 "Failed to send KeyboardEvent for key: {:?}, event_type: {:?}: {:?}",
595 key,
596 event_type,
597 error));
598 }
599 _ => {
600 let _ = inspect_sender.unbounded_send(event).expect("Failed to count generated KeyboardEvent in Input Pipeline Inspect tree.");
601 }
602 }
603 event_time = event_time + zx::MonotonicDuration::from_nanos(1);
608 }
609 }).detach();
610 }
611
612 let pressed_keys = new_keys
615 .iter()
616 .cloned()
617 .filter(|key| !previous_keys.contains(key))
618 .map(|k| (k, fidl_fuchsia_ui_input3::KeyEventType::Pressed));
619
620 let released_keys = previous_keys
623 .iter()
624 .cloned()
625 .filter(|key| !new_keys.contains(key))
626 .map(|k| (k, fidl_fuchsia_ui_input3::KeyEventType::Released));
627
628 let all_keys = released_keys.chain(pressed_keys).collect::<Vec<_>>();
633
634 dispatch_events(
635 all_keys,
636 device_descriptor,
637 event_time,
638 input_event_sender,
639 inspect_sender,
640 metrics_logger.clone(),
641 tracing_id,
642 );
643 }
644}
645
646#[cfg(test)]
647mod tests {
648 use super::*;
649 use crate::testing_utilities;
650 use fuchsia_async as fasync;
651 use futures::StreamExt;
652
653 #[fasync::run_singlethreaded(test)]
656 async fn pressed_key() {
657 let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
658 keys: vec![fidl_fuchsia_input::Key::A],
659 ..Default::default()
660 });
661 let (event_time_i64, _) = testing_utilities::event_times();
662
663 let reports = vec![testing_utilities::create_keyboard_input_report(
664 vec![fidl_fuchsia_input::Key::A],
665 event_time_i64,
666 )];
667 let expected_events = vec![testing_utilities::create_keyboard_event(
668 fidl_fuchsia_input::Key::A,
669 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
670 None,
671 &descriptor,
672 None,
673 )];
674
675 assert_input_report_sequence_generates_events!(
676 input_reports: reports,
677 expected_events: expected_events,
678 device_descriptor: descriptor,
679 device_type: KeyboardBinding,
680 );
681 }
682
683 #[fasync::run_singlethreaded(test)]
686 async fn released_key() {
687 let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
688 keys: vec![fidl_fuchsia_input::Key::A],
689 ..Default::default()
690 });
691 let (event_time_i64, _) = testing_utilities::event_times();
692
693 let reports = vec![
694 testing_utilities::create_keyboard_input_report(
695 vec![fidl_fuchsia_input::Key::A],
696 event_time_i64,
697 ),
698 testing_utilities::create_keyboard_input_report(vec![], event_time_i64),
699 ];
700
701 let expected_events = vec![
702 testing_utilities::create_keyboard_event(
703 fidl_fuchsia_input::Key::A,
704 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
705 None,
706 &descriptor,
707 None,
708 ),
709 testing_utilities::create_keyboard_event(
710 fidl_fuchsia_input::Key::A,
711 fidl_fuchsia_ui_input3::KeyEventType::Released,
712 None,
713 &descriptor,
714 None,
715 ),
716 ];
717
718 assert_input_report_sequence_generates_events!(
719 input_reports: reports,
720 expected_events: expected_events,
721 device_descriptor: descriptor.clone(),
722 device_type: KeyboardBinding,
723 );
724 }
725
726 #[fasync::run_singlethreaded(test)]
729 async fn multiple_pressed_event_filtering() {
730 let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
731 keys: vec![fidl_fuchsia_input::Key::A],
732 ..Default::default()
733 });
734 let (event_time_i64, _) = testing_utilities::event_times();
735
736 let reports = vec![
737 testing_utilities::create_keyboard_input_report(
738 vec![fidl_fuchsia_input::Key::A],
739 event_time_i64,
740 ),
741 testing_utilities::create_keyboard_input_report(
742 vec![fidl_fuchsia_input::Key::A],
743 event_time_i64,
744 ),
745 ];
746
747 let expected_events = vec![testing_utilities::create_keyboard_event(
748 fidl_fuchsia_input::Key::A,
749 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
750 None,
751 &descriptor,
752 None,
753 )];
754
755 assert_input_report_sequence_generates_events!(
756 input_reports: reports,
757 expected_events: expected_events,
758 device_descriptor: descriptor,
759 device_type: KeyboardBinding,
760 );
761 }
762
763 #[fasync::run_singlethreaded(test)]
765 async fn pressed_and_released_keys() {
766 let descriptor = input_device::InputDeviceDescriptor::Keyboard(KeyboardDeviceDescriptor {
767 keys: vec![fidl_fuchsia_input::Key::A, fidl_fuchsia_input::Key::B],
768 ..Default::default()
769 });
770 let (event_time_i64, _) = testing_utilities::event_times();
771
772 let reports = vec![
773 testing_utilities::create_keyboard_input_report(
774 vec![fidl_fuchsia_input::Key::A],
775 event_time_i64,
776 ),
777 testing_utilities::create_keyboard_input_report(
778 vec![fidl_fuchsia_input::Key::B],
779 event_time_i64,
780 ),
781 ];
782
783 let expected_events = vec![
784 testing_utilities::create_keyboard_event(
785 fidl_fuchsia_input::Key::A,
786 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
787 None,
788 &descriptor,
789 None,
790 ),
791 testing_utilities::create_keyboard_event(
792 fidl_fuchsia_input::Key::A,
793 fidl_fuchsia_ui_input3::KeyEventType::Released,
794 None,
795 &descriptor,
796 None,
797 ),
798 testing_utilities::create_keyboard_event(
799 fidl_fuchsia_input::Key::B,
800 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
801 None,
802 &descriptor,
803 None,
804 ),
805 ];
806
807 assert_input_report_sequence_generates_events!(
808 input_reports: reports,
809 expected_events: expected_events,
810 device_descriptor: descriptor,
811 device_type: KeyboardBinding,
812 );
813 }
814
815 #[fuchsia::test]
816 fn get_unsided_modifiers() {
817 use fidl_ui_input3::Modifiers;
818 let event = KeyboardEvent::new(fidl_fuchsia_input::Key::A, KeyEventType::Pressed)
819 .into_with_modifiers(Some(Modifiers::all()));
820 assert_eq!(
821 event.get_unsided_modifiers(),
822 Modifiers::CAPS_LOCK
823 | Modifiers::NUM_LOCK
824 | Modifiers::SCROLL_LOCK
825 | Modifiers::FUNCTION
826 | Modifiers::SYMBOL
827 | Modifiers::SHIFT
828 | Modifiers::ALT
829 | Modifiers::ALT_GRAPH
830 | Modifiers::META
831 | Modifiers::CTRL
832 )
833 }
834
835 #[fuchsia::test]
836 fn conversion_fills_out_all_fields() {
837 use fidl_fuchsia_input::Key;
838 use fidl_ui_input3::{KeyMeaning, LockState, Modifiers, NonPrintableKey};
839 let event = KeyboardEvent::new(Key::A, KeyEventType::Pressed)
840 .into_with_modifiers(Some(Modifiers::all()))
841 .into_with_lock_state(Some(LockState::all()))
842 .into_with_repeat_sequence(42)
843 .into_with_key_meaning(Some(KeyMeaning::NonPrintableKey(NonPrintableKey::Tab)));
844
845 let actual = event.from_key_event_at_time(zx::MonotonicInstant::from_nanos(42));
846 assert_eq!(
847 actual,
848 fidl_fuchsia_ui_input3::KeyEvent {
849 timestamp: Some(42),
850 type_: Some(KeyEventType::Pressed),
851 key: Some(Key::A),
852 modifiers: Some(Modifiers::all()),
853 key_meaning: Some(KeyMeaning::NonPrintableKey(NonPrintableKey::Tab)),
854 repeat_sequence: Some(42),
855 lock_state: Some(LockState::all()),
856 ..Default::default()
857 }
858 );
859 }
860}