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