Skip to main content

starnix_modules_input_event_conversion/
key_linux_to_fuchsia.rs

1// Copyright 2025 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::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/// A state machine accepts uapi::input_event, produces fir::InputReport
14/// when (Key Event + Sync Event) received. It also maintain the currently
15/// pressing key list.
16///
17/// Warning output, clean state and return errno when received events:
18/// - unknown keycode.
19/// - invalid event.
20/// - not follow (Key Event + Sync Event) pattern.
21#[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        // produce no input report for unknown key, there is a warning log from
45        // linux_keycode_to_fuchsia_input_key().
46        if fkey == Key::Unknown {
47            self.reset_state();
48            return error!(EINVAL);
49        }
50        match e.value {
51            // Press
52            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            // Release
64            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                // remove the released key.
74                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}