1use std::io;
2
3use ironrdp_core::{
4 cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, read_padding, write_padding, Decode,
5 DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor,
6};
7use num_derive::FromPrimitive;
8use num_traits::FromPrimitive 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 ;
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(cast_length!("input events count", self.0.len())?);
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 = usize::from(src.read_u16());
65 read_padding!(src, 2);
66
67 let events = core::iter::repeat_with(|| InputEvent::decode(src))
68 .take(number_of_events)
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 + 2 ;
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); dst.write_u16(InputEventType::from(self).as_u16());
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(); 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)]
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 InputEventType {
162 #[expect(
163 clippy::as_conversions,
164 reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive"
165 )]
166 fn as_u16(self) -> u16 {
167 self as u16
168 }
169}
170
171impl From<&InputEvent> for InputEventType {
172 fn from(event: &InputEvent) -> Self {
173 match event {
174 InputEvent::Sync(_) => Self::Sync,
175 InputEvent::Unused(_) => Self::Unused,
176 InputEvent::ScanCode(_) => Self::ScanCode,
177 InputEvent::Unicode(_) => Self::Unicode,
178 InputEvent::Mouse(_) => Self::Mouse,
179 InputEvent::MouseX(_) => Self::MouseX,
180 InputEvent::MouseRel(_) => Self::MouseRel,
181 }
182 }
183}
184
185#[derive(Debug, Error)]
186pub enum InputEventError {
187 #[error("IO error")]
188 IOError(#[from] io::Error),
189 #[error("invalid Input Event type: {0}")]
190 InvalidInputEventType(u16),
191 #[error("encryption not supported")]
192 EncryptionNotSupported,
193 #[error("event code not supported {0}")]
194 EventCodeUnsupported(u8),
195 #[error("keyboard flags not supported {0}")]
196 KeyboardFlagsUnsupported(u8),
197 #[error("synchronize flags not supported {0}")]
198 SynchronizeFlagsUnsupported(u8),
199 #[error("Fast-Path Input Event PDU is empty")]
200 EmptyFastPathInput,
201}