input_pipeline/
ime_handler.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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/// Modifier state plus a tester method.
35#[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
52/// [`ImeHandler`] is responsible for dispatching key events to the IME service, thus making sure
53/// that key events are delivered to application runtimes (e.g., web, Flutter).
54///
55/// > NOTE: The [ImeHandler] requires [ModifierHandler] to be installed upstream to apply the keymaps correctly.
56pub struct ImeHandler {
57    /// The FIDL proxy (client-side stub) to the service for key event injection.
58    key_event_injector: fidl_ui_input3::KeyEventInjectorProxy,
59
60    /// The inventory of this handler's Inspect status.
61    pub inspect_status: InputHandlerStatus,
62
63    /// The metrics logger.
64    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                // Consume the input event.
94                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    /// Creates a new [`ImeHandler`] by connecting out to the key event injector.
112    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    /// Creates a new [`ImeHandler`].
122    ///
123    /// # Parameters
124    /// `key_event_injector`: A proxy (FIDL client-side stub) to the key event
125    /// injector FIDL service.
126    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            /* generates_events */ false,
135        );
136        let handler = ImeHandler { key_event_injector, inspect_status, metrics_logger };
137
138        Ok(Rc::new(handler))
139    }
140
141    /// Dispatches key events to IME and returns KeyboardEvents for unhandled events.
142    ///
143    /// # Parameters
144    /// `key_events`: The key events to dispatch.
145    /// `event_time`: The time in nanoseconds when the events were first recorded.
146    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
162/// Returns a KeyEvent with the given parameters.
163///
164/// # Parameters
165/// * `event`: The keyboard event to process.
166/// * `event_time`: The time in nanoseconds when the event was first recorded.
167fn 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    // Don't override the key meaning if already set, e.g. by prior stage.
184    let key_meaning = event
185        .get_key_meaning()
186        .or_else(|| keymaps::US_QWERTY.apply(event.get_key(), &modifier_state, &lock_state));
187
188    // Don't insert a spurious Some(0).
189    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            // All the expected events have been received, so make sure no more events
251            // are present before returning.
252            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            /* key_meaning */ 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    /// Tests that a pressed key event is dispatched.
327    ///
328    /// > NOTE: The `device_descriptor` used in this test case and elsewhere
329    /// *must* be of type `KeyboardDeviceDescriptor` as this is required by the
330    /// pattern matching in `ImeHandler`.
331    #[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            /* keymap= */ 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            // A key "A" without shift is a lowercase 'a'.
363            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    /// Tests that a released key event is dispatched.
373    #[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            /* keymap= */ 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    /// Tests that both pressed and released keys are dispatched appropriately.
414    #[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                /* keymap= */ 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                /* keymap= */ 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                /* keymap= */ 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                /* keymap= */ 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    // Tests that modifier keys are dispatched appropriately.
508    //
509    // This test depends on the incoming event having correct modifier and lock
510    // state.  Typically you'd do this by installing a ModifierHandler upstream
511    // of this pipeline stage.
512    #[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                /* keymap= */ 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                /* keymap= */ 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                /* keymap= */ 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                // Test that things also work when a key is released.
675                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            /* keymap= */ 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                /* keymap= */ 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                /* keymap= */ 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                /* keymap= */ 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)), // "A"
809                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                /* keymap= */ 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                /* keymap= */ 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                        // Timestamp value is unpredictable and not relevant in this context,
900                        // so we only assert that the property is present.
901                        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                /* keymap= */ None,
932            ),
933            // Should not count received events that have already been handled.
934            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                /* keymap= */ None,
941                /* key_meaning= */ 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                /* keymap= */ None,
951            ),
952            // Should not count non-keyboard input events.
953            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                /* keymap= */ 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                        // Timestamp value is unpredictable and not relevant in this context,
979                        // so we only assert that the property is present.
980                        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}