1use bit_field::BitField as _;
2use bitflags::bitflags;
3use ironrdp_core::{
4 cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, other_err, Decode, DecodeResult, Encode,
5 EncodeResult, ReadCursor, WriteCursor,
6};
7use num_derive::FromPrimitive;
8use num_traits::FromPrimitive as _;
9
10use crate::fast_path::EncryptionFlags;
11use crate::input::{MousePdu, MouseRelPdu, MouseXPdu};
12use crate::per;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct FastPathInputHeader {
17 pub flags: EncryptionFlags,
18 pub data_length: usize,
19 pub num_events: u8,
20}
21
22impl FastPathInputHeader {
23 const NAME: &'static str = "FastPathInputHeader";
24
25 const FIXED_PART_SIZE: usize = 1 ;
26}
27
28impl Encode for FastPathInputHeader {
29 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
30 ensure_size!(in: dst, size: self.size());
31
32 let mut header = 0u8;
33 header.set_bits(0..2, 0); if self.num_events < 16 {
35 header.set_bits(2..7, self.num_events);
36 }
37 header.set_bits(6..8, self.flags.bits());
38 dst.write_u8(header);
39
40 per::write_length(dst, cast_length!("len", self.data_length + self.size())?);
41 if self.num_events > 15 {
42 dst.write_u8(self.num_events);
43 }
44
45 Ok(())
46 }
47
48 fn name(&self) -> &'static str {
49 Self::NAME
50 }
51
52 fn size(&self) -> usize {
53 let num_events_length = if self.num_events < 16 { 0 } else { 1 };
54 Self::FIXED_PART_SIZE + per::sizeof_length(self.data_length + num_events_length + 1) + num_events_length
55 }
56}
57
58impl<'de> Decode<'de> for FastPathInputHeader {
59 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
60 ensure_fixed_part_size!(in: src);
61
62 let header = src.read_u8();
63 let flags = EncryptionFlags::from_bits_truncate(header.get_bits(6..8));
64 let mut num_events = header.get_bits(2..6);
65 let (length, sizeof_length) = per::read_length(src).map_err(|e| other_err!("perLen", source: e))?;
66
67 if !flags.is_empty() {
68 return Err(invalid_field_err!("flags", "encryption not supported"));
69 }
70
71 let num_events_length = if num_events == 0 {
72 ensure_size!(in: src, size: 1);
73 num_events = src.read_u8();
74 1
75 } else {
76 0
77 };
78
79 let data_length = usize::from(length) - sizeof_length - 1 - num_events_length;
80
81 Ok(FastPathInputHeader {
82 flags,
83 data_length,
84 num_events,
85 })
86 }
87}
88
89#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive)]
90#[repr(u8)]
91pub enum FastpathInputEventType {
92 ScanCode = 0x0000,
93 Mouse = 0x0001,
94 MouseX = 0x0002,
95 Sync = 0x0003,
96 Unicode = 0x0004,
97 MouseRel = 0x0005,
98 QoeTimestamp = 0x0006,
99}
100
101impl FastpathInputEventType {
102 #[expect(
103 clippy::as_conversions,
104 reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
105 )]
106 fn as_u8(self) -> u8 {
107 self as u8
108 }
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq)]
112pub enum FastPathInputEvent {
113 KeyboardEvent(KeyboardFlags, u8),
114 UnicodeKeyboardEvent(KeyboardFlags, u16),
115 MouseEvent(MousePdu),
116 MouseEventEx(MouseXPdu),
117 MouseEventRel(MouseRelPdu),
118 QoeEvent(u32),
119 SyncEvent(SynchronizeFlags),
120}
121
122impl FastPathInputEvent {
123 const NAME: &'static str = "FastPathInputEvent";
124
125 const FIXED_PART_SIZE: usize = 1 ;
126}
127
128impl Encode for FastPathInputEvent {
129 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
130 ensure_size!(in: dst, size: self.size());
131
132 let mut header = 0u8;
133 let (flags, code) = match self {
134 FastPathInputEvent::KeyboardEvent(flags, _) => (flags.bits(), FastpathInputEventType::ScanCode),
135 FastPathInputEvent::UnicodeKeyboardEvent(flags, _) => (flags.bits(), FastpathInputEventType::Unicode),
136 FastPathInputEvent::MouseEvent(_) => (0, FastpathInputEventType::Mouse),
137 FastPathInputEvent::MouseEventEx(_) => (0, FastpathInputEventType::MouseX),
138 FastPathInputEvent::MouseEventRel(_) => (0, FastpathInputEventType::MouseRel),
139 FastPathInputEvent::QoeEvent(_) => (0, FastpathInputEventType::QoeTimestamp),
140 FastPathInputEvent::SyncEvent(flags) => (flags.bits(), FastpathInputEventType::Sync),
141 };
142 header.set_bits(0..5, flags);
143 header.set_bits(5..8, code.as_u8());
144 dst.write_u8(header);
145 match self {
146 FastPathInputEvent::KeyboardEvent(_, code) => {
147 dst.write_u8(*code);
148 }
149 FastPathInputEvent::UnicodeKeyboardEvent(_, code) => {
150 dst.write_u16(*code);
151 }
152 FastPathInputEvent::MouseEvent(pdu) => {
153 pdu.encode(dst)?;
154 }
155 FastPathInputEvent::MouseEventEx(pdu) => {
156 pdu.encode(dst)?;
157 }
158 FastPathInputEvent::QoeEvent(stamp) => {
159 dst.write_u32(*stamp);
160 }
161 _ => {}
162 };
163
164 Ok(())
165 }
166
167 fn name(&self) -> &'static str {
168 Self::NAME
169 }
170
171 fn size(&self) -> usize {
172 Self::FIXED_PART_SIZE
173 + match self {
174 FastPathInputEvent::KeyboardEvent(_, _) => 1,
175 FastPathInputEvent::UnicodeKeyboardEvent(_, _) => 2,
176 FastPathInputEvent::MouseEvent(pdu) => pdu.size(),
177 FastPathInputEvent::MouseEventEx(pdu) => pdu.size(),
178 FastPathInputEvent::MouseEventRel(pdu) => pdu.size(),
179 FastPathInputEvent::QoeEvent(_) => 4,
180 FastPathInputEvent::SyncEvent(_) => 0,
181 }
182 }
183}
184
185impl<'de> Decode<'de> for FastPathInputEvent {
186 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
187 ensure_fixed_part_size!(in: src);
188
189 let header = src.read_u8();
190 let flags = header.get_bits(0..5);
191 let code = header.get_bits(5..8);
192 let code: FastpathInputEventType = FastpathInputEventType::from_u8(code)
193 .ok_or_else(|| invalid_field_err!("code", "input event code unsupported"))?;
194 let event = match code {
195 FastpathInputEventType::ScanCode => {
196 ensure_size!(in: src, size: 1);
197 let code = src.read_u8();
198 let flags = KeyboardFlags::from_bits(flags)
199 .ok_or_else(|| invalid_field_err!("flags", "input keyboard flags unsupported"))?;
200 FastPathInputEvent::KeyboardEvent(flags, code)
201 }
202 FastpathInputEventType::Mouse => {
203 let mouse_event = MousePdu::decode(src)?;
204 FastPathInputEvent::MouseEvent(mouse_event)
205 }
206 FastpathInputEventType::MouseX => {
207 let mouse_event = MouseXPdu::decode(src)?;
208 FastPathInputEvent::MouseEventEx(mouse_event)
209 }
210 FastpathInputEventType::MouseRel => {
211 let mouse_event = MouseRelPdu::decode(src)?;
212 FastPathInputEvent::MouseEventRel(mouse_event)
213 }
214 FastpathInputEventType::Sync => {
215 let flags = SynchronizeFlags::from_bits(flags)
216 .ok_or_else(|| invalid_field_err!("flags", "input synchronize flags unsupported"))?;
217 FastPathInputEvent::SyncEvent(flags)
218 }
219 FastpathInputEventType::Unicode => {
220 ensure_size!(in: src, size: 2);
221 let code = src.read_u16();
222 let flags = KeyboardFlags::from_bits(flags)
223 .ok_or_else(|| invalid_field_err!("flags", "input keyboard flags unsupported"))?;
224 FastPathInputEvent::UnicodeKeyboardEvent(flags, code)
225 }
226 FastpathInputEventType::QoeTimestamp => {
227 ensure_size!(in: src, size: 4);
228 let code = src.read_u32();
229 FastPathInputEvent::QoeEvent(code)
230 }
231 };
232 Ok(event)
233 }
234}
235
236bitflags! {
237 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
238 pub struct KeyboardFlags: u8 {
239 const RELEASE = 0x01;
240 const EXTENDED = 0x02;
241 const EXTENDED1 = 0x04;
242 }
243}
244
245bitflags! {
246 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
247 pub struct SynchronizeFlags: u8 {
248 const SCROLL_LOCK = 0x01;
249 const NUM_LOCK = 0x02;
250 const CAPS_LOCK = 0x04;
251 const KANA_LOCK = 0x08;
252 }
253}
254
255#[derive(Debug, Clone, PartialEq, Eq)]
256pub struct FastPathInput(
257 Vec<FastPathInputEvent>,
259);
260
261impl FastPathInput {
262 const NAME: &'static str = "FastPathInput";
263
264 pub fn new(input_events: Vec<FastPathInputEvent>) -> DecodeResult<Self> {
265 if !(1..=255usize).contains(&input_events.len()) {
267 return Err(invalid_field_err!("nEvents", "invalid number of input events"));
268 }
269
270 Ok(Self(input_events))
271 }
272
273 pub fn single(input_event: FastPathInputEvent) -> Self {
274 Self(vec![input_event])
276 }
277
278 pub fn input_events(&self) -> &[FastPathInputEvent] {
279 &self.0
280 }
281}
282
283impl Encode for FastPathInput {
284 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
285 ensure_size!(in: dst, size: self.size());
286
287 if self.0.is_empty() {
288 return Err(other_err!("Empty fast-path input"));
289 }
290
291 let data_length = self.0.iter().map(Encode::size).sum::<usize>();
292 let header = FastPathInputHeader {
293 num_events: u8::try_from(self.0.len()).expect("per invariant (1..=255).contains(num_events.len())"),
294 flags: EncryptionFlags::empty(),
295 data_length,
296 };
297 header.encode(dst)?;
298
299 for event in self.0.iter() {
300 event.encode(dst)?;
301 }
302
303 Ok(())
304 }
305
306 fn name(&self) -> &'static str {
307 Self::NAME
308 }
309
310 fn size(&self) -> usize {
311 let data_length = self.0.iter().map(Encode::size).sum::<usize>();
312 let header = FastPathInputHeader {
313 num_events: u8::try_from(self.0.len())
314 .expect("INVARIANT: num_events is within the range of 1 to 255, inclusive"),
315 flags: EncryptionFlags::empty(),
316 data_length,
317 };
318 header.size() + data_length
319 }
320}
321
322impl<'de> Decode<'de> for FastPathInput {
323 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
324 let header = FastPathInputHeader::decode(src)?;
325 let events = core::iter::repeat_with(|| FastPathInputEvent::decode(src))
326 .take(usize::from(header.num_events))
327 .collect::<Result<Vec<_>, _>>()?;
328
329 Self::new(events)
330 }
331}