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