starnix_modules_input_report_event_conversion/
lib.rs1pub mod consumer_control;
6pub mod keyboard;
7pub mod mouse;
8pub mod touch;
9
10pub use consumer_control::*;
11pub use keyboard::*;
12pub use mouse::*;
13pub use touch::*;
14
15use fidl_fuchsia_input_report as fir;
16use starnix_uapi::uapi;
17
18#[inline]
19pub(crate) fn clamp_i64_to_i32(val: i64) -> i32 {
20 i32::try_from(val).unwrap_or_else(|_| val.clamp(i32::MIN as i64, i32::MAX as i64) as i32)
21}
22
23pub(crate) fn emit_key_transitions(
24 previous: &mut sorted_vec_map::SortedVecSet<u16>,
25 current: sorted_vec_map::SortedVecSet<u16>,
26 time: uapi::timeval,
27 events: &mut Vec<uapi::input_event>,
28) {
29 for &key in previous.iter() {
30 if !current.contains(&key) {
31 events.push(uapi::input_event {
32 time,
33 type_: uapi::EV_KEY as u16,
34 code: key,
35 value: 0,
36 });
37 }
38 }
39 for &key in current.iter() {
40 if !previous.contains(&key) {
41 events.push(uapi::input_event {
42 time,
43 type_: uapi::EV_KEY as u16,
44 code: key,
45 value: 1,
46 });
47 }
48 }
49 *previous = current;
50}
51
52#[derive(Debug, Default, PartialEq)]
54pub struct InputReportConverter {
55 pub touch: TouchReportConverter,
56 pub mouse: MouseReportConverter,
57 pub keyboard: KeyboardReportConverter,
58 pub consumer_control: ConsumerControlReportConverter,
59}
60
61impl InputReportConverter {
62 pub fn new() -> Self {
63 Self::default()
64 }
65
66 pub fn from_device_descriptor(descriptor: &fir::DeviceDescriptor) -> Self {
67 let touch = descriptor
68 .touch
69 .as_ref()
70 .map(TouchReportConverter::from_touch_descriptor)
71 .unwrap_or_default();
72 Self { touch, ..Default::default() }
73 }
74
75 pub fn handle_report(&mut self, report: &fir::InputReport) -> Vec<uapi::input_event> {
76 let event_time = report
77 .event_time
78 .filter(|&t| t > 0)
79 .map(zx::MonotonicInstant::from_nanos)
80 .unwrap_or_else(zx::MonotonicInstant::get);
81
82 let mut events = Vec::new();
83
84 if let Some(ref touch) = report.touch {
85 events.extend(self.touch.handle(touch, event_time));
86 }
87
88 if let Some(ref mouse) = report.mouse {
89 events.extend(self.mouse.handle(mouse, event_time));
90 }
91
92 if let Some(ref keyboard) = report.keyboard {
93 events.extend(self.keyboard.handle(keyboard, event_time));
94 }
95
96 if let Some(ref consumer_control) = report.consumer_control {
97 events.extend(self.consumer_control.handle(consumer_control, event_time));
98 }
99
100 events
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use fidl_fuchsia_input::Key;
108
109 #[::fuchsia::test]
110 fn test_unified_input_report_converter() {
111 let mut converter = InputReportConverter::new();
112 let time_nanos = 700_000_000;
113
114 let report = fir::InputReport {
115 event_time: Some(time_nanos),
116 keyboard: Some(fir::KeyboardInputReport {
117 pressed_keys3: Some(vec![Key::Escape]),
118 ..Default::default()
119 }),
120 mouse: Some(fir::MouseInputReport {
121 movement_x: Some(10),
122 movement_y: Some(-5),
123 ..Default::default()
124 }),
125 ..Default::default()
126 };
127
128 let events = converter.handle_report(&report);
129 assert!(events.iter().any(|e| e.code == uapi::KEY_ESC as u16 && e.value == 1));
130 assert!(events.iter().any(|e| e.code == uapi::REL_X as u16 && e.value == 10));
131 assert!(events.iter().any(|e| e.code == uapi::REL_Y as u16 && e.value == -5));
132 assert_eq!(events[0].time.tv_sec, 0);
133 assert_eq!(events[0].time.tv_usec, (time_nanos / 1_000) as i64);
134 }
135
136 #[::fuchsia::test]
137 fn test_empty_reports_return_empty_events() {
138 assert!(InputReportConverter::new().handle_report(&fir::InputReport::default()).is_empty());
139 }
140
141 #[::fuchsia::test]
142 fn test_event_time_filtering() {
143 let mut converter_zero = InputReportConverter::new();
145 let report_zero = fir::InputReport {
146 event_time: Some(0),
147 keyboard: Some(fir::KeyboardInputReport {
148 pressed_keys3: Some(vec![Key::Escape]),
149 ..Default::default()
150 }),
151 ..Default::default()
152 };
153 let events_zero = converter_zero.handle_report(&report_zero);
154 assert!(!events_zero.is_empty());
155 assert!(events_zero[0].time.tv_sec > 0 || events_zero[0].time.tv_usec > 0);
156
157 let mut converter_neg = InputReportConverter::new();
159 let report_neg = fir::InputReport {
160 event_time: Some(-100),
161 keyboard: Some(fir::KeyboardInputReport {
162 pressed_keys3: Some(vec![Key::Escape]),
163 ..Default::default()
164 }),
165 ..Default::default()
166 };
167 let events_neg = converter_neg.handle_report(&report_neg);
168 assert!(!events_neg.is_empty());
169 assert!(events_neg[0].time.tv_sec > 0 || events_neg[0].time.tv_usec > 0);
170 assert!(events_neg[0].time.tv_usec >= 0);
171 }
172
173 #[::fuchsia::test]
174 fn test_clamp_i64_to_i32() {
175 assert_eq!(clamp_i64_to_i32(0), 0);
176 assert_eq!(clamp_i64_to_i32(42), 42);
177 assert_eq!(clamp_i64_to_i32(-42), -42);
178 assert_eq!(clamp_i64_to_i32(i32::MAX as i64), i32::MAX);
179 assert_eq!(clamp_i64_to_i32(i32::MIN as i64), i32::MIN);
180 assert_eq!(clamp_i64_to_i32(i32::MAX as i64 + 100), i32::MAX);
181 assert_eq!(clamp_i64_to_i32(i32::MIN as i64 - 100), i32::MIN);
182 assert_eq!(clamp_i64_to_i32(i64::MAX), i32::MAX);
183 assert_eq!(clamp_i64_to_i32(i64::MIN), i32::MIN);
184 }
185
186 #[::fuchsia::test]
187 fn test_input_report_converter_from_device_descriptor() {
188 let desc = fir::DeviceDescriptor {
189 touch: Some(fir::TouchDescriptor {
190 input: Some(fir::TouchInputDescriptor {
191 max_contacts: Some(7),
192 ..Default::default()
193 }),
194 ..Default::default()
195 }),
196 ..Default::default()
197 };
198 let converter = InputReportConverter::from_device_descriptor(&desc);
199 assert_eq!(converter.touch.max_slots(), 7);
200
201 let desc_empty = fir::DeviceDescriptor::default();
202 let converter_empty = InputReportConverter::from_device_descriptor(&desc_empty);
203 assert_eq!(converter_empty.touch.max_slots(), 10);
204 }
205}