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