ironrdp_pdu/input/
mod.rs

1use std::io;
2
3use ironrdp_core::{
4    ensure_fixed_part_size, ensure_size, invalid_field_err, read_padding, write_padding, Decode, DecodeResult, Encode,
5    EncodeResult, ReadCursor, WriteCursor,
6};
7use num_derive::{FromPrimitive, ToPrimitive};
8use num_traits::{FromPrimitive as _, ToPrimitive as _};
9use thiserror::Error;
10
11pub mod fast_path;
12pub mod mouse;
13pub mod mouse_rel;
14pub mod mouse_x;
15pub mod scan_code;
16pub mod sync;
17pub mod unicode;
18pub mod unused;
19
20pub use self::mouse::MousePdu;
21pub use self::mouse_rel::MouseRelPdu;
22pub use self::mouse_x::MouseXPdu;
23pub use self::scan_code::ScanCodePdu;
24pub use self::sync::SyncPdu;
25pub use self::unicode::UnicodePdu;
26pub use self::unused::UnusedPdu;
27
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct InputEventPdu(pub Vec<InputEvent>);
30
31impl InputEventPdu {
32    const NAME: &'static str = "InputEventPdu";
33
34    const FIXED_PART_SIZE: usize = 4 /* nEvents */;
35}
36
37impl Encode for InputEventPdu {
38    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
39        ensure_size!(in: dst, size: self.size());
40
41        dst.write_u16(self.0.len() as u16);
42        write_padding!(dst, 2);
43
44        for event in self.0.iter() {
45            event.encode(dst)?;
46        }
47
48        Ok(())
49    }
50
51    fn name(&self) -> &'static str {
52        Self::NAME
53    }
54
55    fn size(&self) -> usize {
56        4 + self.0.iter().map(Encode::size).sum::<usize>()
57    }
58}
59
60impl<'de> Decode<'de> for InputEventPdu {
61    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
62        ensure_fixed_part_size!(in: src);
63
64        let number_of_events = src.read_u16();
65        read_padding!(src, 2);
66
67        let events = (0..number_of_events)
68            .map(|_| InputEvent::decode(src))
69            .collect::<Result<Vec<_>, _>>()?;
70
71        Ok(Self(events))
72    }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq)]
76pub enum InputEvent {
77    Sync(SyncPdu),
78    Unused(UnusedPdu),
79    ScanCode(ScanCodePdu),
80    Unicode(UnicodePdu),
81    Mouse(MousePdu),
82    MouseX(MouseXPdu),
83    MouseRel(MouseRelPdu),
84}
85
86impl InputEvent {
87    const NAME: &'static str = "InputEvent";
88
89    const FIXED_PART_SIZE: usize = 4 /* eventTime */ + 2 /* eventType */;
90}
91
92impl Encode for InputEvent {
93    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
94        ensure_fixed_part_size!(in: dst);
95
96        dst.write_u32(0); // event time is ignored by a server
97        dst.write_u16(InputEventType::from(self).to_u16().unwrap());
98
99        match self {
100            Self::Sync(pdu) => pdu.encode(dst),
101            Self::Unused(pdu) => pdu.encode(dst),
102            Self::ScanCode(pdu) => pdu.encode(dst),
103            Self::Unicode(pdu) => pdu.encode(dst),
104            Self::Mouse(pdu) => pdu.encode(dst),
105            Self::MouseX(pdu) => pdu.encode(dst),
106            Self::MouseRel(pdu) => pdu.encode(dst),
107        }
108    }
109
110    fn name(&self) -> &'static str {
111        Self::NAME
112    }
113
114    fn size(&self) -> usize {
115        Self::FIXED_PART_SIZE
116            + match self {
117                Self::Sync(pdu) => pdu.size(),
118                Self::Unused(pdu) => pdu.size(),
119                Self::ScanCode(pdu) => pdu.size(),
120                Self::Unicode(pdu) => pdu.size(),
121                Self::Mouse(pdu) => pdu.size(),
122                Self::MouseX(pdu) => pdu.size(),
123                Self::MouseRel(pdu) => pdu.size(),
124            }
125    }
126}
127
128impl<'de> Decode<'de> for InputEvent {
129    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
130        ensure_fixed_part_size!(in: src);
131
132        let _event_time = src.read_u32(); // ignored by a server
133        let event_type = src.read_u16();
134        let event_type = InputEventType::from_u16(event_type)
135            .ok_or_else(|| invalid_field_err!("eventType", "invalid input event type"))?;
136
137        match event_type {
138            InputEventType::Sync => Ok(Self::Sync(SyncPdu::decode(src)?)),
139            InputEventType::Unused => Ok(Self::Unused(UnusedPdu::decode(src)?)),
140            InputEventType::ScanCode => Ok(Self::ScanCode(ScanCodePdu::decode(src)?)),
141            InputEventType::Unicode => Ok(Self::Unicode(UnicodePdu::decode(src)?)),
142            InputEventType::Mouse => Ok(Self::Mouse(MousePdu::decode(src)?)),
143            InputEventType::MouseX => Ok(Self::MouseX(MouseXPdu::decode(src)?)),
144            InputEventType::MouseRel => Ok(Self::MouseRel(MouseRelPdu::decode(src)?)),
145        }
146    }
147}
148
149#[derive(Debug, Copy, Clone, PartialEq, FromPrimitive, ToPrimitive)]
150#[repr(u16)]
151enum InputEventType {
152    Sync = 0x0000,
153    Unused = 0x0002,
154    ScanCode = 0x0004,
155    Unicode = 0x0005,
156    Mouse = 0x8001,
157    MouseX = 0x8002,
158    MouseRel = 0x8004,
159}
160
161impl From<&InputEvent> for InputEventType {
162    fn from(event: &InputEvent) -> Self {
163        match event {
164            InputEvent::Sync(_) => Self::Sync,
165            InputEvent::Unused(_) => Self::Unused,
166            InputEvent::ScanCode(_) => Self::ScanCode,
167            InputEvent::Unicode(_) => Self::Unicode,
168            InputEvent::Mouse(_) => Self::Mouse,
169            InputEvent::MouseX(_) => Self::MouseX,
170            InputEvent::MouseRel(_) => Self::MouseRel,
171        }
172    }
173}
174
175#[derive(Debug, Error)]
176pub enum InputEventError {
177    #[error("IO error")]
178    IOError(#[from] io::Error),
179    #[error("invalid Input Event type: {0}")]
180    InvalidInputEventType(u16),
181    #[error("encryption not supported")]
182    EncryptionNotSupported,
183    #[error("event code not supported {0}")]
184    EventCodeUnsupported(u8),
185    #[error("keyboard flags not supported {0}")]
186    KeyboardFlagsUnsupported(u8),
187    #[error("synchronize flags not supported {0}")]
188    SynchronizeFlagsUnsupported(u8),
189    #[error("Fast-Path Input Event PDU is empty")]
190    EmptyFastPathInput,
191}