ironrdp_pdu/input/
fast_path.rs

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, ToPrimitive};
8use num_traits::{FromPrimitive as _, ToPrimitive as _};
9
10use crate::fast_path::EncryptionFlags;
11use crate::input::{MousePdu, MouseRelPdu, MouseXPdu};
12use crate::per;
13
14/// Implements the Fast-Path RDP message header PDU.
15#[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 /* header */;
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); // fast-path action
34        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
55            + per::sizeof_length(self.data_length as u16 + num_events_length as u16 + 1)
56            + num_events_length
57    }
58}
59
60impl<'de> Decode<'de> for FastPathInputHeader {
61    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
62        ensure_fixed_part_size!(in: src);
63
64        let header = src.read_u8();
65        let flags = EncryptionFlags::from_bits_truncate(header.get_bits(6..8));
66        let mut num_events = header.get_bits(2..6);
67        let (length, sizeof_length) = per::read_length(src).map_err(|e| other_err!("perLen", source: e))?;
68
69        if !flags.is_empty() {
70            return Err(invalid_field_err!("flags", "encryption not supported"));
71        }
72
73        let num_events_length = if num_events == 0 {
74            ensure_size!(in: src, size: 1);
75            num_events = src.read_u8();
76            1
77        } else {
78            0
79        };
80
81        let data_length = length as usize - sizeof_length - 1 - num_events_length;
82
83        Ok(FastPathInputHeader {
84            flags,
85            data_length,
86            num_events,
87        })
88    }
89}
90
91#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
92#[repr(u8)]
93pub enum FastpathInputEventType {
94    ScanCode = 0x0000,
95    Mouse = 0x0001,
96    MouseX = 0x0002,
97    Sync = 0x0003,
98    Unicode = 0x0004,
99    MouseRel = 0x0005,
100    QoeTimestamp = 0x0006,
101}
102
103#[derive(Debug, Clone, PartialEq, Eq)]
104pub enum FastPathInputEvent {
105    KeyboardEvent(KeyboardFlags, u8),
106    UnicodeKeyboardEvent(KeyboardFlags, u16),
107    MouseEvent(MousePdu),
108    MouseEventEx(MouseXPdu),
109    MouseEventRel(MouseRelPdu),
110    QoeEvent(u32),
111    SyncEvent(SynchronizeFlags),
112}
113
114impl FastPathInputEvent {
115    const NAME: &'static str = "FastPathInputEvent";
116
117    const FIXED_PART_SIZE: usize = 1 /* header */;
118}
119
120impl Encode for FastPathInputEvent {
121    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
122        ensure_size!(in: dst, size: self.size());
123
124        let mut header = 0u8;
125        let (flags, code) = match self {
126            FastPathInputEvent::KeyboardEvent(flags, _) => (flags.bits(), FastpathInputEventType::ScanCode),
127            FastPathInputEvent::UnicodeKeyboardEvent(flags, _) => (flags.bits(), FastpathInputEventType::Unicode),
128            FastPathInputEvent::MouseEvent(_) => (0, FastpathInputEventType::Mouse),
129            FastPathInputEvent::MouseEventEx(_) => (0, FastpathInputEventType::MouseX),
130            FastPathInputEvent::MouseEventRel(_) => (0, FastpathInputEventType::MouseRel),
131            FastPathInputEvent::QoeEvent(_) => (0, FastpathInputEventType::QoeTimestamp),
132            FastPathInputEvent::SyncEvent(flags) => (flags.bits(), FastpathInputEventType::Sync),
133        };
134        header.set_bits(0..5, flags);
135        header.set_bits(5..8, code.to_u8().unwrap());
136        dst.write_u8(header);
137        match self {
138            FastPathInputEvent::KeyboardEvent(_, code) => {
139                dst.write_u8(*code);
140            }
141            FastPathInputEvent::UnicodeKeyboardEvent(_, code) => {
142                dst.write_u16(*code);
143            }
144            FastPathInputEvent::MouseEvent(pdu) => {
145                pdu.encode(dst)?;
146            }
147            FastPathInputEvent::MouseEventEx(pdu) => {
148                pdu.encode(dst)?;
149            }
150            FastPathInputEvent::QoeEvent(stamp) => {
151                dst.write_u32(*stamp);
152            }
153            _ => {}
154        };
155
156        Ok(())
157    }
158
159    fn name(&self) -> &'static str {
160        Self::NAME
161    }
162
163    fn size(&self) -> usize {
164        Self::FIXED_PART_SIZE
165            + match self {
166                FastPathInputEvent::KeyboardEvent(_, _) => 1,
167                FastPathInputEvent::UnicodeKeyboardEvent(_, _) => 2,
168                FastPathInputEvent::MouseEvent(pdu) => pdu.size(),
169                FastPathInputEvent::MouseEventEx(pdu) => pdu.size(),
170                FastPathInputEvent::MouseEventRel(pdu) => pdu.size(),
171                FastPathInputEvent::QoeEvent(_) => 4,
172                FastPathInputEvent::SyncEvent(_) => 0,
173            }
174    }
175}
176
177impl<'de> Decode<'de> for FastPathInputEvent {
178    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
179        ensure_fixed_part_size!(in: src);
180
181        let header = src.read_u8();
182        let flags = header.get_bits(0..5);
183        let code = header.get_bits(5..8);
184        let code: FastpathInputEventType = FastpathInputEventType::from_u8(code)
185            .ok_or_else(|| invalid_field_err!("code", "input event code unsupported"))?;
186        let event = match code {
187            FastpathInputEventType::ScanCode => {
188                ensure_size!(in: src, size: 1);
189                let code = src.read_u8();
190                let flags = KeyboardFlags::from_bits(flags)
191                    .ok_or_else(|| invalid_field_err!("flags", "input keyboard flags unsupported"))?;
192                FastPathInputEvent::KeyboardEvent(flags, code)
193            }
194            FastpathInputEventType::Mouse => {
195                let mouse_event = MousePdu::decode(src)?;
196                FastPathInputEvent::MouseEvent(mouse_event)
197            }
198            FastpathInputEventType::MouseX => {
199                let mouse_event = MouseXPdu::decode(src)?;
200                FastPathInputEvent::MouseEventEx(mouse_event)
201            }
202            FastpathInputEventType::MouseRel => {
203                let mouse_event = MouseRelPdu::decode(src)?;
204                FastPathInputEvent::MouseEventRel(mouse_event)
205            }
206            FastpathInputEventType::Sync => {
207                let flags = SynchronizeFlags::from_bits(flags)
208                    .ok_or_else(|| invalid_field_err!("flags", "input synchronize flags unsupported"))?;
209                FastPathInputEvent::SyncEvent(flags)
210            }
211            FastpathInputEventType::Unicode => {
212                ensure_size!(in: src, size: 2);
213                let code = src.read_u16();
214                let flags = KeyboardFlags::from_bits(flags)
215                    .ok_or_else(|| invalid_field_err!("flags", "input keyboard flags unsupported"))?;
216                FastPathInputEvent::UnicodeKeyboardEvent(flags, code)
217            }
218            FastpathInputEventType::QoeTimestamp => {
219                ensure_size!(in: src, size: 4);
220                let code = src.read_u32();
221                FastPathInputEvent::QoeEvent(code)
222            }
223        };
224        Ok(event)
225    }
226}
227
228bitflags! {
229    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
230    pub struct KeyboardFlags: u8 {
231        const RELEASE = 0x01;
232        const EXTENDED = 0x02;
233        const EXTENDED1 = 0x04;
234    }
235}
236
237bitflags! {
238    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
239    pub struct SynchronizeFlags: u8 {
240        const SCROLL_LOCK = 0x01;
241        const NUM_LOCK = 0x02;
242        const CAPS_LOCK = 0x04;
243        const KANA_LOCK = 0x08;
244    }
245}
246
247#[derive(Debug, Clone, PartialEq, Eq)]
248pub struct FastPathInput(pub Vec<FastPathInputEvent>);
249
250impl FastPathInput {
251    const NAME: &'static str = "FastPathInput";
252}
253
254impl Encode for FastPathInput {
255    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
256        ensure_size!(in: dst, size: self.size());
257
258        if self.0.is_empty() {
259            return Err(other_err!("Empty fast-path input"));
260        }
261
262        let data_length = self.0.iter().map(Encode::size).sum::<usize>();
263        let header = FastPathInputHeader {
264            num_events: self.0.len() as u8,
265            flags: EncryptionFlags::empty(),
266            data_length,
267        };
268        header.encode(dst)?;
269
270        for event in self.0.iter() {
271            event.encode(dst)?;
272        }
273
274        Ok(())
275    }
276
277    fn name(&self) -> &'static str {
278        Self::NAME
279    }
280
281    fn size(&self) -> usize {
282        let data_length = self.0.iter().map(Encode::size).sum::<usize>();
283        let header = FastPathInputHeader {
284            num_events: self.0.len() as u8,
285            flags: EncryptionFlags::empty(),
286            data_length,
287        };
288        header.size() + data_length
289    }
290}
291
292impl<'de> Decode<'de> for FastPathInput {
293    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
294        let header = FastPathInputHeader::decode(src)?;
295        let events = (0..header.num_events)
296            .map(|_| FastPathInputEvent::decode(src))
297            .collect::<Result<Vec<_>, _>>()?;
298
299        Ok(Self(events))
300    }
301}