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