starnix_modules_input_event_conversion/
key_linux_to_fuchsia.rs1use crate::keymap::KEY_MAP;
6use fidl_fuchsia_input::Key;
7use fidl_fuchsia_input_report as fir;
8use starnix_logging::log_warn;
9use starnix_types::time::time_from_timeval;
10use starnix_uapi::errors::Errno;
11use starnix_uapi::{error, uapi};
12
13#[derive(Debug, PartialEq)]
22pub struct LinuxKeyboardEventParser {
23 cached_event: Option<uapi::input_event>,
24 pressing_keys: Vec<Key>,
25}
26
27impl LinuxKeyboardEventParser {
28 pub fn create() -> Self {
29 Self { cached_event: None, pressing_keys: vec![] }
30 }
31
32 fn reset_state(&mut self) {
33 self.cached_event = None;
34 self.pressing_keys = vec![];
35 }
36
37 fn produce_input_report(
38 &mut self,
39 e: uapi::input_event,
40 ) -> Result<Option<fir::InputReport>, Errno> {
41 self.cached_event = None;
42
43 let fkey = KEY_MAP.linux_keycode_to_fuchsia_input_key(e.code as u32);
44 if fkey == Key::Unknown {
47 self.reset_state();
48 return error!(EINVAL);
49 }
50 match e.value {
51 1 => {
53 if self.pressing_keys.contains(&fkey) {
54 log_warn!(
55 "keyboard receive a press key event while the key is already pressing, key = {:?}",
56 fkey
57 );
58 self.reset_state();
59 return error!(EINVAL);
60 }
61 self.pressing_keys.push(fkey);
62 }
63 0 => {
65 if !self.pressing_keys.contains(&fkey) {
66 log_warn!(
67 "keyboard receive a release key event while the key is not pressing, key = {:?}",
68 fkey
69 );
70 self.reset_state();
71 return error!(EINVAL);
72 }
73 self.pressing_keys =
75 self.pressing_keys.clone().into_iter().filter(|x| *x != fkey).collect();
76 }
77 _ => {
78 log_warn!("key event has invalid value field, event = {:?}", e);
79 self.reset_state();
80 return error!(EINVAL);
81 }
82 }
83
84 let keyboard_report = fir::KeyboardInputReport {
85 pressed_keys3: Some(self.pressing_keys.clone()),
86 ..Default::default()
87 };
88
89 Ok(Some(fir::InputReport {
90 event_time: Some(time_from_timeval::<zx::MonotonicTimeline>(e.time)?.into_nanos()),
91 keyboard: Some(keyboard_report),
92 ..Default::default()
93 }))
94 }
95
96 pub fn handle(&mut self, e: uapi::input_event) -> Result<Option<fir::InputReport>, Errno> {
97 match self.cached_event {
98 Some(key_event) => match e.type_ as u32 {
99 uapi::EV_SYN => self.produce_input_report(key_event),
100 _ => {
101 self.reset_state();
102 log_warn!("keyboard expect EV_SYN event but got = {:?}", e);
103 error!(EINVAL)
104 }
105 },
106 None => match e.type_ as u32 {
107 uapi::EV_KEY => {
108 self.cached_event = Some(e);
109 Ok(None)
110 }
111 _ => {
112 self.reset_state();
113 log_warn!("keyboard expect EV_KEY event but got = {:?}", e);
114 error!(EINVAL)
115 }
116 },
117 }
118 }
119}
120
121#[cfg(test)]
122mod key_linux_fuchsia_tests {
123 use super::*;
124 use assert_matches::assert_matches;
125 use pretty_assertions::assert_eq;
126 use test_case::test_case;
127 use uapi::timeval;
128
129 fn uapi_input_event(ty: u32, code: u32, value: i32) -> uapi::input_event {
130 uapi::input_event { time: timeval::default(), type_: ty as u16, code: code as u16, value }
131 }
132
133 #[test]
134 fn parse_linux_events_to_fidl_keyboard_event_send_syn_when_no_cached_event() {
135 let mut linux_keyboard_event_parser = LinuxKeyboardEventParser::create();
136 let e = uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0);
137 let res = linux_keyboard_event_parser.handle(e);
138 assert_eq!(res, error!(EINVAL));
139 }
140
141 #[test_case(
142 uapi_input_event(uapi::EV_KEY, uapi::KEY_A, 1);
143 "press")]
144 #[test_case(
145 uapi_input_event(uapi::EV_KEY, uapi::KEY_A, 0);
146 "release, not fail on this step")]
147 #[test_case(
148 uapi_input_event(uapi::EV_KEY, uapi::KEY_RESERVED, 1);
149 "unknown keycode, not fail on this step")]
150 fn parse_linux_events_to_fidl_keyboard_event_send_key_when_no_cached_event_and_no_pressing_keys(
151 e: uapi::input_event,
152 ) {
153 let mut linux_keyboard_event_parser = LinuxKeyboardEventParser::create();
154 let res = linux_keyboard_event_parser.handle(e);
155 assert_eq!(res, Ok(None));
156 assert_eq!(
157 linux_keyboard_event_parser,
158 LinuxKeyboardEventParser { cached_event: Some(e), pressing_keys: vec![] },
159 );
160 }
161
162 #[test]
163 fn parse_linux_events_to_fidl_keyboard_event_send_syn_when_have_cached_event_and_no_pressing_keys()
164 {
165 let mut linux_keyboard_event_parser = LinuxKeyboardEventParser::create();
166 let e = uapi_input_event(uapi::EV_KEY, uapi::KEY_A, 1);
167 let res = linux_keyboard_event_parser.handle(e);
168 assert_eq!(res, Ok(None));
169
170 let e = uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0);
171 let res = linux_keyboard_event_parser.handle(e);
172 assert_eq!(
173 res,
174 Ok(Some(fir::InputReport {
175 event_time: Some(0),
176 keyboard: Some(fir::KeyboardInputReport {
177 pressed_keys3: Some(vec![Key::A]),
178 ..Default::default()
179 }),
180 ..Default::default()
181 }))
182 );
183 assert_eq!(
184 linux_keyboard_event_parser,
185 LinuxKeyboardEventParser { cached_event: None, pressing_keys: vec![Key::A] },
186 );
187 }
188
189 #[test_case(
190 uapi_input_event(uapi::EV_KEY, uapi::KEY_A, 0);
191 "release not pressing")]
192 #[test_case(
193 uapi_input_event(uapi::EV_KEY, uapi::KEY_RESERVED, 1);
194 "unknown keycode")]
195 fn parse_linux_events_to_fidl_keyboard_event_send_syn_when_have_cached_event_and_no_pressing_keys_failed(
196 cached: uapi::input_event,
197 ) {
198 let mut linux_keyboard_event_parser = LinuxKeyboardEventParser::create();
199 let res = linux_keyboard_event_parser.handle(cached);
200 assert_eq!(res, Ok(None));
201
202 let e = uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0);
203 let res = linux_keyboard_event_parser.handle(e);
204 assert_eq!(res, error!(EINVAL));
205 assert_eq!(
206 linux_keyboard_event_parser,
207 LinuxKeyboardEventParser { cached_event: None, pressing_keys: vec![] },
208 );
209 }
210
211 #[test]
212 fn parse_linux_events_to_fidl_keyboard_event_send_key_when_have_cached_event() {
213 let mut linux_keyboard_event_parser = LinuxKeyboardEventParser::create();
214 let e = uapi_input_event(uapi::EV_KEY, uapi::KEY_A, 1);
215 let res = linux_keyboard_event_parser.handle(e);
216 assert_eq!(res, Ok(None));
217
218 let e = uapi_input_event(uapi::EV_KEY, uapi::KEY_B, 1);
219 let res = linux_keyboard_event_parser.handle(e);
220 assert_eq!(res, error!(EINVAL));
221 assert_eq!(
222 linux_keyboard_event_parser,
223 LinuxKeyboardEventParser { cached_event: None, pressing_keys: vec![] },
224 );
225 }
226
227 #[test]
228 fn parse_linux_events_to_fidl_keyboard_event_press_pressing_key() {
229 let mut linux_keyboard_event_parser = LinuxKeyboardEventParser::create();
230 let press_a = uapi_input_event(uapi::EV_KEY, uapi::KEY_A, 1);
231 let res = linux_keyboard_event_parser.handle(press_a);
232 assert_eq!(res, Ok(None));
233
234 let syn = uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0);
235 let res = linux_keyboard_event_parser.handle(syn);
236 assert_matches!(res, Ok(Some(_)));
237
238 let res = linux_keyboard_event_parser.handle(press_a);
239 assert_eq!(res, Ok(None));
240 let res = linux_keyboard_event_parser.handle(syn);
241 assert_eq!(res, error!(EINVAL));
242 assert_eq!(
243 linux_keyboard_event_parser,
244 LinuxKeyboardEventParser { cached_event: None, pressing_keys: vec![] },
245 );
246 }
247
248 #[test]
249 fn parse_linux_events_to_fidl_keyboard_event_release_key() {
250 let mut linux_keyboard_event_parser = LinuxKeyboardEventParser::create();
251 let press_a = uapi_input_event(uapi::EV_KEY, uapi::KEY_A, 1);
252 let res = linux_keyboard_event_parser.handle(press_a);
253 assert_eq!(res, Ok(None));
254
255 let syn = uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0);
256 let res = linux_keyboard_event_parser.handle(syn);
257 assert_matches!(res, Ok(Some(_)));
258
259 let release_a = uapi_input_event(uapi::EV_KEY, uapi::KEY_A, 0);
260 let res = linux_keyboard_event_parser.handle(release_a);
261 assert_eq!(res, Ok(None));
262 let res = linux_keyboard_event_parser.handle(syn);
263 assert_eq!(
264 res,
265 Ok(Some(fir::InputReport {
266 event_time: Some(0),
267 keyboard: Some(fir::KeyboardInputReport {
268 pressed_keys3: Some(vec![]),
269 ..Default::default()
270 }),
271 ..Default::default()
272 }))
273 );
274 assert_eq!(
275 linux_keyboard_event_parser,
276 LinuxKeyboardEventParser { cached_event: None, pressing_keys: vec![] },
277 );
278 }
279}