ironrdp_ainput/
lib.rs

1#![cfg_attr(doc, doc = include_str!("../README.md"))]
2#![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")]
3
4use bitflags::bitflags;
5use ironrdp_core::{
6    ensure_fixed_part_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor,
7};
8use ironrdp_dvc::DvcEncode;
9use num_derive::{FromPrimitive, ToPrimitive};
10use num_traits::{FromPrimitive as _, ToPrimitive as _};
11// Advanced Input channel as defined from Freerdp, [here]:
12//
13// [here]: https://github.com/FreeRDP/FreeRDP/blob/master/include/freerdp/channels/ainput.h
14
15const VERSION_MAJOR: u32 = 1;
16const VERSION_MINOR: u32 = 0;
17
18pub const CHANNEL_NAME: &str = "FreeRDP::Advanced::Input";
19
20bitflags! {
21    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
22    pub struct MouseEventFlags: u64 {
23        const WHEEL = 0x0000_0001;
24        const MOVE = 0x0000_0004;
25        const DOWN = 0x0000_0008;
26
27        const REL = 0x0000_0010;
28        const HAVE_REL = 0x0000_0020;
29        const BUTTON1 = 0x0000_1000; /* left */
30        const BUTTON2 = 0x0000_2000; /* right */
31        const BUTTON3 = 0x0000_4000; /* middle */
32
33        const XBUTTON1 = 0x0000_0100;
34        const XBUTTON2 = 0x0000_0200;
35    }
36}
37
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct VersionPdu {
40    major_version: u32,
41    minor_version: u32,
42}
43
44impl VersionPdu {
45    const NAME: &'static str = "AInputVersionPdu";
46
47    const FIXED_PART_SIZE: usize = 4 /* MajorVersion */ + 4 /* MinorVersion */;
48
49    pub fn new() -> Self {
50        Self {
51            major_version: VERSION_MAJOR,
52            minor_version: VERSION_MINOR,
53        }
54    }
55}
56
57impl Default for VersionPdu {
58    fn default() -> Self {
59        Self::new()
60    }
61}
62
63impl Encode for VersionPdu {
64    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
65        ensure_fixed_part_size!(in: dst);
66
67        dst.write_u32(self.major_version);
68        dst.write_u32(self.minor_version);
69
70        Ok(())
71    }
72
73    fn name(&self) -> &'static str {
74        Self::NAME
75    }
76
77    fn size(&self) -> usize {
78        Self::FIXED_PART_SIZE
79    }
80}
81
82impl<'de> Decode<'de> for VersionPdu {
83    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
84        ensure_fixed_part_size!(in: src);
85
86        let major_version = src.read_u32();
87        let minor_version = src.read_u32();
88
89        Ok(Self {
90            major_version,
91            minor_version,
92        })
93    }
94}
95
96#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
97pub enum ServerPduType {
98    Version = 0x01,
99}
100
101impl<'a> From<&'a ServerPdu> for ServerPduType {
102    fn from(s: &'a ServerPdu) -> Self {
103        match s {
104            ServerPdu::Version(_) => Self::Version,
105        }
106    }
107}
108
109#[derive(Debug, Clone, PartialEq, Eq)]
110pub enum ServerPdu {
111    Version(VersionPdu),
112}
113
114impl ServerPdu {
115    const NAME: &'static str = "AInputServerPdu";
116
117    const FIXED_PART_SIZE: usize = 2 /* PduType */;
118}
119
120impl Encode for ServerPdu {
121    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
122        ensure_fixed_part_size!(in: dst);
123
124        dst.write_u16(ServerPduType::from(self).to_u16().unwrap());
125        match self {
126            ServerPdu::Version(pdu) => pdu.encode(dst),
127        }
128    }
129
130    fn name(&self) -> &'static str {
131        Self::NAME
132    }
133
134    fn size(&self) -> usize {
135        Self::FIXED_PART_SIZE
136            .checked_add(match self {
137                ServerPdu::Version(pdu) => pdu.size(),
138            })
139            .expect("never overflow")
140    }
141}
142
143impl DvcEncode for ServerPdu {}
144
145impl<'de> Decode<'de> for ServerPdu {
146    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
147        ensure_fixed_part_size!(in: src);
148
149        let pdu_type =
150            ServerPduType::from_u16(src.read_u16()).ok_or_else(|| invalid_field_err!("pduType", "invalid pdu type"))?;
151
152        let server_pdu = match pdu_type {
153            ServerPduType::Version => ServerPdu::Version(VersionPdu::decode(src)?),
154        };
155
156        Ok(server_pdu)
157    }
158}
159
160#[derive(Debug, Clone, PartialEq, Eq)]
161pub struct MousePdu {
162    pub time: u64,
163    pub flags: MouseEventFlags,
164    pub x: i32,
165    pub y: i32,
166}
167
168impl MousePdu {
169    const NAME: &'static str = "AInputMousePdu";
170
171    const FIXED_PART_SIZE: usize = 8 /* Time */ + 8 /* Flags */ + 4 /* X */ + 4 /* Y */;
172}
173
174impl Encode for MousePdu {
175    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
176        ensure_fixed_part_size!(in: dst);
177
178        dst.write_u64(self.time);
179        dst.write_u64(self.flags.bits());
180        dst.write_i32(self.x);
181        dst.write_i32(self.y);
182
183        Ok(())
184    }
185
186    fn name(&self) -> &'static str {
187        Self::NAME
188    }
189
190    fn size(&self) -> usize {
191        Self::FIXED_PART_SIZE
192    }
193}
194
195impl<'de> Decode<'de> for MousePdu {
196    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
197        ensure_fixed_part_size!(in: src);
198
199        let time = src.read_u64();
200        let flags = MouseEventFlags::from_bits_retain(src.read_u64());
201        let x = src.read_i32();
202        let y = src.read_i32();
203
204        Ok(Self { time, flags, x, y })
205    }
206}
207
208#[derive(Debug, Clone, PartialEq, Eq)]
209pub enum ClientPdu {
210    Mouse(MousePdu),
211}
212
213impl ClientPdu {
214    const NAME: &'static str = "AInputClientPdu";
215
216    const FIXED_PART_SIZE: usize = 2 /* PduType */;
217}
218
219impl Encode for ClientPdu {
220    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
221        ensure_fixed_part_size!(in: dst);
222
223        dst.write_u16(ClientPduType::from(self).to_u16().unwrap());
224        match self {
225            ClientPdu::Mouse(pdu) => pdu.encode(dst),
226        }
227    }
228
229    fn name(&self) -> &'static str {
230        Self::NAME
231    }
232
233    fn size(&self) -> usize {
234        Self::FIXED_PART_SIZE
235            .checked_add(match self {
236                ClientPdu::Mouse(pdu) => pdu.size(),
237            })
238            .expect("never overflow")
239    }
240}
241
242impl<'de> Decode<'de> for ClientPdu {
243    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
244        ensure_fixed_part_size!(in: src);
245
246        let pdu_type =
247            ClientPduType::from_u16(src.read_u16()).ok_or_else(|| invalid_field_err!("pduType", "invalid pdu type"))?;
248
249        let client_pdu = match pdu_type {
250            ClientPduType::Mouse => ClientPdu::Mouse(MousePdu::decode(src)?),
251        };
252
253        Ok(client_pdu)
254    }
255}
256
257#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
258pub enum ClientPduType {
259    Mouse = 0x02,
260}
261
262impl<'a> From<&'a ClientPdu> for ClientPduType {
263    fn from(s: &'a ClientPdu) -> Self {
264        match s {
265            ClientPdu::Mouse(_) => Self::Mouse,
266        }
267    }
268}