1use crate::input_handler::{InputHandlerStatus, UnhandledInputHandler};
10use crate::{input_device, keyboard_binding};
11use async_trait::async_trait;
12use fuchsia_inspect::health::Reporter;
13
14use std::cell::RefCell;
15use std::rc::Rc;
16
17#[derive(Debug, Default)]
23pub struct KeymapHandler {
24 modifier_state: RefCell<keymaps::ModifierState>,
26
27 lock_state: RefCell<keymaps::LockStateKeys>,
29
30 pub inspect_status: InputHandlerStatus,
32}
33
34#[async_trait(?Send)]
37impl UnhandledInputHandler for KeymapHandler {
38 async fn handle_unhandled_input_event(
39 self: Rc<Self>,
40 input_event: input_device::UnhandledInputEvent,
41 ) -> Vec<input_device::InputEvent> {
42 match input_event.clone() {
43 input_device::UnhandledInputEvent {
45 device_event: input_device::InputDeviceEvent::Keyboard(event),
46 device_descriptor,
47 event_time,
48 trace_id,
49 } => {
50 self.inspect_status
51 .count_received_event(input_device::InputEvent::from(input_event));
52 vec![input_device::InputEvent::from(self.process_keyboard_event(
53 event,
54 device_descriptor,
55 event_time,
56 trace_id,
57 ))]
58 }
59 _ => vec![input_device::InputEvent::from(input_event)],
61 }
62 }
63
64 fn set_handler_healthy(self: std::rc::Rc<Self>) {
65 self.inspect_status.health_node.borrow_mut().set_ok();
66 }
67
68 fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
69 self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
70 }
71}
72
73impl KeymapHandler {
74 pub fn new(input_handlers_node: &fuchsia_inspect::Node) -> Rc<Self> {
76 let inspect_status = InputHandlerStatus::new(
77 input_handlers_node,
78 "keymap_handler",
79 false,
80 );
81 Rc::new(Self {
82 modifier_state: Default::default(),
83 lock_state: Default::default(),
84 inspect_status,
85 })
86 }
87
88 fn process_keyboard_event(
90 self: &Rc<Self>,
91 event: keyboard_binding::KeyboardEvent,
92 device_descriptor: input_device::InputDeviceDescriptor,
93 event_time: zx::MonotonicInstant,
94 trace_id: Option<fuchsia_trace::Id>,
95 ) -> input_device::UnhandledInputEvent {
96 fuchsia_trace::duration!(c"input", c"keymap_handler");
97 if let Some(trace_id) = trace_id {
98 fuchsia_trace::flow_step!(c"input", c"event_in_input_pipeline", trace_id.into());
99 }
100
101 let (key, event_type) = (event.get_key(), event.get_event_type());
102 log::debug!(
103 concat!(
104 "Keymap::process_keyboard_event: key:{:?}, ",
105 "modifier_state:{:?}, lock_state: {:?}, event_type: {:?}"
106 ),
107 key,
108 self.modifier_state.borrow(),
109 self.lock_state.borrow(),
110 event_type
111 );
112
113 self.modifier_state.borrow_mut().update(event_type, key);
114 self.lock_state.borrow_mut().update(event_type, key);
115 let key_meaning = keymaps::select_keymap(&event.get_keymap()).apply(
116 key,
117 &*self.modifier_state.borrow(),
118 &*self.lock_state.borrow(),
119 );
120 input_device::UnhandledInputEvent {
121 device_event: input_device::InputDeviceEvent::Keyboard(
122 event.into_with_key_meaning(key_meaning),
123 ),
124 device_descriptor,
125 event_time,
126 trace_id,
127 }
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use crate::input_handler::InputHandler;
135 use crate::{consumer_controls_binding, testing_utilities};
136 use pretty_assertions::assert_eq;
137 use std::convert::TryFrom as _;
138 use {
139 fidl_fuchsia_input as finput, fidl_fuchsia_ui_input3 as finput3, fuchsia_async as fasync,
140 zx,
141 };
142
143 fn create_unhandled_keyboard_event(
145 key: finput::Key,
146 event_type: finput3::KeyEventType,
147 keymap: Option<String>,
148 ) -> input_device::UnhandledInputEvent {
149 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
150 keyboard_binding::KeyboardDeviceDescriptor {
151 keys: vec![finput::Key::A, finput::Key::B],
152 ..Default::default()
153 },
154 );
155 let (_, event_time_u64) = testing_utilities::event_times();
156 input_device::UnhandledInputEvent::try_from(
157 testing_utilities::create_keyboard_event_with_time(
158 key,
159 event_type,
160 None,
161 event_time_u64,
162 &device_descriptor,
163 keymap,
164 ),
165 )
166 .unwrap()
167 }
168
169 fn create_unhandled_consumer_controls_event(
171 pressed_buttons: Vec<fidl_fuchsia_input_report::ConsumerControlButton>,
172 event_time: zx::MonotonicInstant,
173 device_descriptor: &input_device::InputDeviceDescriptor,
174 ) -> input_device::UnhandledInputEvent {
175 input_device::UnhandledInputEvent::try_from(
176 testing_utilities::create_consumer_controls_event(
177 pressed_buttons,
178 event_time,
179 device_descriptor,
180 ),
181 )
182 .unwrap()
183 }
184
185 fn get_key_meaning(event: &input_device::InputEvent) -> Option<finput3::KeyMeaning> {
186 match event {
187 input_device::InputEvent {
188 device_event: input_device::InputDeviceEvent::Keyboard(event),
189 ..
190 } => event.get_key_meaning(),
191 _ => None,
192 }
193 }
194
195 #[fasync::run_singlethreaded(test)]
196 async fn test_keymap_application() {
197 #[derive(Debug)]
200 struct TestCase {
201 events: Vec<input_device::UnhandledInputEvent>,
202 expected: Vec<Option<finput3::KeyMeaning>>,
203 }
204 let tests: Vec<TestCase> = vec![
205 TestCase {
206 events: vec![create_unhandled_keyboard_event(
207 finput::Key::A,
208 finput3::KeyEventType::Pressed,
209 Some("US_QWERTY".into()),
210 )],
211 expected: vec![
212 Some(finput3::KeyMeaning::Codepoint(97)), ],
214 },
215 TestCase {
216 events: vec![create_unhandled_consumer_controls_event(
218 vec![],
219 zx::MonotonicInstant::ZERO,
220 &input_device::InputDeviceDescriptor::ConsumerControls(
221 consumer_controls_binding::ConsumerControlsDeviceDescriptor {
222 buttons: vec![],
223 device_id: 0,
224 },
225 ),
226 )],
227 expected: vec![None],
228 },
229 TestCase {
230 events: vec![
231 create_unhandled_keyboard_event(
232 finput::Key::LeftShift,
233 finput3::KeyEventType::Pressed,
234 Some("US_QWERTY".into()),
235 ),
236 create_unhandled_keyboard_event(
237 finput::Key::A,
238 finput3::KeyEventType::Pressed,
239 Some("US_QWERTY".into()),
240 ),
241 ],
242 expected: vec![
243 Some(finput3::KeyMeaning::NonPrintableKey(finput3::NonPrintableKey::Shift)),
244 Some(finput3::KeyMeaning::Codepoint(65)), ],
246 },
247 TestCase {
248 events: vec![
249 create_unhandled_keyboard_event(
250 finput::Key::Tab,
251 finput3::KeyEventType::Pressed,
252 Some("US_QWERTY".into()),
253 ),
254 create_unhandled_keyboard_event(
255 finput::Key::A,
256 finput3::KeyEventType::Pressed,
257 Some("US_QWERTY".into()),
258 ),
259 ],
260 expected: vec![
261 Some(finput3::KeyMeaning::NonPrintableKey(finput3::NonPrintableKey::Tab)),
262 Some(finput3::KeyMeaning::Codepoint(97)), ],
264 },
265 ];
266 let inspector = fuchsia_inspect::Inspector::default();
267 let test_node = inspector.root().create_child("test_node");
268 for test in &tests {
269 let mut actual: Vec<Option<finput3::KeyMeaning>> = vec![];
270 let handler = KeymapHandler::new(&test_node);
271 for event in &test.events {
272 let mut result = handler
273 .clone()
274 .handle_unhandled_input_event(event.clone())
275 .await
276 .iter()
277 .map(get_key_meaning)
278 .collect();
279 actual.append(&mut result);
280 }
281 assert_eq!(test.expected, actual);
282 }
283 }
284
285 #[fuchsia::test]
286 fn keymap_handler_initialized_with_inspect_node() {
287 let inspector = fuchsia_inspect::Inspector::default();
288 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
289 let _handler = KeymapHandler::new(&fake_handlers_node);
290 diagnostics_assertions::assert_data_tree!(inspector, root: {
291 input_handlers_node: {
292 keymap_handler: {
293 events_received_count: 0u64,
294 events_handled_count: 0u64,
295 last_received_timestamp_ns: 0u64,
296 "fuchsia.inspect.Health": {
297 status: "STARTING_UP",
298 start_timestamp_nanos: diagnostics_assertions::AnyProperty
301 },
302 }
303 }
304 });
305 }
306
307 #[fasync::run_singlethreaded(test)]
308 async fn keymap_handler_inspect_counts_events() {
309 let inspector = fuchsia_inspect::Inspector::default();
310 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
311 let keymap_handler = KeymapHandler::new(&fake_handlers_node);
312 let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
313 keyboard_binding::KeyboardDeviceDescriptor {
314 keys: vec![finput::Key::A, finput::Key::B],
315 ..Default::default()
316 },
317 );
318 let (_, event_time_u64) = testing_utilities::event_times();
319 let input_events = vec![
320 testing_utilities::create_keyboard_event_with_time(
321 finput::Key::A,
322 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
323 None,
324 event_time_u64,
325 &device_descriptor,
326 None,
327 ),
328 testing_utilities::create_keyboard_event_with_handled(
330 finput::Key::B,
331 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
332 None,
333 event_time_u64,
334 &device_descriptor,
335 None,
336 None,
337 input_device::Handled::Yes,
338 ),
339 testing_utilities::create_keyboard_event_with_time(
340 finput::Key::A,
341 fidl_fuchsia_ui_input3::KeyEventType::Released,
342 None,
343 event_time_u64,
344 &device_descriptor,
345 None,
346 ),
347 testing_utilities::create_fake_input_event(event_time_u64),
349 testing_utilities::create_keyboard_event_with_time(
350 finput::Key::B,
351 fidl_fuchsia_ui_input3::KeyEventType::Pressed,
352 None,
353 event_time_u64,
354 &device_descriptor,
355 None,
356 ),
357 ];
358
359 for input_event in input_events {
360 let _ = keymap_handler.clone().handle_input_event(input_event).await;
361 }
362
363 let last_event_timestamp: u64 = event_time_u64.into_nanos().try_into().unwrap();
364
365 diagnostics_assertions::assert_data_tree!(inspector, root: {
366 input_handlers_node: {
367 keymap_handler: {
368 events_received_count: 3u64,
369 events_handled_count: 0u64,
370 last_received_timestamp_ns: last_event_timestamp,
371 "fuchsia.inspect.Health": {
372 status: "STARTING_UP",
373 start_timestamp_nanos: diagnostics_assertions::AnyProperty
376 },
377 }
378 }
379 });
380 }
381}