lan_mouse_proto/
lib.rs

1use input_event::{Event as InputEvent, KeyboardEvent, PointerEvent};
2use num_enum::{IntoPrimitive, TryFromPrimitive, TryFromPrimitiveError};
3use paste::paste;
4use std::{
5    fmt::{Debug, Display},
6    mem::size_of,
7};
8use thiserror::Error;
9
10/// defines the maximum size an encoded event can take up
11/// this is currently the pointer motion event
12/// type: u8, time: u32, dx: f64, dy: f64
13pub const MAX_EVENT_SIZE: usize = size_of::<u8>() + size_of::<u32>() + 2 * size_of::<f64>();
14
15/// error type for protocol violations
16#[derive(Debug, Error)]
17pub enum ProtocolError {
18    /// event type does not exist
19    #[error("invalid event id: `{0}`")]
20    InvalidEventId(#[from] TryFromPrimitiveError<EventType>),
21}
22
23/// main lan-mouse protocol event type
24#[derive(Clone, Copy, Debug)]
25pub enum ProtoEvent {
26    /// notify a client that the cursor entered its region
27    /// [`ProtoEvent::Ack`] with the same serial is used for synchronization between devices
28    Enter(u32),
29    /// notify a client that the cursor left its region
30    /// [`ProtoEvent::Ack`] with the same serial is used for synchronization between devices
31    Leave(u32),
32    /// acknowledge of an [`ProtoEvent::Enter`] or [`ProtoEvent::Leave`] event
33    Ack(u32),
34    /// Input event
35    Input(InputEvent),
36    /// Ping event for tracking unresponsive clients.
37    /// A client has to respond with [`ProtoEvent::Pong`].
38    Ping,
39    /// Response to [`ProtoEvent::Ping`]
40    Pong,
41}
42
43impl Display for ProtoEvent {
44    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45        match self {
46            ProtoEvent::Enter(s) => write!(f, "Enter({s})"),
47            ProtoEvent::Leave(s) => write!(f, "Leave({s})"),
48            ProtoEvent::Ack(s) => write!(f, "Ack({s})"),
49            ProtoEvent::Input(e) => write!(f, "{e}"),
50            ProtoEvent::Ping => write!(f, "ping"),
51            ProtoEvent::Pong => write!(f, "pong"),
52        }
53    }
54}
55
56#[derive(TryFromPrimitive, IntoPrimitive)]
57#[repr(u8)]
58pub enum EventType {
59    PointerMotion,
60    PointerButton,
61    PointerAxis,
62    PointerAxisValue120,
63    KeyboardKey,
64    KeyboardModifiers,
65    Ping,
66    Pong,
67    Enter,
68    Leave,
69    Ack,
70}
71
72impl ProtoEvent {
73    fn event_type(&self) -> EventType {
74        match self {
75            ProtoEvent::Input(e) => match e {
76                InputEvent::Pointer(p) => match p {
77                    PointerEvent::Motion { .. } => EventType::PointerMotion,
78                    PointerEvent::Button { .. } => EventType::PointerButton,
79                    PointerEvent::Axis { .. } => EventType::PointerAxis,
80                    PointerEvent::AxisDiscrete120 { .. } => EventType::PointerAxisValue120,
81                },
82                InputEvent::Keyboard(k) => match k {
83                    KeyboardEvent::Key { .. } => EventType::KeyboardKey,
84                    KeyboardEvent::Modifiers { .. } => EventType::KeyboardModifiers,
85                },
86            },
87            ProtoEvent::Ping => EventType::Ping,
88            ProtoEvent::Pong => EventType::Pong,
89            ProtoEvent::Enter(_) => EventType::Enter,
90            ProtoEvent::Leave(_) => EventType::Leave,
91            ProtoEvent::Ack(_) => EventType::Ack,
92        }
93    }
94}
95
96impl TryFrom<[u8; MAX_EVENT_SIZE]> for ProtoEvent {
97    type Error = ProtocolError;
98
99    fn try_from(buf: [u8; MAX_EVENT_SIZE]) -> Result<Self, Self::Error> {
100        let mut buf = &buf[..];
101        let event_type = decode_u8(&mut buf)?;
102        match EventType::try_from(event_type)? {
103            EventType::PointerMotion => {
104                Ok(Self::Input(InputEvent::Pointer(PointerEvent::Motion {
105                    time: decode_u32(&mut buf)?,
106                    dx: decode_f64(&mut buf)?,
107                    dy: decode_f64(&mut buf)?,
108                })))
109            }
110            EventType::PointerButton => {
111                Ok(Self::Input(InputEvent::Pointer(PointerEvent::Button {
112                    time: decode_u32(&mut buf)?,
113                    button: decode_u32(&mut buf)?,
114                    state: decode_u32(&mut buf)?,
115                })))
116            }
117            EventType::PointerAxis => Ok(Self::Input(InputEvent::Pointer(PointerEvent::Axis {
118                time: decode_u32(&mut buf)?,
119                axis: decode_u8(&mut buf)?,
120                value: decode_f64(&mut buf)?,
121            }))),
122            EventType::PointerAxisValue120 => Ok(Self::Input(InputEvent::Pointer(
123                PointerEvent::AxisDiscrete120 {
124                    axis: decode_u8(&mut buf)?,
125                    value: decode_i32(&mut buf)?,
126                },
127            ))),
128            EventType::KeyboardKey => Ok(Self::Input(InputEvent::Keyboard(KeyboardEvent::Key {
129                time: decode_u32(&mut buf)?,
130                key: decode_u32(&mut buf)?,
131                state: decode_u8(&mut buf)?,
132            }))),
133            EventType::KeyboardModifiers => Ok(Self::Input(InputEvent::Keyboard(
134                KeyboardEvent::Modifiers {
135                    depressed: decode_u32(&mut buf)?,
136                    latched: decode_u32(&mut buf)?,
137                    locked: decode_u32(&mut buf)?,
138                    group: decode_u32(&mut buf)?,
139                },
140            ))),
141            EventType::Ping => Ok(Self::Ping),
142            EventType::Pong => Ok(Self::Pong),
143            EventType::Enter => Ok(Self::Enter(decode_u32(&mut buf)?)),
144            EventType::Leave => Ok(Self::Leave(decode_u32(&mut buf)?)),
145            EventType::Ack => Ok(Self::Ack(decode_u32(&mut buf)?)),
146        }
147    }
148}
149
150impl From<ProtoEvent> for ([u8; MAX_EVENT_SIZE], usize) {
151    fn from(event: ProtoEvent) -> Self {
152        let mut buf = [0u8; MAX_EVENT_SIZE];
153        let mut len = 0usize;
154        {
155            let mut buf = &mut buf[..];
156            let buf = &mut buf;
157            let len = &mut len;
158            encode_u8(buf, len, event.event_type() as u8);
159            match event {
160                ProtoEvent::Input(event) => match event {
161                    InputEvent::Pointer(p) => match p {
162                        PointerEvent::Motion { time, dx, dy } => {
163                            encode_u32(buf, len, time);
164                            encode_f64(buf, len, dx);
165                            encode_f64(buf, len, dy);
166                        }
167                        PointerEvent::Button {
168                            time,
169                            button,
170                            state,
171                        } => {
172                            encode_u32(buf, len, time);
173                            encode_u32(buf, len, button);
174                            encode_u32(buf, len, state);
175                        }
176                        PointerEvent::Axis { time, axis, value } => {
177                            encode_u32(buf, len, time);
178                            encode_u8(buf, len, axis);
179                            encode_f64(buf, len, value);
180                        }
181                        PointerEvent::AxisDiscrete120 { axis, value } => {
182                            encode_u8(buf, len, axis);
183                            encode_i32(buf, len, value);
184                        }
185                    },
186                    InputEvent::Keyboard(k) => match k {
187                        KeyboardEvent::Key { time, key, state } => {
188                            encode_u32(buf, len, time);
189                            encode_u32(buf, len, key);
190                            encode_u8(buf, len, state);
191                        }
192                        KeyboardEvent::Modifiers {
193                            depressed,
194                            latched,
195                            locked,
196                            group,
197                        } => {
198                            encode_u32(buf, len, depressed);
199                            encode_u32(buf, len, latched);
200                            encode_u32(buf, len, locked);
201                            encode_u32(buf, len, group);
202                        }
203                    },
204                },
205                ProtoEvent::Ping => {}
206                ProtoEvent::Pong => {}
207                ProtoEvent::Enter(serial) => encode_u32(buf, len, serial),
208                ProtoEvent::Leave(serial) => encode_u32(buf, len, serial),
209                ProtoEvent::Ack(serial) => encode_u32(buf, len, serial),
210            }
211        }
212        (buf, len)
213    }
214}
215
216macro_rules! decode_impl {
217    ($t:ty) => {
218        paste! {
219            fn [<decode_ $t>](data: &mut &[u8]) -> Result<$t, ProtocolError> {
220                let (int_bytes, rest) = data.split_at(size_of::<$t>());
221                *data = rest;
222                Ok($t::from_be_bytes(int_bytes.try_into().unwrap()))
223            }
224        }
225    };
226}
227
228decode_impl!(u8);
229decode_impl!(u32);
230decode_impl!(i32);
231decode_impl!(f64);
232
233macro_rules! encode_impl {
234    ($t:ty) => {
235        paste! {
236            fn [<encode_ $t>](buf: &mut &mut [u8], amt: &mut usize, n: $t) {
237                let src = n.to_be_bytes();
238                let data = std::mem::take(buf);
239                let (int_bytes, rest) = data.split_at_mut(size_of::<$t>());
240                int_bytes.copy_from_slice(&src);
241                *amt += size_of::<$t>();
242                *buf = rest
243            }
244        }
245    };
246}
247
248encode_impl!(u8);
249encode_impl!(u32);
250encode_impl!(i32);
251encode_impl!(f64);