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