1use crate::input_handler::{InputHandlerStatus, UnhandledInputHandler};
6use crate::{input_device, keyboard_binding, metrics};
7use anyhow::Error;
8use async_trait::async_trait;
9use fidl_fuchsia_ui_input3::{self as fidl_ui_input3, LockState, Modifiers};
10use fuchsia_component::client::connect_to_protocol;
11use fuchsia_inspect::health::Reporter;
12
13use keymaps::{LockStateChecker, ModifierChecker};
14use metrics_registry::*;
15use std::rc::Rc;
16
17#[derive(Debug)]
18pub struct FrozenLockState {
19 lock_state: LockState,
20}
21
22impl From<LockState> for FrozenLockState {
23 fn from(lock_state: LockState) -> Self {
24 FrozenLockState { lock_state }
25 }
26}
27
28impl LockStateChecker for FrozenLockState {
29 fn test(&self, value: LockState) -> bool {
30 self.lock_state.contains(value)
31 }
32}
33
34#[derive(Debug)]
36pub struct FrozenModifierState {
37 state: Modifiers,
38}
39
40impl From<fidl_fuchsia_ui_input3::Modifiers> for FrozenModifierState {
41 fn from(state: Modifiers) -> Self {
42 FrozenModifierState { state }
43 }
44}
45
46impl ModifierChecker for FrozenModifierState {
47 fn test(&self, value: Modifiers) -> bool {
48 self.state.contains(value)
49 }
50}
51
52pub struct ImeHandler {
57 key_event_injector: fidl_ui_input3::KeyEventInjectorProxy,
59
60 pub inspect_status: InputHandlerStatus,
62
63 metrics_logger: metrics::MetricsLogger,
65}
66
67#[async_trait(?Send)]
68impl UnhandledInputHandler for ImeHandler {
69 async fn handle_unhandled_input_event(
70 self: Rc<Self>,
71 unhandled_input_event: input_device::UnhandledInputEvent,
72 ) -> Vec<input_device::InputEvent> {
73 match unhandled_input_event {
74 input_device::UnhandledInputEvent {
75 device_event: input_device::InputDeviceEvent::Keyboard(ref keyboard_device_event),
76 device_descriptor:
77 input_device::InputDeviceDescriptor::Keyboard(ref keyboard_description),
78 event_time,
79 trace_id: _,
80 } => {
81 self.inspect_status.count_received_event(input_device::InputEvent::from(
82 unhandled_input_event.clone(),
83 ));
84 let key_event = create_key_event(
85 &keyboard_device_event,
86 event_time,
87 keyboard_description.device_id,
88 );
89 self.dispatch_key(key_event).await;
90 self.inspect_status.count_handled_event();
92 vec![input_device::InputEvent::from(unhandled_input_event).into_handled()]
93 }
94 _ => vec![input_device::InputEvent::from(unhandled_input_event)],
95 }
96 }
97
98 fn set_handler_healthy(self: std::rc::Rc<Self>) {
99 self.inspect_status.health_node.borrow_mut().set_ok();
100 }
101
102 fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
103 self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
104 }
105}
106
107impl ImeHandler {
108 pub async fn new(
110 input_handlers_node: &fuchsia_inspect::Node,
111 metrics_logger: metrics::MetricsLogger,
112 ) -> Result<Rc<Self>, Error> {
113 let key_event_injector = connect_to_protocol::<fidl_ui_input3::KeyEventInjectorMarker>()?;
114
115 Self::new_handler(key_event_injector, input_handlers_node, metrics_logger).await
116 }
117
118 async fn new_handler(
124 key_event_injector: fidl_ui_input3::KeyEventInjectorProxy,
125 input_handlers_node: &fuchsia_inspect::Node,
126 metrics_logger: metrics::MetricsLogger,
127 ) -> Result<Rc<Self>, Error> {
128 let inspect_status = InputHandlerStatus::new(
129 input_handlers_node,
130 "ime_handler",
131 false,
132 );
133 let handler = ImeHandler { key_event_injector, inspect_status, metrics_logger };
134
135 Ok(Rc::new(handler))
136 }
137
138 async fn dispatch_key(self: &Rc<Self>, key_event: fidl_ui_input3::KeyEvent) {
144 assert!(
145 key_event.timestamp.is_some(),
146 "dispatch_key: got a key_event without a timestamp: {:?}",
147 &key_event
148 );
149 match self.key_event_injector.inject(&key_event).await {
150 Err(err) => self.metrics_logger.log_error(
151 InputPipelineErrorMetricDimensionEvent::ImeFailedToDispatchKeyToIme,
152 std::format!("Failed to dispatch key to IME: {:?}", err),
153 ),
154 _ => {}
155 };
156 }
157}
158
159fn create_key_event(
165 event: &keyboard_binding::KeyboardEvent,
166 event_time: zx::MonotonicInstant,
167 device_id: u32,
168) -> fidl_ui_input3::KeyEvent {
169 let modifier_state: FrozenModifierState =
170 event.get_modifiers().unwrap_or_else(|| Modifiers::from_bits_allow_unknown(0)).into();
171 let lock_state: FrozenLockState =
172 event.get_lock_state().unwrap_or_else(|| LockState::from_bits_allow_unknown(0)).into();
173 log::debug!(
174 "ImeHandler::create_key_event: key:{:?}, modifier_state: {:?}, lock_state: {:?}, event_type: {:?}",
175 event.get_key(),
176 modifier_state,
177 lock_state,
178 event.get_event_type(),
179 );
180 let key_meaning = event
182 .get_key_meaning()
183 .or_else(|| keymaps::US_QWERTY.apply(event.get_key(), &modifier_state, &lock_state));
184
185 let repeat_sequence = match event.get_repeat_sequence() {
187 0 => None,
188 s => Some(s),
189 };
190
191 fidl_ui_input3::KeyEvent {
192 timestamp: Some(event_time.into_nanos()),
193 type_: event.get_event_type().into(),
194 key: event.get_key().into(),
195 modifiers: event.get_modifiers(),
196 lock_state: event.get_lock_state(),
197 key_meaning,
198 repeat_sequence,
199 device_id: Some(device_id),
200 ..Default::default()
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207 use crate::input_handler::InputHandler;
208 use crate::keyboard_binding::{self, KeyboardEvent};
209 use crate::testing_utilities;
210 use assert_matches::assert_matches;
211 use futures::StreamExt;
212 use std::convert::TryFrom as _;
213 use test_case::test_case;
214 use {
215 fidl_fuchsia_input as fidl_input, fidl_fuchsia_ui_input3 as fidl_ui_input3,
216 fuchsia_async as fasync,
217 };
218
219 fn handle_events(
220 ime_handler: Rc<ImeHandler>,
221 input_events: Vec<input_device::UnhandledInputEvent>,
222 ) {
223 fasync::Task::local(async move {
224 for input_event in input_events {
225 assert_matches!(
226 ime_handler.clone().handle_unhandled_input_event(input_event).await.as_slice(),
227 [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
228 );
229 }
230 })
231 .detach();
232 }
233
234 async fn assert_ime_receives_events(
235 expected_events: Vec<fidl_ui_input3::KeyEvent>,
236 mut request_stream: fidl_ui_input3::KeyEventInjectorRequestStream,
237 ) {
238 let mut expected_events_iter = expected_events.iter().peekable();
239 while let Some(Ok(fidl_ui_input3::KeyEventInjectorRequest::Inject {
240 key_event,
241 responder,
242 ..
243 })) = request_stream.next().await
244 {
245 pretty_assertions::assert_eq!(&key_event, expected_events_iter.next().unwrap());
246
247 if expected_events_iter.peek().is_none() {
250 responder
251 .send(fidl_ui_input3::KeyEventStatus::Handled)
252 .expect("error responding to DispatchKey");
253 return;
254 }
255 responder
256 .send(fidl_ui_input3::KeyEventStatus::Handled)
257 .expect("error responding to DispatchKey");
258 }
259
260 assert!(false);
261 }
262
263 fn connect_to_key_event_injector(
264 ) -> (fidl_ui_input3::KeyEventInjectorProxy, fidl_ui_input3::KeyEventInjectorRequestStream)
265 {
266 fidl::endpoints::create_proxy_and_stream::<fidl_ui_input3::KeyEventInjectorMarker>()
267 }
268
269 fn create_unhandled_keyboard_event(
270 key: fidl_fuchsia_input::Key,
271 event_type: fidl_fuchsia_ui_input3::KeyEventType,
272 modifiers: Option<fidl_ui_input3::Modifiers>,
273 event_time: zx::MonotonicInstant,
274 device_descriptor: &input_device::InputDeviceDescriptor,
275 keymap: Option<String>,
276 ) -> input_device::UnhandledInputEvent {
277 create_unhandled_keyboard_event_with_key_meaning(
278 key,
279 event_type,
280 modifiers,
281 event_time,
282 device_descriptor,
283 keymap,
284 None,
285 )
286 }
287
288 fn create_unhandled_keyboard_event_with_key_meaning(
289 key: fidl_fuchsia_input::Key,
290 event_type: fidl_fuchsia_ui_input3::KeyEventType,
291 modifiers: Option<fidl_ui_input3::Modifiers>,
292 event_time: zx::MonotonicInstant,
293 device_descriptor: &input_device::InputDeviceDescriptor,
294 keymap: Option<String>,
295 key_meaning: Option<fidl_fuchsia_ui_input3::KeyMeaning>,
296 ) -> input_device::UnhandledInputEvent {
297 input_device::UnhandledInputEvent::try_from(
298 testing_utilities::create_keyboard_event_with_key_meaning(
299 key,
300 event_type,
301 modifiers,
302 event_time,
303 device_descriptor,
304 keymap,
305 key_meaning,
306 ),
307 )
308 .unwrap()
309 }
310
311 fn create_unhandled_input_event(
312 keyboard_event: keyboard_binding::KeyboardEvent,
313 device_descriptor: &input_device::InputDeviceDescriptor,
314 event_time: zx::MonotonicInstant,
315 ) -> input_device::UnhandledInputEvent {
316 input_device::UnhandledInputEvent {
317 device_event: input_device::InputDeviceEvent::Keyboard(keyboard_event),
318 device_descriptor: device_descriptor.clone(),
319 event_time,
320 trace_id: None,
321 }
322 }
323
324 #[fasync::run_singlethreaded(test)]
330 async fn pressed_key() {
331 let (proxy, request_stream) = connect_to_key_event_injector();
332 let inspector = fuchsia_inspect::Inspector::default();
333 let test_node = inspector.root().create_child("test_node");
334 let ime_handler =
335 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
336 .await
337 .expect("Failed to create ImeHandler.");
338
339 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
340 keyboard_binding::KeyboardDeviceDescriptor {
341 keys: vec![fidl_input::Key::A],
342 device_id: 0,
343 ..Default::default()
344 },
345 );
346 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
347 let input_events = vec![create_unhandled_keyboard_event(
348 fidl_input::Key::A,
349 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
350 None,
351 event_time_u64,
352 &device_descriptor,
353 None,
354 )];
355
356 let expected_events = vec![fidl_ui_input3::KeyEvent {
357 timestamp: Some(event_time_i64),
358 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
359 key: Some(fidl_input::Key::A),
360 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
362 device_id: Some(0),
363 ..Default::default()
364 }];
365
366 handle_events(ime_handler, input_events);
367 assert_ime_receives_events(expected_events, request_stream).await;
368 }
369
370 #[fasync::run_singlethreaded(test)]
372 async fn released_key() {
373 let (proxy, request_stream) = connect_to_key_event_injector();
374 let inspector = fuchsia_inspect::Inspector::default();
375 let test_node = inspector.root().create_child("test_node");
376 let ime_handler =
377 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
378 .await
379 .expect("Failed to create ImeHandler.");
380
381 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
382 keyboard_binding::KeyboardDeviceDescriptor {
383 keys: vec![fidl_input::Key::A],
384 device_id: 0,
385 ..Default::default()
386 },
387 );
388 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
389 let input_events = vec![create_unhandled_keyboard_event(
390 fidl_input::Key::A,
391 fidl_fuchsia_ui_input3::KeyEventType::Released,
392 None,
393 event_time_u64,
394 &device_descriptor,
395 None,
396 )];
397
398 let expected_events = vec![fidl_ui_input3::KeyEvent {
399 timestamp: Some(event_time_i64),
400 type_: Some(fidl_ui_input3::KeyEventType::Released),
401 key: Some(fidl_input::Key::A),
402 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
403 device_id: Some(0),
404 ..Default::default()
405 }];
406
407 handle_events(ime_handler, input_events);
408 assert_ime_receives_events(expected_events, request_stream).await;
409 }
410
411 #[fasync::run_singlethreaded(test)]
413 async fn pressed_and_released_key() {
414 let (proxy, request_stream) = connect_to_key_event_injector();
415 let inspector = fuchsia_inspect::Inspector::default();
416 let test_node = inspector.root().create_child("test_node");
417 let ime_handler =
418 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
419 .await
420 .expect("Failed to create ImeHandler.");
421
422 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
423 keyboard_binding::KeyboardDeviceDescriptor {
424 keys: vec![fidl_input::Key::A, fidl_input::Key::B],
425 device_id: 0,
426 ..Default::default()
427 },
428 );
429 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
430 let input_events = vec![
431 create_unhandled_keyboard_event(
432 fidl_input::Key::A,
433 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
434 None,
435 event_time_u64,
436 &device_descriptor,
437 None,
438 ),
439 create_unhandled_keyboard_event(
440 fidl_input::Key::A,
441 fidl_fuchsia_ui_input3::KeyEventType::Released,
442 None,
443 event_time_u64,
444 &device_descriptor,
445 None,
446 ),
447 create_unhandled_keyboard_event(
448 fidl_input::Key::B,
449 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
450 None,
451 event_time_u64,
452 &device_descriptor,
453 None,
454 ),
455 create_unhandled_keyboard_event_with_key_meaning(
456 fidl_input::Key::C,
457 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
458 None,
459 event_time_u64,
460 &device_descriptor,
461 None,
462 Some(fidl_fuchsia_ui_input3::KeyMeaning::Codepoint(42)),
463 ),
464 ];
465
466 let expected_events = vec![
467 fidl_ui_input3::KeyEvent {
468 timestamp: Some(event_time_i64),
469 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
470 key: Some(fidl_input::Key::A),
471 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
472 device_id: Some(0),
473 ..Default::default()
474 },
475 fidl_ui_input3::KeyEvent {
476 timestamp: Some(event_time_i64),
477 type_: Some(fidl_ui_input3::KeyEventType::Released),
478 key: Some(fidl_input::Key::A),
479 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
480 device_id: Some(0),
481 ..Default::default()
482 },
483 fidl_ui_input3::KeyEvent {
484 timestamp: Some(event_time_i64),
485 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
486 key: Some(fidl_input::Key::B),
487 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(98)),
488 device_id: Some(0),
489 ..Default::default()
490 },
491 fidl_ui_input3::KeyEvent {
492 timestamp: Some(event_time_i64),
493 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
494 key: Some(fidl_input::Key::C),
495 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(42)),
496 device_id: Some(0),
497 ..Default::default()
498 },
499 ];
500
501 handle_events(ime_handler, input_events);
502 assert_ime_receives_events(expected_events, request_stream).await;
503 }
504
505 #[fasync::run_singlethreaded(test)]
511 async fn repeated_modifier_key() {
512 let (proxy, request_stream) = connect_to_key_event_injector();
513 let inspector = fuchsia_inspect::Inspector::default();
514 let test_node = inspector.root().create_child("test_node");
515 let ime_handler =
516 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
517 .await
518 .expect("Failed to create ImeHandler.");
519
520 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
521 keyboard_binding::KeyboardDeviceDescriptor {
522 keys: vec![fidl_input::Key::A, fidl_input::Key::CapsLock],
523 device_id: 0,
524 ..Default::default()
525 },
526 );
527 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
528 let input_events = vec![
529 create_unhandled_input_event(
530 KeyboardEvent::new(
531 fidl_input::Key::CapsLock,
532 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
533 )
534 .into_with_modifiers(Some(fidl_ui_input3::Modifiers::CAPS_LOCK))
535 .into_with_lock_state(Some(fidl_ui_input3::LockState::CAPS_LOCK)),
536 &device_descriptor,
537 event_time_u64,
538 ),
539 create_unhandled_input_event(
540 KeyboardEvent::new(
541 fidl_input::Key::A,
542 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
543 )
544 .into_with_modifiers(Some(fidl_ui_input3::Modifiers::CAPS_LOCK))
545 .into_with_lock_state(Some(fidl_ui_input3::LockState::CAPS_LOCK)),
546 &device_descriptor,
547 event_time_u64,
548 ),
549 create_unhandled_input_event(
550 KeyboardEvent::new(
551 fidl_input::Key::CapsLock,
552 fidl_fuchsia_ui_input3::KeyEventType::Released,
553 )
554 .into_with_lock_state(Some(fidl_ui_input3::LockState::CAPS_LOCK)),
555 &device_descriptor,
556 event_time_u64,
557 ),
558 ];
559
560 let expected_events = vec![
561 fidl_ui_input3::KeyEvent {
562 timestamp: Some(event_time_i64),
563 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
564 key: Some(fidl_input::Key::CapsLock),
565 modifiers: Some(fidl_ui_input3::Modifiers::CAPS_LOCK),
566 lock_state: Some(fidl_ui_input3::LockState::CAPS_LOCK),
567 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
568 fidl_ui_input3::NonPrintableKey::CapsLock,
569 )),
570 device_id: Some(0),
571 ..Default::default()
572 },
573 fidl_ui_input3::KeyEvent {
574 timestamp: Some(event_time_i64),
575 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
576 key: Some(fidl_input::Key::A),
577 modifiers: Some(fidl_ui_input3::Modifiers::CAPS_LOCK),
578 lock_state: Some(fidl_ui_input3::LockState::CAPS_LOCK),
579 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(65)),
580 device_id: Some(0),
581 ..Default::default()
582 },
583 fidl_ui_input3::KeyEvent {
584 timestamp: Some(event_time_i64),
585 type_: Some(fidl_ui_input3::KeyEventType::Released),
586 key: Some(fidl_input::Key::CapsLock),
587 lock_state: Some(fidl_ui_input3::LockState::CAPS_LOCK),
588 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
589 fidl_ui_input3::NonPrintableKey::CapsLock,
590 )),
591 device_id: Some(0),
592 ..Default::default()
593 },
594 ];
595
596 handle_events(ime_handler, input_events);
597 assert_ime_receives_events(expected_events, request_stream).await;
598 }
599
600 #[fasync::run_singlethreaded(test)]
601 async fn nonprintable_key_meanings_set_correctly() {
602 let (proxy, request_stream) = connect_to_key_event_injector();
603 let inspector = fuchsia_inspect::Inspector::default();
604 let test_node = inspector.root().create_child("test_node");
605 let ime_handler =
606 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
607 .await
608 .expect("Failed to create ImeHandler.");
609
610 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
611 keyboard_binding::KeyboardDeviceDescriptor {
612 keys: vec![
613 fidl_input::Key::Enter,
614 fidl_input::Key::Tab,
615 fidl_input::Key::Backspace,
616 ],
617 device_id: 0,
618 ..Default::default()
619 },
620 );
621 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
622 let input_events = vec![
623 create_unhandled_keyboard_event(
624 fidl_input::Key::Enter,
625 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
626 None,
627 event_time_u64,
628 &device_descriptor,
629 None,
630 ),
631 create_unhandled_keyboard_event(
632 fidl_input::Key::Tab,
633 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
634 None,
635 event_time_u64,
636 &device_descriptor,
637 None,
638 ),
639 create_unhandled_keyboard_event(
640 fidl_input::Key::Backspace,
641 fidl_fuchsia_ui_input3::KeyEventType::Released,
642 None,
643 event_time_u64,
644 &device_descriptor,
645 None,
646 ),
647 ];
648
649 let expected_events = vec![
650 fidl_ui_input3::KeyEvent {
651 timestamp: Some(event_time_i64),
652 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
653 key: Some(fidl_input::Key::Enter),
654 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
655 fidl_ui_input3::NonPrintableKey::Enter,
656 )),
657 device_id: Some(0),
658 ..Default::default()
659 },
660 fidl_ui_input3::KeyEvent {
661 timestamp: Some(event_time_i64),
662 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
663 key: Some(fidl_input::Key::Tab),
664 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
665 fidl_ui_input3::NonPrintableKey::Tab,
666 )),
667 device_id: Some(0),
668 ..Default::default()
669 },
670 fidl_ui_input3::KeyEvent {
671 timestamp: Some(event_time_i64),
672 type_: Some(fidl_ui_input3::KeyEventType::Released),
674 key: Some(fidl_input::Key::Backspace),
675 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
676 fidl_ui_input3::NonPrintableKey::Backspace,
677 )),
678 device_id: Some(0),
679 ..Default::default()
680 },
681 ];
682
683 handle_events(ime_handler, input_events);
684 assert_ime_receives_events(expected_events, request_stream).await;
685 }
686
687 #[fasync::run_singlethreaded(test)]
688 async fn tab() {
689 let (proxy, request_stream) = connect_to_key_event_injector();
690 let inspector = fuchsia_inspect::Inspector::default();
691 let test_node = inspector.root().create_child("test_node");
692 let ime_handler =
693 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
694 .await
695 .expect("Failed to create ImeHandler.");
696
697 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
698 keyboard_binding::KeyboardDeviceDescriptor {
699 keys: vec![
700 fidl_input::Key::Enter,
701 fidl_input::Key::Tab,
702 fidl_input::Key::Backspace,
703 ],
704 device_id: 0,
705 ..Default::default()
706 },
707 );
708 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
709 let input_events = vec![create_unhandled_keyboard_event(
710 fidl_input::Key::Tab,
711 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
712 None,
713 event_time_u64,
714 &device_descriptor,
715 None,
716 )];
717
718 let expected_events = vec![fidl_ui_input3::KeyEvent {
719 timestamp: Some(event_time_i64),
720 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
721 key: Some(fidl_input::Key::Tab),
722 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
723 fidl_ui_input3::NonPrintableKey::Tab,
724 )),
725 device_id: Some(0),
726 ..Default::default()
727 }];
728
729 handle_events(ime_handler, input_events);
730 assert_ime_receives_events(expected_events, request_stream).await;
731 }
732
733 #[fasync::run_singlethreaded(test)]
734 async fn shift_shift_a() {
735 let (proxy, request_stream) = connect_to_key_event_injector();
736 let inspector = fuchsia_inspect::Inspector::default();
737 let test_node = inspector.root().create_child("test_node");
738 let ime_handler =
739 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
740 .await
741 .expect("Failed to create ImeHandler.");
742
743 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
744 keyboard_binding::KeyboardDeviceDescriptor {
745 keys: vec![fidl_input::Key::LeftCtrl, fidl_input::Key::Tab],
746 device_id: 0,
747 ..Default::default()
748 },
749 );
750 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
751 let input_events = vec![
752 create_unhandled_keyboard_event(
753 fidl_input::Key::LeftShift,
754 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
755 Some(Modifiers::LEFT_SHIFT | Modifiers::SHIFT),
756 event_time_u64,
757 &device_descriptor,
758 None,
759 ),
760 create_unhandled_keyboard_event(
761 fidl_input::Key::RightShift,
762 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
763 Some(Modifiers::LEFT_SHIFT | Modifiers::RIGHT_SHIFT | Modifiers::SHIFT),
764 event_time_u64,
765 &device_descriptor,
766 None,
767 ),
768 create_unhandled_keyboard_event(
769 fidl_input::Key::A,
770 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
771 Some(Modifiers::LEFT_SHIFT | Modifiers::RIGHT_SHIFT | Modifiers::SHIFT),
772 event_time_u64,
773 &device_descriptor,
774 None,
775 ),
776 ];
777
778 let expected_events = vec![
779 fidl_ui_input3::KeyEvent {
780 timestamp: Some(event_time_i64),
781 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
782 key: Some(fidl_input::Key::LeftShift),
783 modifiers: Some(Modifiers::LEFT_SHIFT | Modifiers::SHIFT),
784 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
785 fidl_ui_input3::NonPrintableKey::Shift,
786 )),
787 device_id: Some(0),
788 ..Default::default()
789 },
790 fidl_ui_input3::KeyEvent {
791 timestamp: Some(event_time_i64),
792 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
793 key: Some(fidl_input::Key::RightShift),
794 modifiers: Some(Modifiers::RIGHT_SHIFT | Modifiers::LEFT_SHIFT | Modifiers::SHIFT),
795 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
796 fidl_ui_input3::NonPrintableKey::Shift,
797 )),
798 device_id: Some(0),
799 ..Default::default()
800 },
801 fidl_ui_input3::KeyEvent {
802 timestamp: Some(event_time_i64),
803 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
804 key: Some(fidl_input::Key::A),
805 modifiers: Some(Modifiers::RIGHT_SHIFT | Modifiers::LEFT_SHIFT | Modifiers::SHIFT),
806 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(65)), device_id: Some(0),
808 ..Default::default()
809 },
810 ];
811
812 handle_events(ime_handler, input_events);
813 assert_ime_receives_events(expected_events, request_stream).await;
814 }
815
816 #[fasync::run_singlethreaded(test)]
817 async fn ctrl_tab() {
818 let (proxy, request_stream) = connect_to_key_event_injector();
819 let inspector = fuchsia_inspect::Inspector::default();
820 let test_node = inspector.root().create_child("test_node");
821 let ime_handler =
822 ImeHandler::new_handler(proxy, &test_node, metrics::MetricsLogger::default())
823 .await
824 .expect("Failed to create ImeHandler.");
825
826 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
827 keyboard_binding::KeyboardDeviceDescriptor {
828 keys: vec![fidl_input::Key::LeftCtrl, fidl_input::Key::Tab],
829 device_id: 0,
830 ..Default::default()
831 },
832 );
833 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
834 let input_events = vec![
835 create_unhandled_keyboard_event(
836 fidl_input::Key::LeftCtrl,
837 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
838 None,
839 event_time_u64,
840 &device_descriptor,
841 None,
842 ),
843 create_unhandled_keyboard_event(
844 fidl_input::Key::Tab,
845 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
846 None,
847 event_time_u64,
848 &device_descriptor,
849 None,
850 ),
851 ];
852
853 let expected_events = vec![
854 fidl_ui_input3::KeyEvent {
855 timestamp: Some(event_time_i64),
856 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
857 key: Some(fidl_input::Key::LeftCtrl),
858 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
859 fidl_ui_input3::NonPrintableKey::Control,
860 )),
861 device_id: Some(0),
862 ..Default::default()
863 },
864 fidl_ui_input3::KeyEvent {
865 timestamp: Some(event_time_i64),
866 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
867 key: Some(fidl_input::Key::Tab),
868 key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
869 fidl_ui_input3::NonPrintableKey::Tab,
870 )),
871 device_id: Some(0),
872 ..Default::default()
873 },
874 ];
875
876 handle_events(ime_handler, input_events);
877 assert_ime_receives_events(expected_events, request_stream).await;
878 }
879
880 #[fasync::run_singlethreaded(test)]
881 async fn ime_handler_initialized_with_inspect_node() {
882 let (proxy, _) = connect_to_key_event_injector();
883 let inspector = fuchsia_inspect::Inspector::default();
884 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
885 let _handler =
886 ImeHandler::new_handler(proxy, &fake_handlers_node, metrics::MetricsLogger::default())
887 .await
888 .expect("Failed to create ImeHandler.");
889 diagnostics_assertions::assert_data_tree!(inspector, root: {
890 input_handlers_node: {
891 ime_handler: {
892 events_received_count: 0u64,
893 events_handled_count: 0u64,
894 last_received_timestamp_ns: 0u64,
895 "fuchsia.inspect.Health": {
896 status: "STARTING_UP",
897 start_timestamp_nanos: diagnostics_assertions::AnyProperty
900 },
901 }
902 }
903 });
904 }
905
906 #[fasync::run_singlethreaded(test)]
907 async fn ime_handler_inspect_counts_events() {
908 let (proxy, _) = connect_to_key_event_injector();
909 let inspector = fuchsia_inspect::Inspector::default();
910 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
911 let ime_handler =
912 ImeHandler::new_handler(proxy, &fake_handlers_node, metrics::MetricsLogger::default())
913 .await
914 .expect("Failed to create ImeHandler.");
915 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
916 keyboard_binding::KeyboardDeviceDescriptor {
917 keys: vec![fidl_input::Key::A, fidl_input::Key::B],
918 ..Default::default()
919 },
920 );
921 let (_, event_time_u64) = testing_utilities::event_times();
922 let input_events = vec![
923 testing_utilities::create_keyboard_event_with_time(
924 fidl_input::Key::A,
925 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
926 None,
927 event_time_u64,
928 &device_descriptor,
929 None,
930 ),
931 testing_utilities::create_keyboard_event_with_handled(
933 fidl_input::Key::B,
934 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
935 None,
936 event_time_u64,
937 &device_descriptor,
938 None,
939 None,
940 input_device::Handled::Yes,
941 ),
942 testing_utilities::create_keyboard_event_with_time(
943 fidl_input::Key::A,
944 fidl_fuchsia_ui_input3::KeyEventType::Released,
945 None,
946 event_time_u64,
947 &device_descriptor,
948 None,
949 ),
950 testing_utilities::create_fake_input_event(event_time_u64),
952 testing_utilities::create_keyboard_event_with_time(
953 fidl_input::Key::B,
954 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
955 None,
956 event_time_u64,
957 &device_descriptor,
958 None,
959 ),
960 ];
961
962 for input_event in input_events {
963 let _ = ime_handler.clone().handle_input_event(input_event).await;
964 }
965
966 let last_event_timestamp: u64 = event_time_u64.into_nanos().try_into().unwrap();
967
968 diagnostics_assertions::assert_data_tree!(inspector, root: {
969 input_handlers_node: {
970 ime_handler: {
971 events_received_count: 3u64,
972 events_handled_count: 3u64,
973 last_received_timestamp_ns: last_event_timestamp,
974 "fuchsia.inspect.Health": {
975 status: "STARTING_UP",
976 start_timestamp_nanos: diagnostics_assertions::AnyProperty
979 },
980 }
981 }
982 });
983 }
984
985 #[test_case(
986 keyboard_binding::KeyboardEvent::new(
987 fidl_input::Key::A,
988 fidl_ui_input3::KeyEventType::Pressed),
989 zx::MonotonicInstant::from_nanos(42) => fidl_ui_input3::KeyEvent{
990 timestamp: Some(42),
991 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
992 key: Some(fidl_input::Key::A),
993 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
994 device_id: Some(0),
995 ..Default::default()}; "basic value copy")]
996 #[test_case(
997 keyboard_binding::KeyboardEvent::new(
998 fidl_input::Key::A,
999 fidl_ui_input3::KeyEventType::Pressed)
1000 .into_with_repeat_sequence(13),
1001 zx::MonotonicInstant::from_nanos(42) => fidl_ui_input3::KeyEvent{
1002 timestamp: Some(42),
1003 type_: Some(fidl_ui_input3::KeyEventType::Pressed),
1004 key: Some(fidl_input::Key::A),
1005 key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
1006 repeat_sequence: Some(13),
1007 device_id: Some(0),
1008 ..Default::default()}; "repeat_sequence is honored")]
1009 fn test_create_key_event(
1010 event: keyboard_binding::KeyboardEvent,
1011 event_time: zx::MonotonicInstant,
1012 ) -> fidl_ui_input3::KeyEvent {
1013 super::create_key_event(&event, event_time, 0)
1014 }
1015}