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 _};
11const 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; const BUTTON2 = 0x0000_2000; const BUTTON3 = 0x0000_4000; 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 + 4 ;
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 ;
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 + 8 + 4 + 4 ;
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 ;
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}