input_pipeline/
modifier_handler.rs

1// Copyright 2021 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_device::{
6    Handled, InputDeviceEvent, InputEvent, InputEventType, UnhandledInputEvent,
7};
8use crate::input_handler::{Handler, InputHandlerStatus, UnhandledInputHandler};
9use async_trait::async_trait;
10use fidl_fuchsia_ui_input3::{KeyMeaning, Modifiers, NonPrintableKey};
11use fuchsia_inspect::health::Reporter;
12use keymaps::{LockStateKeys, ModifierState};
13use std::cell::RefCell;
14use std::rc::Rc;
15
16/// Tracks modifier state and decorates passing events with the modifiers.
17///
18/// This handler should be installed as early as possible in the input pipeline,
19/// to ensure that all later stages have the modifiers and lock states available.
20/// This holds even for non-keyboard handlers, to allow handling `Ctrl+Click`
21/// events, for example.
22///
23/// One possible exception to this rule would be a hardware key rewriting handler for
24/// limited keyboards.
25#[derive(Debug)]
26pub struct ModifierHandler {
27    /// The tracked state of the modifiers.
28    modifier_state: RefCell<ModifierState>,
29
30    /// The tracked lock state.
31    lock_state: RefCell<LockStateKeys>,
32
33    /// The inventory of this handler's Inspect status.
34    pub inspect_status: InputHandlerStatus,
35}
36
37impl Handler for ModifierHandler {
38    fn set_handler_healthy(self: std::rc::Rc<Self>) {
39        self.inspect_status.health_node.borrow_mut().set_ok();
40    }
41
42    fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
43        self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
44    }
45
46    fn get_name(&self) -> &'static str {
47        "ModifierHandler"
48    }
49
50    fn interest(&self) -> Vec<InputEventType> {
51        vec![InputEventType::Keyboard]
52    }
53}
54
55#[async_trait(?Send)]
56impl UnhandledInputHandler for ModifierHandler {
57    async fn handle_unhandled_input_event(
58        self: Rc<Self>,
59        unhandled_input_event: UnhandledInputEvent,
60    ) -> Vec<InputEvent> {
61        fuchsia_trace::duration!("input", "modifier_handler");
62        match unhandled_input_event {
63            UnhandledInputEvent {
64                device_event: InputDeviceEvent::Keyboard(mut event),
65                device_descriptor,
66                event_time,
67                trace_id,
68            } => {
69                fuchsia_trace::duration!("input", "modifier_handler[processing]");
70                if let Some(trace_id) = trace_id {
71                    fuchsia_trace::flow_step!(
72                        c"input",
73                        c"event_in_input_pipeline",
74                        trace_id.into()
75                    );
76                }
77
78                self.inspect_status.count_received_event(&event_time);
79                self.modifier_state.borrow_mut().update(event.get_event_type(), event.get_key());
80                self.lock_state.borrow_mut().update(event.get_event_type(), event.get_key());
81                event = event
82                    .into_with_lock_state(Some(self.lock_state.borrow().get_state()))
83                    .into_with_modifiers(Some(self.modifier_state.borrow().get_state()));
84                log::debug!("modifiers and lock state applied: {:?}", &event);
85                vec![InputEvent {
86                    device_event: InputDeviceEvent::Keyboard(event),
87                    device_descriptor,
88                    event_time,
89                    handled: Handled::No,
90                    trace_id,
91                }]
92            }
93            // Pass other events through.
94            _ => {
95                // TODO: b/478249522 - add cobalt logging
96                log::warn!("Unhandled input event: {:?}", unhandled_input_event.get_event_type());
97                vec![InputEvent::from(unhandled_input_event)]
98            }
99        }
100    }
101}
102
103impl ModifierHandler {
104    /// Creates a new [ModifierHandler].
105    pub fn new(input_handlers_node: &fuchsia_inspect::Node) -> Rc<Self> {
106        let inspect_status = InputHandlerStatus::new(
107            input_handlers_node,
108            "modifier_handler",
109            /* generates_events */ false,
110        );
111        Rc::new(Self {
112            modifier_state: RefCell::new(ModifierState::new()),
113            lock_state: RefCell::new(LockStateKeys::new()),
114            inspect_status,
115        })
116    }
117}
118
119/// Tracks the state of the modifiers that are tied to the key meaning (as opposed to hardware
120/// keys).
121#[derive(Debug)]
122pub struct ModifierMeaningHandler {
123    /// The tracked state of the modifiers.
124    modifier_state: RefCell<ModifierState>,
125
126    /// The inventory of this handler's Inspect status.
127    pub inspect_status: InputHandlerStatus,
128}
129
130impl ModifierMeaningHandler {
131    /// Creates a new [ModifierMeaningHandler].
132    pub fn new(input_handlers_node: &fuchsia_inspect::Node) -> Rc<Self> {
133        let inspect_status = InputHandlerStatus::new(
134            input_handlers_node,
135            "modifier_meaning_handler",
136            /* generates_events */ false,
137        );
138        Rc::new(Self { modifier_state: RefCell::new(ModifierState::new()), inspect_status })
139    }
140}
141
142impl Handler for ModifierMeaningHandler {
143    fn set_handler_healthy(self: std::rc::Rc<Self>) {
144        self.inspect_status.health_node.borrow_mut().set_ok();
145    }
146
147    fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
148        self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
149    }
150
151    fn get_name(&self) -> &'static str {
152        "ModifierHandler"
153    }
154
155    fn interest(&self) -> Vec<InputEventType> {
156        vec![InputEventType::Keyboard]
157    }
158}
159
160#[async_trait(?Send)]
161impl UnhandledInputHandler for ModifierMeaningHandler {
162    async fn handle_unhandled_input_event(
163        self: Rc<Self>,
164        unhandled_input_event: UnhandledInputEvent,
165    ) -> Vec<InputEvent> {
166        fuchsia_trace::duration!("input", "modifier_meaning_handler");
167        match unhandled_input_event {
168            UnhandledInputEvent {
169                device_event: InputDeviceEvent::Keyboard(mut event),
170                device_descriptor,
171                event_time,
172                trace_id,
173            } if event.get_key_meaning()
174                == Some(KeyMeaning::NonPrintableKey(NonPrintableKey::AltGraph)) =>
175            {
176                fuchsia_trace::duration!("input", "modifier_meaning_handler[processing]");
177                if let Some(trace_id) = trace_id {
178                    fuchsia_trace::flow_step!(
179                        c"input",
180                        c"event_in_input_pipeline",
181                        trace_id.into()
182                    );
183                }
184                self.inspect_status.count_received_event(&event_time);
185                // The "obvious" rewrite of this if and the match guard above is
186                // unstable, so doing it this way.
187                if let Some(key_meaning) = event.get_key_meaning() {
188                    self.modifier_state
189                        .borrow_mut()
190                        .update_with_key_meaning(event.get_event_type(), key_meaning);
191                    let new_modifier = event.get_modifiers().unwrap_or(Modifiers::empty())
192                        | self.modifier_state.borrow().get_state();
193                    event = event.into_with_modifiers(Some(new_modifier));
194                    log::debug!("additinal modifiers and lock state applied: {:?}", &event);
195                }
196                vec![InputEvent {
197                    device_event: InputDeviceEvent::Keyboard(event),
198                    device_descriptor,
199                    event_time,
200                    handled: Handled::No,
201                    trace_id,
202                }]
203            }
204            // Pass other events through.
205            _ => {
206                // TODO: b/478249522 - add cobalt logging
207                log::warn!("Unhandled input event: {:?}", unhandled_input_event.get_event_type());
208                vec![InputEvent::from(unhandled_input_event)]
209            }
210        }
211    }
212}
213
214#[cfg(test)]
215mod tests {
216    use super::*;
217    use crate::input_device::InputDeviceDescriptor;
218    use crate::input_handler::InputHandler;
219    use crate::keyboard_binding::{self, KeyboardEvent};
220    use crate::testing_utilities;
221    use fidl_fuchsia_input::Key;
222    use fidl_fuchsia_ui_input3::{KeyEventType, LockState};
223    use fuchsia_async as fasync;
224    use pretty_assertions::assert_eq;
225
226    fn get_unhandled_input_event(event: KeyboardEvent) -> UnhandledInputEvent {
227        UnhandledInputEvent {
228            device_event: InputDeviceEvent::Keyboard(event),
229            event_time: zx::MonotonicInstant::from_nanos(42),
230            device_descriptor: InputDeviceDescriptor::Fake,
231            trace_id: None,
232        }
233    }
234
235    #[fasync::run_singlethreaded(test)]
236    async fn test_decoration() {
237        let inspector = fuchsia_inspect::Inspector::default();
238        let test_node = inspector.root().create_child("test_node");
239        let handler = ModifierHandler::new(&test_node);
240        let input_event =
241            get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed));
242        let result = handler.handle_unhandled_input_event(input_event.clone()).await;
243
244        // This handler decorates, but does not handle the key. Hence,
245        // the key remains unhandled.
246        let expected = InputEvent::from(get_unhandled_input_event(
247            KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)
248                .into_with_modifiers(Some(Modifiers::CAPS_LOCK))
249                .into_with_lock_state(Some(LockState::CAPS_LOCK)),
250        ));
251        assert_eq!(vec![expected], result);
252    }
253
254    #[fasync::run_singlethreaded(test)]
255    async fn test_key_meaning_decoration() {
256        let inspector = fuchsia_inspect::Inspector::default();
257        let test_node = inspector.root().create_child("test_node");
258        let handler = ModifierMeaningHandler::new(&test_node);
259        {
260            let input_event = get_unhandled_input_event(
261                KeyboardEvent::new(Key::RightAlt, KeyEventType::Pressed)
262                    .into_with_key_meaning(Some(KeyMeaning::NonPrintableKey(
263                        NonPrintableKey::AltGraph,
264                    )))
265                    .into_with_modifiers(Some(Modifiers::CAPS_LOCK)),
266            );
267            let result = handler.clone().handle_unhandled_input_event(input_event.clone()).await;
268            let expected = InputEvent::from(get_unhandled_input_event(
269                KeyboardEvent::new(Key::RightAlt, KeyEventType::Pressed)
270                    .into_with_key_meaning(Some(KeyMeaning::NonPrintableKey(
271                        NonPrintableKey::AltGraph,
272                    )))
273                    .into_with_modifiers(Some(Modifiers::ALT_GRAPH | Modifiers::CAPS_LOCK)),
274            ));
275            assert_eq!(vec![expected], result);
276        }
277        {
278            let input_event = get_unhandled_input_event(
279                KeyboardEvent::new(Key::RightAlt, KeyEventType::Released)
280                    .into_with_key_meaning(Some(KeyMeaning::NonPrintableKey(
281                        NonPrintableKey::AltGraph,
282                    )))
283                    .into_with_modifiers(Some(Modifiers::CAPS_LOCK)),
284            );
285            let handler = handler.clone();
286            let result = handler.handle_unhandled_input_event(input_event.clone()).await;
287            let expected = InputEvent::from(get_unhandled_input_event(
288                KeyboardEvent::new(Key::RightAlt, KeyEventType::Released)
289                    .into_with_key_meaning(Some(KeyMeaning::NonPrintableKey(
290                        NonPrintableKey::AltGraph,
291                    )))
292                    .into_with_modifiers(Some(Modifiers::CAPS_LOCK)),
293            ));
294            assert_eq!(vec![expected], result);
295        }
296    }
297
298    // CapsLock  """"""\______/""""""""""\_______/"""
299    // Modifiers ------CCCCCCCC----------CCCCCCCCC---
300    // LockState ------CCCCCCCCCCCCCCCCCCCCCCCCCCC---
301    //
302    // C == CapsLock
303    #[fasync::run_singlethreaded(test)]
304    async fn test_modifier_press_lock_release() {
305        let input_events = vec![
306            get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)),
307            get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Released)),
308            get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)),
309            get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Released)),
310        ];
311
312        let inspector = fuchsia_inspect::Inspector::default();
313        let test_node = inspector.root().create_child("test_node");
314        let handler = ModifierHandler::new(&test_node);
315        let clone_handler = move || handler.clone();
316        let result = futures::future::join_all(
317            input_events
318                .into_iter()
319                .map(|e| async { clone_handler().handle_unhandled_input_event(e).await }),
320        )
321        .await
322        .into_iter()
323        .flatten()
324        .collect::<Vec<InputEvent>>();
325
326        let expected = IntoIterator::into_iter([
327            get_unhandled_input_event(
328                KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)
329                    .into_with_modifiers(Some(Modifiers::CAPS_LOCK))
330                    .into_with_lock_state(Some(LockState::CAPS_LOCK)),
331            ),
332            get_unhandled_input_event(
333                KeyboardEvent::new(Key::CapsLock, KeyEventType::Released)
334                    .into_with_modifiers(Some(Modifiers::from_bits_allow_unknown(0)))
335                    .into_with_lock_state(Some(LockState::CAPS_LOCK)),
336            ),
337            get_unhandled_input_event(
338                KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)
339                    .into_with_modifiers(Some(Modifiers::CAPS_LOCK))
340                    .into_with_lock_state(Some(LockState::CAPS_LOCK)),
341            ),
342            get_unhandled_input_event(
343                KeyboardEvent::new(Key::CapsLock, KeyEventType::Released)
344                    .into_with_modifiers(Some(Modifiers::from_bits_allow_unknown(0)))
345                    .into_with_lock_state(Some(LockState::from_bits_allow_unknown(0))),
346            ),
347        ])
348        .map(InputEvent::from)
349        .collect::<Vec<_>>();
350
351        assert_eq!(expected, result);
352    }
353
354    // CapsLock  """"""\______/"""""""""""""""""""
355    // A         """""""""""""""""""\________/""""
356    // Modifiers ------CCCCCCCC-------------------
357    // LockState ------CCCCCCCCCCCCCCCCCCCCCCCCCCC
358    //
359    // C == CapsLock
360    #[fasync::run_singlethreaded(test)]
361    async fn repeated_modifier_key() {
362        let input_events = vec![
363            get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)),
364            get_unhandled_input_event(KeyboardEvent::new(Key::CapsLock, KeyEventType::Released)),
365            get_unhandled_input_event(KeyboardEvent::new(Key::A, KeyEventType::Pressed)),
366            get_unhandled_input_event(KeyboardEvent::new(Key::A, KeyEventType::Released)),
367        ];
368
369        let inspector = fuchsia_inspect::Inspector::default();
370        let test_node = inspector.root().create_child("test_node");
371        let handler = ModifierHandler::new(&test_node);
372        let clone_handler = move || handler.clone();
373        let result = futures::future::join_all(
374            input_events
375                .into_iter()
376                .map(|e| async { clone_handler().handle_unhandled_input_event(e).await }),
377        )
378        .await
379        .into_iter()
380        .flatten()
381        .collect::<Vec<InputEvent>>();
382
383        let expected = IntoIterator::into_iter([
384            get_unhandled_input_event(
385                KeyboardEvent::new(Key::CapsLock, KeyEventType::Pressed)
386                    .into_with_modifiers(Some(Modifiers::CAPS_LOCK))
387                    .into_with_lock_state(Some(LockState::CAPS_LOCK)),
388            ),
389            get_unhandled_input_event(
390                KeyboardEvent::new(Key::CapsLock, KeyEventType::Released)
391                    .into_with_modifiers(Some(Modifiers::from_bits_allow_unknown(0)))
392                    .into_with_lock_state(Some(LockState::CAPS_LOCK)),
393            ),
394            get_unhandled_input_event(
395                KeyboardEvent::new(Key::A, KeyEventType::Pressed)
396                    .into_with_modifiers(Some(Modifiers::from_bits_allow_unknown(0)))
397                    .into_with_lock_state(Some(LockState::CAPS_LOCK)),
398            ),
399            get_unhandled_input_event(
400                KeyboardEvent::new(Key::A, KeyEventType::Released)
401                    .into_with_modifiers(Some(Modifiers::from_bits_allow_unknown(0)))
402                    .into_with_lock_state(Some(LockState::CAPS_LOCK)),
403            ),
404        ])
405        .map(InputEvent::from)
406        .collect::<Vec<_>>();
407        assert_eq!(expected, result);
408    }
409
410    #[fuchsia::test]
411    async fn modifier_handlers_initialized_with_inspect_node() {
412        let inspector = fuchsia_inspect::Inspector::default();
413        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
414        let _modifier_handler = ModifierHandler::new(&fake_handlers_node);
415        let _modifier_meaning_handler = ModifierMeaningHandler::new(&fake_handlers_node);
416        diagnostics_assertions::assert_data_tree!(inspector, root: {
417            input_handlers_node: {
418                modifier_handler: {
419                    events_received_count: 0u64,
420                    events_handled_count: 0u64,
421                    last_received_timestamp_ns: 0u64,
422                    "fuchsia.inspect.Health": {
423                        status: "STARTING_UP",
424                        // Timestamp value is unpredictable and not relevant in this context,
425                        // so we only assert that the property is present.
426                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
427                    },
428                },
429                modifier_meaning_handler: {
430                    events_received_count: 0u64,
431                    events_handled_count: 0u64,
432                    last_received_timestamp_ns: 0u64,
433                    "fuchsia.inspect.Health": {
434                        status: "STARTING_UP",
435                        // Timestamp value is unpredictable and not relevant in this context,
436                        // so we only assert that the property is present.
437                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
438                    },
439                }
440            }
441        });
442    }
443
444    #[fasync::run_singlethreaded(test)]
445    async fn modifier_handler_inspect_counts_events() {
446        let inspector = fuchsia_inspect::Inspector::default();
447        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
448        let modifier_handler = ModifierHandler::new(&fake_handlers_node);
449        let modifier_meaning_handler = ModifierMeaningHandler::new(&fake_handlers_node);
450        let device_descriptor =
451            InputDeviceDescriptor::Keyboard(keyboard_binding::KeyboardDeviceDescriptor {
452                keys: vec![Key::A, Key::B, Key::RightAlt],
453                ..Default::default()
454            });
455        let (_, event_time_u64) = testing_utilities::event_times();
456        let input_events = vec![
457            testing_utilities::create_keyboard_event_with_time(
458                Key::A,
459                fidl_fuchsia_ui_input3::KeyEventType::Pressed,
460                None,
461                event_time_u64,
462                &device_descriptor,
463                /* keymap= */ None,
464            ),
465            // Should not count received events that have already been handled.
466            testing_utilities::create_keyboard_event_with_handled(
467                Key::B,
468                fidl_fuchsia_ui_input3::KeyEventType::Pressed,
469                None,
470                event_time_u64,
471                &device_descriptor,
472                /* keymap= */ None,
473                /* key_meaning= */ None,
474                Handled::Yes,
475            ),
476            testing_utilities::create_keyboard_event_with_time(
477                Key::A,
478                fidl_fuchsia_ui_input3::KeyEventType::Released,
479                None,
480                event_time_u64,
481                &device_descriptor,
482                /* keymap= */ None,
483            ),
484            // Should not count non-keyboard input events.
485            testing_utilities::create_fake_input_event(event_time_u64),
486            // Only event that should be counted by ModifierMeaningHandler.
487            testing_utilities::create_keyboard_event_with_key_meaning(
488                Key::RightAlt,
489                fidl_fuchsia_ui_input3::KeyEventType::Pressed,
490                None,
491                event_time_u64,
492                &device_descriptor,
493                /* keymap= */ None,
494                /* key_meaning= */
495                Some(KeyMeaning::NonPrintableKey(NonPrintableKey::AltGraph)),
496            ),
497        ];
498
499        for input_event in input_events {
500            let _ = modifier_handler.clone().handle_input_event(input_event.clone()).await;
501            let _ = modifier_meaning_handler.clone().handle_input_event(input_event).await;
502        }
503
504        let last_event_timestamp: u64 = event_time_u64.into_nanos().try_into().unwrap();
505
506        diagnostics_assertions::assert_data_tree!(inspector, root: {
507            input_handlers_node: {
508                modifier_handler: {
509                    events_received_count: 3u64,
510                    events_handled_count: 0u64,
511                    last_received_timestamp_ns: last_event_timestamp,
512                    "fuchsia.inspect.Health": {
513                        status: "STARTING_UP",
514                        // Timestamp value is unpredictable and not relevant in this context,
515                        // so we only assert that the property is present.
516                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
517                    },
518                },
519                modifier_meaning_handler: {
520                    events_received_count: 1u64,
521                    events_handled_count: 0u64,
522                    last_received_timestamp_ns: last_event_timestamp,
523                    "fuchsia.inspect.Health": {
524                        status: "STARTING_UP",
525                        // Timestamp value is unpredictable and not relevant in this context,
526                        // so we only assert that the property is present.
527                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
528                    },
529                }
530            }
531        });
532    }
533}