ironrdp_server/
handler.rs1use ironrdp_ainput as ainput;
2use ironrdp_pdu::input::fast_path::{self, SynchronizeFlags};
3use ironrdp_pdu::input::mouse::PointerFlags;
4use ironrdp_pdu::input::mouse_rel::PointerRelFlags;
5use ironrdp_pdu::input::mouse_x::PointerXFlags;
6use ironrdp_pdu::input::sync::SyncToggleFlags;
7use ironrdp_pdu::input::{scan_code, unicode, MousePdu, MouseRelPdu, MouseXPdu};
8
9#[derive(Debug)]
14pub enum KeyboardEvent {
15 Pressed { code: u8, extended: bool },
16 Released { code: u8, extended: bool },
17 UnicodePressed(u16),
18 UnicodeReleased(u16),
19 Synchronize(SynchronizeFlags),
20}
21
22#[derive(Debug)]
27pub enum MouseEvent {
28 Move { x: u16, y: u16 },
29 RightPressed,
30 RightReleased,
31 LeftPressed,
32 LeftReleased,
33 MiddlePressed,
34 MiddleReleased,
35 Button4Pressed,
36 Button4Released,
37 Button5Pressed,
38 Button5Released,
39 VerticalScroll { value: i16 },
40 Scroll { x: i32, y: i32 },
41 RelMove { x: i32, y: i32 },
42}
43
44pub trait RdpServerInputHandler: Send {
74 fn keyboard(&mut self, event: KeyboardEvent);
75 fn mouse(&mut self, event: MouseEvent);
76}
77
78impl From<(u8, fast_path::KeyboardFlags)> for KeyboardEvent {
79 fn from((key, flags): (u8, fast_path::KeyboardFlags)) -> Self {
80 let extended = flags.contains(fast_path::KeyboardFlags::EXTENDED);
81 if flags.contains(fast_path::KeyboardFlags::RELEASE) {
82 KeyboardEvent::Released { code: key, extended }
83 } else {
84 KeyboardEvent::Pressed { code: key, extended }
85 }
86 }
87}
88
89impl From<(u16, fast_path::KeyboardFlags)> for KeyboardEvent {
90 fn from((key, flags): (u16, fast_path::KeyboardFlags)) -> Self {
91 if flags.contains(fast_path::KeyboardFlags::RELEASE) {
92 KeyboardEvent::UnicodeReleased(key)
93 } else {
94 KeyboardEvent::UnicodePressed(key)
95 }
96 }
97}
98
99impl From<(u16, scan_code::KeyboardFlags)> for KeyboardEvent {
100 #[expect(
101 clippy::as_conversions,
102 clippy::cast_possible_truncation,
103 reason = "we are truncating the value on purpose"
104 )]
105 fn from((key, flags): (u16, scan_code::KeyboardFlags)) -> Self {
106 let extended = flags.contains(scan_code::KeyboardFlags::EXTENDED);
107
108 if flags.contains(scan_code::KeyboardFlags::RELEASE) {
109 KeyboardEvent::Released {
110 code: key as u8,
111 extended,
112 }
113 } else {
114 KeyboardEvent::Pressed {
115 code: key as u8,
116 extended,
117 }
118 }
119 }
120}
121
122impl From<(u16, unicode::KeyboardFlags)> for KeyboardEvent {
123 fn from((key, flags): (u16, unicode::KeyboardFlags)) -> Self {
124 if flags.contains(unicode::KeyboardFlags::RELEASE) {
125 KeyboardEvent::UnicodeReleased(key)
126 } else {
127 KeyboardEvent::UnicodePressed(key)
128 }
129 }
130}
131
132impl From<SynchronizeFlags> for KeyboardEvent {
133 fn from(value: SynchronizeFlags) -> Self {
134 KeyboardEvent::Synchronize(value)
135 }
136}
137
138impl From<SyncToggleFlags> for KeyboardEvent {
139 #[expect(
140 clippy::as_conversions,
141 clippy::cast_possible_truncation,
142 reason = "we are truncating the value on purpose"
143 )]
144 fn from(value: SyncToggleFlags) -> Self {
145 KeyboardEvent::Synchronize(SynchronizeFlags::from_bits_truncate(value.bits() as u8))
146 }
147}
148
149impl From<MousePdu> for MouseEvent {
150 fn from(value: MousePdu) -> Self {
151 if value.flags.contains(PointerFlags::LEFT_BUTTON) {
152 if value.flags.contains(PointerFlags::DOWN) {
153 MouseEvent::LeftPressed
154 } else {
155 MouseEvent::LeftReleased
156 }
157 } else if value.flags.contains(PointerFlags::RIGHT_BUTTON) {
158 if value.flags.contains(PointerFlags::DOWN) {
159 MouseEvent::RightPressed
160 } else {
161 MouseEvent::RightReleased
162 }
163 } else if value.flags.contains(PointerFlags::VERTICAL_WHEEL) {
164 MouseEvent::VerticalScroll {
165 value: value.number_of_wheel_rotation_units,
166 }
167 } else {
168 MouseEvent::Move {
169 x: value.x_position,
170 y: value.y_position,
171 }
172 }
173 }
174}
175
176impl From<MouseXPdu> for MouseEvent {
177 fn from(value: MouseXPdu) -> Self {
178 if value.flags.contains(PointerXFlags::BUTTON1) {
179 if value.flags.contains(PointerXFlags::DOWN) {
180 MouseEvent::LeftPressed
181 } else {
182 MouseEvent::LeftReleased
183 }
184 } else if value.flags.contains(PointerXFlags::BUTTON2) {
185 if value.flags.contains(PointerXFlags::DOWN) {
186 MouseEvent::RightPressed
187 } else {
188 MouseEvent::RightReleased
189 }
190 } else {
191 MouseEvent::Move {
192 x: value.x_position,
193 y: value.y_position,
194 }
195 }
196 }
197}
198
199impl From<MouseRelPdu> for MouseEvent {
200 fn from(value: MouseRelPdu) -> Self {
201 if value.flags.contains(PointerRelFlags::BUTTON1) {
202 if value.flags.contains(PointerRelFlags::DOWN) {
203 MouseEvent::LeftPressed
204 } else {
205 MouseEvent::LeftReleased
206 }
207 } else if value.flags.contains(PointerRelFlags::BUTTON2) {
208 if value.flags.contains(PointerRelFlags::DOWN) {
209 MouseEvent::RightPressed
210 } else {
211 MouseEvent::RightReleased
212 }
213 } else if value.flags.contains(PointerRelFlags::BUTTON3) {
214 if value.flags.contains(PointerRelFlags::DOWN) {
215 MouseEvent::MiddlePressed
216 } else {
217 MouseEvent::MiddleReleased
218 }
219 } else if value.flags.contains(PointerRelFlags::XBUTTON1) {
220 if value.flags.contains(PointerRelFlags::DOWN) {
221 MouseEvent::Button4Pressed
222 } else {
223 MouseEvent::Button4Released
224 }
225 } else if value.flags.contains(PointerRelFlags::XBUTTON2) {
226 if value.flags.contains(PointerRelFlags::DOWN) {
227 MouseEvent::Button5Pressed
228 } else {
229 MouseEvent::Button5Released
230 }
231 } else {
232 MouseEvent::RelMove {
233 x: value.x_delta.into(),
234 y: value.y_delta.into(),
235 }
236 }
237 }
238}
239
240impl From<ainput::MousePdu> for MouseEvent {
241 fn from(value: ainput::MousePdu) -> Self {
242 use ainput::MouseEventFlags;
243
244 if value.flags.contains(MouseEventFlags::BUTTON1) {
245 if value.flags.contains(MouseEventFlags::DOWN) {
246 MouseEvent::LeftPressed
247 } else {
248 MouseEvent::LeftReleased
249 }
250 } else if value.flags.contains(MouseEventFlags::BUTTON2) {
251 if value.flags.contains(MouseEventFlags::DOWN) {
252 MouseEvent::RightPressed
253 } else {
254 MouseEvent::RightReleased
255 }
256 } else if value.flags.contains(MouseEventFlags::BUTTON3) {
257 if value.flags.contains(MouseEventFlags::DOWN) {
258 MouseEvent::MiddlePressed
259 } else {
260 MouseEvent::MiddleReleased
261 }
262 } else if value.flags.contains(MouseEventFlags::WHEEL) {
263 MouseEvent::Scroll { x: value.x, y: value.y }
264 } else if value.flags.contains(MouseEventFlags::REL) {
265 MouseEvent::RelMove { x: value.x, y: value.y }
266 } else if value.flags.contains(MouseEventFlags::MOVE) {
267 MouseEvent::Move {
269 x: value.x.try_into().unwrap_or(0),
270 y: value.y.try_into().unwrap_or(0),
271 }
272 } else {
273 MouseEvent::Move { x: 0, y: 0 }
274 }
275 }
276}