1#[derive(Debug, Clone, Copy)]
6pub enum InputEvent {
7 PointerMove {
9 x: f32,
11 y: f32,
13 buttons: u8,
15 timestamp_ms: u32,
17 },
18
19 PointerDown { button: u8, x: f32, y: f32 },
21
22 PointerUp { button: u8, x: f32, y: f32 },
24
25 Scroll {
27 delta_x: f32,
28 delta_y: f32,
29 mode: ScrollMode,
30 },
31
32 KeyDown { code: u16 },
34
35 KeyUp { code: u16 },
37}
38
39#[derive(Debug, Clone, Copy)]
40pub enum ScrollMode {
41 Pixels = 0,
42 Lines = 1,
43 Pages = 2,
44}
45
46const TAG_POINTER_MOVE: u8 = 0x01;
48const TAG_POINTER_DOWN: u8 = 0x02;
49const TAG_POINTER_UP: u8 = 0x03;
50const TAG_SCROLL: u8 = 0x04;
51const TAG_KEY_DOWN: u8 = 0x10;
52const TAG_KEY_UP: u8 = 0x11;
53
54impl InputEvent {
55 pub fn to_bytes(&self) -> Vec<u8> {
57 match self {
58 InputEvent::PointerMove {
59 x,
60 y,
61 buttons,
62 timestamp_ms,
63 } => {
64 let mut buf = Vec::with_capacity(14);
65 buf.push(TAG_POINTER_MOVE);
66 buf.push(*buttons);
67 buf.extend_from_slice(&x.to_le_bytes());
68 buf.extend_from_slice(&y.to_le_bytes());
69 buf.extend_from_slice(×tamp_ms.to_le_bytes());
70 buf
71 }
72 InputEvent::PointerDown { button, x, y } => {
73 let mut buf = Vec::with_capacity(10);
74 buf.push(TAG_POINTER_DOWN);
75 buf.push(*button);
76 buf.extend_from_slice(&x.to_le_bytes());
77 buf.extend_from_slice(&y.to_le_bytes());
78 buf
79 }
80 InputEvent::PointerUp { button, x, y } => {
81 let mut buf = Vec::with_capacity(10);
82 buf.push(TAG_POINTER_UP);
83 buf.push(*button);
84 buf.extend_from_slice(&x.to_le_bytes());
85 buf.extend_from_slice(&y.to_le_bytes());
86 buf
87 }
88 InputEvent::Scroll {
89 delta_x,
90 delta_y,
91 mode,
92 } => {
93 let mut buf = Vec::with_capacity(10);
94 buf.push(TAG_SCROLL);
95 buf.extend_from_slice(&delta_x.to_le_bytes());
96 buf.extend_from_slice(&delta_y.to_le_bytes());
97 buf.push(*mode as u8);
98 buf
99 }
100 InputEvent::KeyDown { code } => {
101 vec![TAG_KEY_DOWN, (*code >> 8) as u8, *code as u8]
102 }
103 InputEvent::KeyUp { code } => {
104 vec![TAG_KEY_UP, (*code >> 8) as u8, *code as u8]
105 }
106 }
107 }
108
109 pub fn from_bytes(data: &[u8]) -> Result<Self, InputEventError> {
111 if data.is_empty() {
112 return Err(InputEventError::Empty);
113 }
114
115 match data[0] {
116 TAG_POINTER_MOVE if data.len() >= 14 => Ok(InputEvent::PointerMove {
117 buttons: data[1],
118 x: f32::from_le_bytes(data[2..6].try_into().unwrap()),
119 y: f32::from_le_bytes(data[6..10].try_into().unwrap()),
120 timestamp_ms: u32::from_le_bytes(data[10..14].try_into().unwrap()),
121 }),
122 TAG_POINTER_DOWN if data.len() >= 10 => Ok(InputEvent::PointerDown {
123 button: data[1],
124 x: f32::from_le_bytes(data[2..6].try_into().unwrap()),
125 y: f32::from_le_bytes(data[6..10].try_into().unwrap()),
126 }),
127 TAG_POINTER_UP if data.len() >= 10 => Ok(InputEvent::PointerUp {
128 button: data[1],
129 x: f32::from_le_bytes(data[2..6].try_into().unwrap()),
130 y: f32::from_le_bytes(data[6..10].try_into().unwrap()),
131 }),
132 TAG_SCROLL if data.len() >= 10 => Ok(InputEvent::Scroll {
133 delta_x: f32::from_le_bytes(data[1..5].try_into().unwrap()),
134 delta_y: f32::from_le_bytes(data[5..9].try_into().unwrap()),
135 mode: match data[9] {
136 1 => ScrollMode::Lines,
137 2 => ScrollMode::Pages,
138 _ => ScrollMode::Pixels,
139 },
140 }),
141 TAG_KEY_DOWN if data.len() >= 3 => Ok(InputEvent::KeyDown {
142 code: ((data[1] as u16) << 8) | data[2] as u16,
143 }),
144 TAG_KEY_UP if data.len() >= 3 => Ok(InputEvent::KeyUp {
145 code: ((data[1] as u16) << 8) | data[2] as u16,
146 }),
147 tag => Err(InputEventError::UnknownTag(tag)),
148 }
149 }
150}
151
152#[derive(Debug, thiserror::Error)]
153pub enum InputEventError {
154 #[error("empty input buffer")]
155 Empty,
156 #[error("unknown input event tag: 0x{0:02x}")]
157 UnknownTag(u8),
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn roundtrip_pointer_move() {
166 let event = InputEvent::PointerMove {
167 x: 0.5,
168 y: 0.75,
169 buttons: 1,
170 timestamp_ms: 12345,
171 };
172 let bytes = event.to_bytes();
173 let decoded = InputEvent::from_bytes(&bytes).unwrap();
174 match decoded {
175 InputEvent::PointerMove {
176 x,
177 y,
178 buttons,
179 timestamp_ms,
180 } => {
181 assert!((x - 0.5).abs() < f32::EPSILON);
182 assert!((y - 0.75).abs() < f32::EPSILON);
183 assert_eq!(buttons, 1);
184 assert_eq!(timestamp_ms, 12345);
185 }
186 _ => panic!("wrong variant"),
187 }
188 }
189
190 #[test]
191 fn roundtrip_key_down() {
192 let event = InputEvent::KeyDown { code: 0x0041 };
193 let bytes = event.to_bytes();
194 let decoded = InputEvent::from_bytes(&bytes).unwrap();
195 match decoded {
196 InputEvent::KeyDown { code } => assert_eq!(code, 0x0041),
197 _ => panic!("wrong variant"),
198 }
199 }
200}