1use input_event::{Event as InputEvent, KeyboardEvent, PointerEvent};
2use num_enum::{IntoPrimitive, TryFromPrimitive, TryFromPrimitiveError};
3use paste::paste;
4use std::{
5 fmt::{Debug, Display, Formatter},
6 mem::size_of,
7};
8use thiserror::Error;
9
10pub const MAX_EVENT_SIZE: usize = size_of::<u8>() + size_of::<u32>() + 2 * size_of::<f64>();
14
15#[derive(Debug, Error)]
17pub enum ProtocolError {
18 #[error("invalid event id: `{0}`")]
20 InvalidEventId(#[from] TryFromPrimitiveError<EventType>),
21 #[error("invalid event id: `{0}`")]
23 InvalidPosition(#[from] TryFromPrimitiveError<Position>),
24}
25
26#[derive(Clone, Copy, Debug, TryFromPrimitive, IntoPrimitive)]
28#[repr(u8)]
29pub enum Position {
30 Left,
31 Right,
32 Top,
33 Bottom,
34}
35
36impl Display for Position {
37 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
38 let pos = match self {
39 Position::Left => "left",
40 Position::Right => "right",
41 Position::Top => "top",
42 Position::Bottom => "bottom",
43 };
44 write!(f, "{pos}")
45 }
46}
47
48#[derive(Clone, Copy, Debug)]
50pub enum ProtoEvent {
51 Enter(Position),
54 Leave(u32),
57 Ack(u32),
59 Input(InputEvent),
61 Ping,
64 Pong(bool),
66}
67
68impl Display for ProtoEvent {
69 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
70 match self {
71 ProtoEvent::Enter(s) => write!(f, "Enter({s})"),
72 ProtoEvent::Leave(s) => write!(f, "Leave({s})"),
73 ProtoEvent::Ack(s) => write!(f, "Ack({s})"),
74 ProtoEvent::Input(e) => write!(f, "{e}"),
75 ProtoEvent::Ping => write!(f, "ping"),
76 ProtoEvent::Pong(alive) => {
77 write!(
78 f,
79 "pong: {}",
80 if *alive { "alive" } else { "not available" }
81 )
82 }
83 }
84 }
85}
86
87#[derive(TryFromPrimitive, IntoPrimitive)]
88#[repr(u8)]
89pub enum EventType {
90 PointerMotion,
91 PointerButton,
92 PointerAxis,
93 PointerAxisValue120,
94 KeyboardKey,
95 KeyboardModifiers,
96 Ping,
97 Pong,
98 Enter,
99 Leave,
100 Ack,
101}
102
103impl ProtoEvent {
104 fn event_type(&self) -> EventType {
105 match self {
106 ProtoEvent::Input(e) => match e {
107 InputEvent::Pointer(p) => match p {
108 PointerEvent::Motion { .. } => EventType::PointerMotion,
109 PointerEvent::Button { .. } => EventType::PointerButton,
110 PointerEvent::Axis { .. } => EventType::PointerAxis,
111 PointerEvent::AxisDiscrete120 { .. } => EventType::PointerAxisValue120,
112 },
113 InputEvent::Keyboard(k) => match k {
114 KeyboardEvent::Key { .. } => EventType::KeyboardKey,
115 KeyboardEvent::Modifiers { .. } => EventType::KeyboardModifiers,
116 },
117 },
118 ProtoEvent::Ping => EventType::Ping,
119 ProtoEvent::Pong(_) => EventType::Pong,
120 ProtoEvent::Enter(_) => EventType::Enter,
121 ProtoEvent::Leave(_) => EventType::Leave,
122 ProtoEvent::Ack(_) => EventType::Ack,
123 }
124 }
125}
126
127impl TryFrom<[u8; MAX_EVENT_SIZE]> for ProtoEvent {
128 type Error = ProtocolError;
129
130 fn try_from(buf: [u8; MAX_EVENT_SIZE]) -> Result<Self, Self::Error> {
131 let mut buf = &buf[..];
132 let event_type = decode_u8(&mut buf)?;
133 match EventType::try_from(event_type)? {
134 EventType::PointerMotion => {
135 Ok(Self::Input(InputEvent::Pointer(PointerEvent::Motion {
136 time: decode_u32(&mut buf)?,
137 dx: decode_f64(&mut buf)?,
138 dy: decode_f64(&mut buf)?,
139 })))
140 }
141 EventType::PointerButton => {
142 Ok(Self::Input(InputEvent::Pointer(PointerEvent::Button {
143 time: decode_u32(&mut buf)?,
144 button: decode_u32(&mut buf)?,
145 state: decode_u32(&mut buf)?,
146 })))
147 }
148 EventType::PointerAxis => Ok(Self::Input(InputEvent::Pointer(PointerEvent::Axis {
149 time: decode_u32(&mut buf)?,
150 axis: decode_u8(&mut buf)?,
151 value: decode_f64(&mut buf)?,
152 }))),
153 EventType::PointerAxisValue120 => Ok(Self::Input(InputEvent::Pointer(
154 PointerEvent::AxisDiscrete120 {
155 axis: decode_u8(&mut buf)?,
156 value: decode_i32(&mut buf)?,
157 },
158 ))),
159 EventType::KeyboardKey => Ok(Self::Input(InputEvent::Keyboard(KeyboardEvent::Key {
160 time: decode_u32(&mut buf)?,
161 key: decode_u32(&mut buf)?,
162 state: decode_u8(&mut buf)?,
163 }))),
164 EventType::KeyboardModifiers => Ok(Self::Input(InputEvent::Keyboard(
165 KeyboardEvent::Modifiers {
166 depressed: decode_u32(&mut buf)?,
167 latched: decode_u32(&mut buf)?,
168 locked: decode_u32(&mut buf)?,
169 group: decode_u32(&mut buf)?,
170 },
171 ))),
172 EventType::Ping => Ok(Self::Ping),
173 EventType::Pong => Ok(Self::Pong(decode_u8(&mut buf)? != 0)),
174 EventType::Enter => Ok(Self::Enter(decode_u8(&mut buf)?.try_into()?)),
175 EventType::Leave => Ok(Self::Leave(decode_u32(&mut buf)?)),
176 EventType::Ack => Ok(Self::Ack(decode_u32(&mut buf)?)),
177 }
178 }
179}
180
181impl From<ProtoEvent> for ([u8; MAX_EVENT_SIZE], usize) {
182 fn from(event: ProtoEvent) -> Self {
183 let mut buf = [0u8; MAX_EVENT_SIZE];
184 let mut len = 0usize;
185 {
186 let mut buf = &mut buf[..];
187 let buf = &mut buf;
188 let len = &mut len;
189 encode_u8(buf, len, event.event_type() as u8);
190 match event {
191 ProtoEvent::Input(event) => match event {
192 InputEvent::Pointer(p) => match p {
193 PointerEvent::Motion { time, dx, dy } => {
194 encode_u32(buf, len, time);
195 encode_f64(buf, len, dx);
196 encode_f64(buf, len, dy);
197 }
198 PointerEvent::Button {
199 time,
200 button,
201 state,
202 } => {
203 encode_u32(buf, len, time);
204 encode_u32(buf, len, button);
205 encode_u32(buf, len, state);
206 }
207 PointerEvent::Axis { time, axis, value } => {
208 encode_u32(buf, len, time);
209 encode_u8(buf, len, axis);
210 encode_f64(buf, len, value);
211 }
212 PointerEvent::AxisDiscrete120 { axis, value } => {
213 encode_u8(buf, len, axis);
214 encode_i32(buf, len, value);
215 }
216 },
217 InputEvent::Keyboard(k) => match k {
218 KeyboardEvent::Key { time, key, state } => {
219 encode_u32(buf, len, time);
220 encode_u32(buf, len, key);
221 encode_u8(buf, len, state);
222 }
223 KeyboardEvent::Modifiers {
224 depressed,
225 latched,
226 locked,
227 group,
228 } => {
229 encode_u32(buf, len, depressed);
230 encode_u32(buf, len, latched);
231 encode_u32(buf, len, locked);
232 encode_u32(buf, len, group);
233 }
234 },
235 },
236 ProtoEvent::Ping => {}
237 ProtoEvent::Pong(alive) => encode_u8(buf, len, alive as u8),
238 ProtoEvent::Enter(pos) => encode_u8(buf, len, pos as u8),
239 ProtoEvent::Leave(serial) => encode_u32(buf, len, serial),
240 ProtoEvent::Ack(serial) => encode_u32(buf, len, serial),
241 }
242 }
243 (buf, len)
244 }
245}
246
247macro_rules! decode_impl {
248 ($t:ty) => {
249 paste! {
250 fn [<decode_ $t>](data: &mut &[u8]) -> Result<$t, ProtocolError> {
251 let (int_bytes, rest) = data.split_at(size_of::<$t>());
252 *data = rest;
253 Ok($t::from_be_bytes(int_bytes.try_into().unwrap()))
254 }
255 }
256 };
257}
258
259decode_impl!(u8);
260decode_impl!(u32);
261decode_impl!(i32);
262decode_impl!(f64);
263
264macro_rules! encode_impl {
265 ($t:ty) => {
266 paste! {
267 fn [<encode_ $t>](buf: &mut &mut [u8], amt: &mut usize, n: $t) {
268 let src = n.to_be_bytes();
269 let data = std::mem::take(buf);
270 let (int_bytes, rest) = data.split_at_mut(size_of::<$t>());
271 int_bytes.copy_from_slice(&src);
272 *amt += size_of::<$t>();
273 *buf = rest
274 }
275 }
276 };
277}
278
279encode_impl!(u8);
280encode_impl!(u32);
281encode_impl!(i32);
282encode_impl!(f64);