/src/FreeRDP/libfreerdp/core/input.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * FreeRDP: A Remote Desktop Protocol Implementation |
3 | | * Input PDUs |
4 | | * |
5 | | * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com> |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | #include <time.h> |
21 | | #include <freerdp/config.h> |
22 | | |
23 | | #include <winpr/crt.h> |
24 | | #include <winpr/assert.h> |
25 | | |
26 | | #include <freerdp/input.h> |
27 | | #include <freerdp/log.h> |
28 | | |
29 | | #include "message.h" |
30 | | |
31 | | #include "input.h" |
32 | | |
33 | | #define TAG FREERDP_TAG("core") |
34 | | |
35 | | /* Input Events */ |
36 | 0 | #define INPUT_EVENT_SYNC 0x0000 |
37 | 0 | #define INPUT_EVENT_SCANCODE 0x0004 |
38 | 0 | #define INPUT_EVENT_UNICODE 0x0005 |
39 | 0 | #define INPUT_EVENT_MOUSE 0x8001 |
40 | 0 | #define INPUT_EVENT_MOUSEX 0x8002 |
41 | 0 | #define INPUT_EVENT_MOUSEREL 0x8004 |
42 | | |
43 | | static void rdp_write_client_input_pdu_header(wStream* s, UINT16 number) |
44 | 0 | { |
45 | 0 | WINPR_ASSERT(s); |
46 | 0 | WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 4); |
47 | 0 | Stream_Write_UINT16(s, number); /* numberEvents (2 bytes) */ |
48 | 0 | Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */ |
49 | 0 | } |
50 | | |
51 | | static void rdp_write_input_event_header(wStream* s, UINT32 time, UINT16 type) |
52 | 0 | { |
53 | 0 | WINPR_ASSERT(s); |
54 | 0 | WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 6); |
55 | 0 | Stream_Write_UINT32(s, time); /* eventTime (4 bytes) */ |
56 | 0 | Stream_Write_UINT16(s, type); /* messageType (2 bytes) */ |
57 | 0 | } |
58 | | |
59 | | static wStream* rdp_client_input_pdu_init(rdpRdp* rdp, UINT16 type, UINT16* sec_flags) |
60 | 0 | { |
61 | 0 | wStream* s = rdp_data_pdu_init(rdp, sec_flags); |
62 | |
|
63 | 0 | if (!s) |
64 | 0 | return NULL; |
65 | | |
66 | 0 | rdp_write_client_input_pdu_header(s, 1); |
67 | 0 | rdp_write_input_event_header(s, 0, type); |
68 | 0 | return s; |
69 | 0 | } |
70 | | |
71 | | static BOOL rdp_send_client_input_pdu(rdpRdp* rdp, wStream* s, UINT16 sec_flags) |
72 | 0 | { |
73 | 0 | WINPR_ASSERT(rdp); |
74 | 0 | WINPR_ASSERT(rdp->mcs); |
75 | 0 | return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_INPUT, rdp->mcs->userId, sec_flags); |
76 | 0 | } |
77 | | |
78 | | static void input_write_synchronize_event(wStream* s, UINT32 flags) |
79 | 0 | { |
80 | 0 | WINPR_ASSERT(s); |
81 | 0 | WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 6); |
82 | 0 | Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */ |
83 | 0 | Stream_Write_UINT32(s, flags); /* toggleFlags (4 bytes) */ |
84 | 0 | } |
85 | | |
86 | | static BOOL input_ensure_client_running(rdpInput* input) |
87 | 0 | { |
88 | 0 | WINPR_ASSERT(input); |
89 | 0 | if (freerdp_shall_disconnect_context(input->context)) |
90 | 0 | { |
91 | 0 | WLog_WARN(TAG, "[APPLICATION BUG] input functions called after the session terminated"); |
92 | 0 | return FALSE; |
93 | 0 | } |
94 | 0 | return TRUE; |
95 | 0 | } |
96 | | |
97 | | static BOOL input_send_synchronize_event(rdpInput* input, UINT32 flags) |
98 | 0 | { |
99 | 0 | UINT16 sec_flags = 0; |
100 | |
|
101 | 0 | if (!input || !input->context) |
102 | 0 | return FALSE; |
103 | | |
104 | 0 | rdpRdp* rdp = input->context->rdp; |
105 | |
|
106 | 0 | if (!input_ensure_client_running(input)) |
107 | 0 | return FALSE; |
108 | | |
109 | 0 | wStream* s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_SYNC, &sec_flags); |
110 | |
|
111 | 0 | if (!s) |
112 | 0 | return FALSE; |
113 | | |
114 | 0 | input_write_synchronize_event(s, flags); |
115 | 0 | return rdp_send_client_input_pdu(rdp, s, sec_flags); |
116 | 0 | } |
117 | | |
118 | | static void input_write_keyboard_event(wStream* s, UINT16 flags, UINT16 code) |
119 | 0 | { |
120 | 0 | WINPR_ASSERT(s); |
121 | 0 | WINPR_ASSERT(code <= UINT8_MAX); |
122 | | |
123 | 0 | Stream_Write_UINT16(s, flags); /* keyboardFlags (2 bytes) */ |
124 | 0 | Stream_Write_UINT16(s, code); /* keyCode (2 bytes) */ |
125 | 0 | Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */ |
126 | 0 | } |
127 | | |
128 | | static BOOL input_send_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code) |
129 | 0 | { |
130 | 0 | UINT16 sec_flags = 0; |
131 | 0 | wStream* s = NULL; |
132 | 0 | rdpRdp* rdp = NULL; |
133 | |
|
134 | 0 | if (!input || !input->context) |
135 | 0 | return FALSE; |
136 | | |
137 | 0 | rdp = input->context->rdp; |
138 | |
|
139 | 0 | if (!input_ensure_client_running(input)) |
140 | 0 | return FALSE; |
141 | | |
142 | 0 | s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_SCANCODE, &sec_flags); |
143 | |
|
144 | 0 | if (!s) |
145 | 0 | return FALSE; |
146 | | |
147 | 0 | input_write_keyboard_event(s, flags, code); |
148 | 0 | return rdp_send_client_input_pdu(rdp, s, sec_flags); |
149 | 0 | } |
150 | | |
151 | | static void input_write_unicode_keyboard_event(wStream* s, UINT16 flags, UINT16 code) |
152 | 0 | { |
153 | 0 | Stream_Write_UINT16(s, flags); /* keyboardFlags (2 bytes) */ |
154 | 0 | Stream_Write_UINT16(s, code); /* unicodeCode (2 bytes) */ |
155 | 0 | Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */ |
156 | 0 | } |
157 | | |
158 | | static BOOL input_send_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) |
159 | 0 | { |
160 | 0 | UINT16 sec_flags = 0; |
161 | 0 | wStream* s = NULL; |
162 | 0 | rdpRdp* rdp = NULL; |
163 | |
|
164 | 0 | if (!input || !input->context) |
165 | 0 | return FALSE; |
166 | | |
167 | 0 | if (!input_ensure_client_running(input)) |
168 | 0 | return FALSE; |
169 | | |
170 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_UnicodeInput)) |
171 | 0 | { |
172 | 0 | WLog_WARN(TAG, "Unicode input not supported by server."); |
173 | 0 | return FALSE; |
174 | 0 | } |
175 | | |
176 | 0 | rdp = input->context->rdp; |
177 | 0 | s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_UNICODE, &sec_flags); |
178 | |
|
179 | 0 | if (!s) |
180 | 0 | return FALSE; |
181 | | |
182 | 0 | input_write_unicode_keyboard_event(s, flags, code); |
183 | 0 | return rdp_send_client_input_pdu(rdp, s, sec_flags); |
184 | 0 | } |
185 | | |
186 | | static void input_write_mouse_event(wStream* s, UINT16 flags, UINT16 x, UINT16 y) |
187 | 0 | { |
188 | 0 | Stream_Write_UINT16(s, flags); /* pointerFlags (2 bytes) */ |
189 | 0 | Stream_Write_UINT16(s, x); /* xPos (2 bytes) */ |
190 | 0 | Stream_Write_UINT16(s, y); /* yPos (2 bytes) */ |
191 | 0 | } |
192 | | |
193 | | static BOOL input_send_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) |
194 | 0 | { |
195 | 0 | UINT16 sec_flags = 0; |
196 | |
|
197 | 0 | if (!input || !input->context || !input->context->settings) |
198 | 0 | return FALSE; |
199 | | |
200 | 0 | rdpRdp* rdp = input->context->rdp; |
201 | |
|
202 | 0 | if (!input_ensure_client_running(input)) |
203 | 0 | return FALSE; |
204 | | |
205 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasHorizontalWheel)) |
206 | 0 | { |
207 | 0 | if (flags & PTR_FLAGS_HWHEEL) |
208 | 0 | { |
209 | 0 | WLog_WARN(TAG, |
210 | 0 | "skip mouse event %" PRIu16 "x%" PRIu16 " flags=0x%04" PRIX16 |
211 | 0 | ", no horizontal mouse wheel supported", |
212 | 0 | x, y, flags); |
213 | 0 | return TRUE; |
214 | 0 | } |
215 | 0 | } |
216 | | |
217 | 0 | wStream* s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_MOUSE, &sec_flags); |
218 | |
|
219 | 0 | if (!s) |
220 | 0 | return FALSE; |
221 | | |
222 | 0 | input_write_mouse_event(s, flags, x, y); |
223 | 0 | return rdp_send_client_input_pdu(rdp, s, sec_flags); |
224 | 0 | } |
225 | | |
226 | | static BOOL input_send_relmouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, INT16 yDelta) |
227 | 0 | { |
228 | 0 | UINT16 sec_flags = 0; |
229 | 0 | wStream* s = NULL; |
230 | 0 | rdpRdp* rdp = NULL; |
231 | |
|
232 | 0 | if (!input || !input->context || !input->context->settings) |
233 | 0 | return FALSE; |
234 | | |
235 | 0 | rdp = input->context->rdp; |
236 | |
|
237 | 0 | if (!input_ensure_client_running(input)) |
238 | 0 | return FALSE; |
239 | | |
240 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasRelativeMouseEvent)) |
241 | 0 | { |
242 | 0 | WLog_ERR(TAG, "Sending relative mouse event, but no support for that"); |
243 | 0 | return FALSE; |
244 | 0 | } |
245 | | |
246 | 0 | s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_MOUSEREL, &sec_flags); |
247 | |
|
248 | 0 | if (!s) |
249 | 0 | return FALSE; |
250 | | |
251 | 0 | Stream_Write_UINT16(s, flags); /* pointerFlags (2 bytes) */ |
252 | 0 | Stream_Write_INT16(s, xDelta); /* xDelta (2 bytes) */ |
253 | 0 | Stream_Write_INT16(s, yDelta); /* yDelta (2 bytes) */ |
254 | | |
255 | 0 | return rdp_send_client_input_pdu(rdp, s, sec_flags); |
256 | 0 | } |
257 | | |
258 | | static void input_write_extended_mouse_event(wStream* s, UINT16 flags, UINT16 x, UINT16 y) |
259 | 0 | { |
260 | 0 | Stream_Write_UINT16(s, flags); /* pointerFlags (2 bytes) */ |
261 | 0 | Stream_Write_UINT16(s, x); /* xPos (2 bytes) */ |
262 | 0 | Stream_Write_UINT16(s, y); /* yPos (2 bytes) */ |
263 | 0 | } |
264 | | |
265 | | static BOOL input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) |
266 | 0 | { |
267 | 0 | UINT16 sec_flags = 0; |
268 | |
|
269 | 0 | WINPR_ASSERT(input); |
270 | 0 | WINPR_ASSERT(input->context); |
271 | 0 | WINPR_ASSERT(input->context->settings); |
272 | | |
273 | 0 | rdpRdp* rdp = input->context->rdp; |
274 | 0 | WINPR_ASSERT(rdp); |
275 | | |
276 | 0 | if (!input_ensure_client_running(input)) |
277 | 0 | return FALSE; |
278 | | |
279 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasExtendedMouseEvent)) |
280 | 0 | { |
281 | 0 | WLog_WARN(TAG, |
282 | 0 | "skip extended mouse event %" PRIu16 "x%" PRIu16 " flags=0x%04" PRIX16 |
283 | 0 | ", no extended mouse events supported", |
284 | 0 | x, y, flags); |
285 | 0 | return TRUE; |
286 | 0 | } |
287 | | |
288 | 0 | wStream* s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_MOUSEX, &sec_flags); |
289 | |
|
290 | 0 | if (!s) |
291 | 0 | return FALSE; |
292 | | |
293 | 0 | input_write_extended_mouse_event(s, flags, x, y); |
294 | 0 | return rdp_send_client_input_pdu(rdp, s, sec_flags); |
295 | 0 | } |
296 | | |
297 | | static BOOL input_send_focus_in_event(rdpInput* input, UINT16 toggleStates) |
298 | 0 | { |
299 | | /* send a tab up like mstsc.exe */ |
300 | 0 | if (!input_send_keyboard_event(input, KBD_FLAGS_RELEASE, 0x0f)) |
301 | 0 | return FALSE; |
302 | | |
303 | | /* send the toggle key states */ |
304 | 0 | if (!input_send_synchronize_event(input, (toggleStates & 0x1F))) |
305 | 0 | return FALSE; |
306 | | |
307 | | /* send another tab up like mstsc.exe */ |
308 | 0 | return input_send_keyboard_event(input, KBD_FLAGS_RELEASE, 0x0f); |
309 | 0 | } |
310 | | |
311 | | static BOOL input_send_keyboard_pause_event(rdpInput* input) |
312 | 0 | { |
313 | | /* In ancient days, pause-down without control sent E1 1D 45 E1 9D C5, |
314 | | * and pause-up sent nothing. However, reverse engineering mstsc shows |
315 | | * it sending the following sequence: |
316 | | */ |
317 | | |
318 | | /* Control down (0x1D) */ |
319 | 0 | if (!input_send_keyboard_event(input, KBD_FLAGS_EXTENDED1, |
320 | 0 | RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL))) |
321 | 0 | return FALSE; |
322 | | |
323 | | /* Numlock down (0x45) */ |
324 | 0 | if (!input_send_keyboard_event(input, 0, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK))) |
325 | 0 | return FALSE; |
326 | | |
327 | | /* Control up (0x1D) */ |
328 | 0 | if (!input_send_keyboard_event(input, KBD_FLAGS_RELEASE | KBD_FLAGS_EXTENDED1, |
329 | 0 | RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL))) |
330 | 0 | return FALSE; |
331 | | |
332 | | /* Numlock up (0x45) */ |
333 | 0 | return input_send_keyboard_event(input, KBD_FLAGS_RELEASE, |
334 | 0 | RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); |
335 | 0 | } |
336 | | |
337 | | static BOOL input_send_fastpath_synchronize_event(rdpInput* input, UINT32 flags) |
338 | 0 | { |
339 | 0 | UINT16 sec_flags = 0; |
340 | 0 | wStream* s = NULL; |
341 | 0 | rdpRdp* rdp = NULL; |
342 | |
|
343 | 0 | WINPR_ASSERT(input); |
344 | 0 | WINPR_ASSERT(input->context); |
345 | | |
346 | 0 | rdp = input->context->rdp; |
347 | 0 | WINPR_ASSERT(rdp); |
348 | | |
349 | 0 | if (!input_ensure_client_running(input)) |
350 | 0 | return FALSE; |
351 | | |
352 | | /* The FastPath Synchronization eventFlags has identical values as SlowPath */ |
353 | 0 | s = fastpath_input_pdu_init(rdp->fastpath, (BYTE)flags, FASTPATH_INPUT_EVENT_SYNC, &sec_flags); |
354 | |
|
355 | 0 | if (!s) |
356 | 0 | return FALSE; |
357 | | |
358 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags); |
359 | 0 | } |
360 | | |
361 | | static BOOL input_send_fastpath_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code) |
362 | 0 | { |
363 | 0 | UINT16 sec_flags = 0; |
364 | 0 | wStream* s = NULL; |
365 | 0 | BYTE eventFlags = 0; |
366 | 0 | rdpRdp* rdp = NULL; |
367 | |
|
368 | 0 | WINPR_ASSERT(input); |
369 | 0 | WINPR_ASSERT(input->context); |
370 | | |
371 | 0 | rdp = input->context->rdp; |
372 | 0 | WINPR_ASSERT(rdp); |
373 | | |
374 | 0 | if (!input_ensure_client_running(input)) |
375 | 0 | return FALSE; |
376 | | |
377 | 0 | eventFlags |= (flags & KBD_FLAGS_RELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0; |
378 | 0 | eventFlags |= (flags & KBD_FLAGS_EXTENDED) ? FASTPATH_INPUT_KBDFLAGS_EXTENDED : 0; |
379 | 0 | eventFlags |= (flags & KBD_FLAGS_EXTENDED1) ? FASTPATH_INPUT_KBDFLAGS_PREFIX_E1 : 0; |
380 | 0 | s = fastpath_input_pdu_init(rdp->fastpath, eventFlags, FASTPATH_INPUT_EVENT_SCANCODE, |
381 | 0 | &sec_flags); |
382 | |
|
383 | 0 | if (!s) |
384 | 0 | return FALSE; |
385 | | |
386 | 0 | WINPR_ASSERT(code <= UINT8_MAX); |
387 | 0 | Stream_Write_UINT8(s, code); /* keyCode (1 byte) */ |
388 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags); |
389 | 0 | } |
390 | | |
391 | | static BOOL input_send_fastpath_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) |
392 | 0 | { |
393 | 0 | UINT16 sec_flags = 0; |
394 | 0 | wStream* s = NULL; |
395 | 0 | BYTE eventFlags = 0; |
396 | 0 | rdpRdp* rdp = NULL; |
397 | |
|
398 | 0 | WINPR_ASSERT(input); |
399 | 0 | WINPR_ASSERT(input->context); |
400 | 0 | WINPR_ASSERT(input->context->settings); |
401 | | |
402 | 0 | rdp = input->context->rdp; |
403 | 0 | WINPR_ASSERT(rdp); |
404 | | |
405 | 0 | if (!input_ensure_client_running(input)) |
406 | 0 | return FALSE; |
407 | | |
408 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_UnicodeInput)) |
409 | 0 | { |
410 | 0 | WLog_WARN(TAG, "Unicode input not supported by server."); |
411 | 0 | return FALSE; |
412 | 0 | } |
413 | | |
414 | 0 | eventFlags |= (flags & KBD_FLAGS_RELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0; |
415 | 0 | s = fastpath_input_pdu_init(rdp->fastpath, eventFlags, FASTPATH_INPUT_EVENT_UNICODE, |
416 | 0 | &sec_flags); |
417 | |
|
418 | 0 | if (!s) |
419 | 0 | return FALSE; |
420 | | |
421 | 0 | Stream_Write_UINT16(s, code); /* unicodeCode (2 bytes) */ |
422 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags); |
423 | 0 | } |
424 | | |
425 | | static BOOL input_send_fastpath_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) |
426 | 0 | { |
427 | 0 | UINT16 sec_flags = 0; |
428 | 0 | wStream* s = NULL; |
429 | 0 | rdpRdp* rdp = NULL; |
430 | |
|
431 | 0 | WINPR_ASSERT(input); |
432 | 0 | WINPR_ASSERT(input->context); |
433 | 0 | WINPR_ASSERT(input->context->settings); |
434 | | |
435 | 0 | rdp = input->context->rdp; |
436 | 0 | WINPR_ASSERT(rdp); |
437 | | |
438 | 0 | if (!input_ensure_client_running(input)) |
439 | 0 | return FALSE; |
440 | | |
441 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasHorizontalWheel)) |
442 | 0 | { |
443 | 0 | if (flags & PTR_FLAGS_HWHEEL) |
444 | 0 | { |
445 | 0 | WLog_WARN(TAG, |
446 | 0 | "skip mouse event %" PRIu16 "x%" PRIu16 " flags=0x%04" PRIX16 |
447 | 0 | ", no horizontal mouse wheel supported", |
448 | 0 | x, y, flags); |
449 | 0 | return TRUE; |
450 | 0 | } |
451 | 0 | } |
452 | | |
453 | 0 | s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSE, &sec_flags); |
454 | |
|
455 | 0 | if (!s) |
456 | 0 | return FALSE; |
457 | | |
458 | 0 | input_write_mouse_event(s, flags, x, y); |
459 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags); |
460 | 0 | } |
461 | | |
462 | | static BOOL input_send_fastpath_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, |
463 | | UINT16 y) |
464 | 0 | { |
465 | 0 | UINT16 sec_flags = 0; |
466 | 0 | wStream* s = NULL; |
467 | 0 | rdpRdp* rdp = NULL; |
468 | |
|
469 | 0 | WINPR_ASSERT(input); |
470 | 0 | WINPR_ASSERT(input->context); |
471 | | |
472 | 0 | rdp = input->context->rdp; |
473 | 0 | WINPR_ASSERT(rdp); |
474 | | |
475 | 0 | if (!input_ensure_client_running(input)) |
476 | 0 | return FALSE; |
477 | | |
478 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasExtendedMouseEvent)) |
479 | 0 | { |
480 | 0 | WLog_WARN(TAG, |
481 | 0 | "skip extended mouse event %" PRIu16 "x%" PRIu16 " flags=0x%04" PRIX16 |
482 | 0 | ", no extended mouse events supported", |
483 | 0 | x, y, flags); |
484 | 0 | return TRUE; |
485 | 0 | } |
486 | | |
487 | 0 | s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSEX, &sec_flags); |
488 | |
|
489 | 0 | if (!s) |
490 | 0 | return FALSE; |
491 | | |
492 | 0 | input_write_extended_mouse_event(s, flags, x, y); |
493 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags); |
494 | 0 | } |
495 | | |
496 | | static BOOL input_send_fastpath_relmouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, |
497 | | INT16 yDelta) |
498 | 0 | { |
499 | 0 | UINT16 sec_flags = 0; |
500 | 0 | wStream* s = NULL; |
501 | 0 | rdpRdp* rdp = NULL; |
502 | |
|
503 | 0 | WINPR_ASSERT(input); |
504 | 0 | WINPR_ASSERT(input->context); |
505 | 0 | WINPR_ASSERT(input->context->settings); |
506 | | |
507 | 0 | rdp = input->context->rdp; |
508 | 0 | WINPR_ASSERT(rdp); |
509 | | |
510 | 0 | if (!input_ensure_client_running(input)) |
511 | 0 | return FALSE; |
512 | | |
513 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasRelativeMouseEvent)) |
514 | 0 | { |
515 | 0 | WLog_ERR(TAG, "Sending relative fastpath mouse event, but no support for that announced"); |
516 | 0 | return FALSE; |
517 | 0 | } |
518 | | |
519 | 0 | s = fastpath_input_pdu_init(rdp->fastpath, 0, TS_FP_RELPOINTER_EVENT, &sec_flags); |
520 | |
|
521 | 0 | if (!s) |
522 | 0 | return FALSE; |
523 | | |
524 | 0 | Stream_Write_UINT16(s, flags); /* pointerFlags (2 bytes) */ |
525 | 0 | Stream_Write_INT16(s, xDelta); /* xDelta (2 bytes) */ |
526 | 0 | Stream_Write_INT16(s, yDelta); /* yDelta (2 bytes) */ |
527 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags); |
528 | 0 | } |
529 | | |
530 | | static BOOL input_send_fastpath_qoe_event(rdpInput* input, UINT32 timestampMS) |
531 | 0 | { |
532 | 0 | WINPR_ASSERT(input); |
533 | 0 | WINPR_ASSERT(input->context); |
534 | 0 | WINPR_ASSERT(input->context->settings); |
535 | | |
536 | 0 | rdpRdp* rdp = input->context->rdp; |
537 | 0 | WINPR_ASSERT(rdp); |
538 | | |
539 | 0 | if (!input_ensure_client_running(input)) |
540 | 0 | return FALSE; |
541 | | |
542 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasQoeEvent)) |
543 | 0 | { |
544 | 0 | WLog_ERR(TAG, "Sending qoe event, but no support for that announced"); |
545 | 0 | return FALSE; |
546 | 0 | } |
547 | | |
548 | 0 | UINT16 sec_flags = 0; |
549 | 0 | wStream* s = fastpath_input_pdu_init(rdp->fastpath, 0, TS_FP_QOETIMESTAMP_EVENT, &sec_flags); |
550 | |
|
551 | 0 | if (!s) |
552 | 0 | return FALSE; |
553 | | |
554 | 0 | if (!Stream_EnsureRemainingCapacity(s, 4)) |
555 | 0 | { |
556 | 0 | Stream_Free(s, TRUE); |
557 | 0 | return FALSE; |
558 | 0 | } |
559 | | |
560 | 0 | Stream_Write_UINT32(s, timestampMS); |
561 | 0 | return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags); |
562 | 0 | } |
563 | | |
564 | | static BOOL input_send_fastpath_focus_in_event(rdpInput* input, UINT16 toggleStates) |
565 | 0 | { |
566 | 0 | UINT16 sec_flags = 0; |
567 | 0 | wStream* s = NULL; |
568 | 0 | BYTE eventFlags = 0; |
569 | 0 | rdpRdp* rdp = NULL; |
570 | |
|
571 | 0 | WINPR_ASSERT(input); |
572 | 0 | WINPR_ASSERT(input->context); |
573 | | |
574 | 0 | rdp = input->context->rdp; |
575 | 0 | WINPR_ASSERT(rdp); |
576 | | |
577 | 0 | if (!input_ensure_client_running(input)) |
578 | 0 | return FALSE; |
579 | | |
580 | 0 | s = fastpath_input_pdu_init_header(rdp->fastpath, &sec_flags); |
581 | |
|
582 | 0 | if (!s) |
583 | 0 | return FALSE; |
584 | | |
585 | | /* send a tab up like mstsc.exe */ |
586 | 0 | eventFlags = FASTPATH_INPUT_KBDFLAGS_RELEASE | FASTPATH_INPUT_EVENT_SCANCODE << 5; |
587 | 0 | Stream_Write_UINT8(s, eventFlags); /* Key Release event (1 byte) */ |
588 | 0 | Stream_Write_UINT8(s, 0x0f); /* keyCode (1 byte) */ |
589 | | /* send the toggle key states */ |
590 | 0 | eventFlags = (toggleStates & 0x1F) | FASTPATH_INPUT_EVENT_SYNC << 5; |
591 | 0 | Stream_Write_UINT8(s, eventFlags); /* toggle state (1 byte) */ |
592 | | /* send another tab up like mstsc.exe */ |
593 | 0 | eventFlags = FASTPATH_INPUT_KBDFLAGS_RELEASE | FASTPATH_INPUT_EVENT_SCANCODE << 5; |
594 | 0 | Stream_Write_UINT8(s, eventFlags); /* Key Release event (1 byte) */ |
595 | 0 | Stream_Write_UINT8(s, 0x0f); /* keyCode (1 byte) */ |
596 | 0 | return fastpath_send_multiple_input_pdu(rdp->fastpath, s, 3, sec_flags); |
597 | 0 | } |
598 | | |
599 | | static BOOL input_send_fastpath_keyboard_pause_event(rdpInput* input) |
600 | 0 | { |
601 | | /* In ancient days, pause-down without control sent E1 1D 45 E1 9D C5, |
602 | | * and pause-up sent nothing. However, reverse engineering mstsc shows |
603 | | * it sending the following sequence: |
604 | | */ |
605 | 0 | UINT16 sec_flags = 0; |
606 | 0 | wStream* s = NULL; |
607 | 0 | const BYTE keyDownEvent = FASTPATH_INPUT_EVENT_SCANCODE << 5; |
608 | 0 | const BYTE keyUpEvent = (FASTPATH_INPUT_EVENT_SCANCODE << 5) | FASTPATH_INPUT_KBDFLAGS_RELEASE; |
609 | 0 | rdpRdp* rdp = NULL; |
610 | |
|
611 | 0 | WINPR_ASSERT(input); |
612 | 0 | WINPR_ASSERT(input->context); |
613 | | |
614 | 0 | rdp = input->context->rdp; |
615 | 0 | WINPR_ASSERT(rdp); |
616 | | |
617 | 0 | if (!input_ensure_client_running(input)) |
618 | 0 | return FALSE; |
619 | | |
620 | 0 | s = fastpath_input_pdu_init_header(rdp->fastpath, &sec_flags); |
621 | |
|
622 | 0 | if (!s) |
623 | 0 | return FALSE; |
624 | | |
625 | | /* Control down (0x1D) */ |
626 | 0 | Stream_Write_UINT8(s, keyDownEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1); |
627 | 0 | Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)); |
628 | | /* Numlock down (0x45) */ |
629 | 0 | Stream_Write_UINT8(s, keyDownEvent); |
630 | 0 | Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); |
631 | | /* Control up (0x1D) */ |
632 | 0 | Stream_Write_UINT8(s, keyUpEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1); |
633 | 0 | Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)); |
634 | | /* Numlock down (0x45) */ |
635 | 0 | Stream_Write_UINT8(s, keyUpEvent); |
636 | 0 | Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)); |
637 | 0 | return fastpath_send_multiple_input_pdu(rdp->fastpath, s, 4, sec_flags); |
638 | 0 | } |
639 | | |
640 | | static BOOL input_recv_sync_event(rdpInput* input, wStream* s) |
641 | 0 | { |
642 | 0 | UINT32 toggleFlags = 0; |
643 | |
|
644 | 0 | WINPR_ASSERT(input); |
645 | 0 | WINPR_ASSERT(s); |
646 | | |
647 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
648 | 0 | return FALSE; |
649 | | |
650 | 0 | Stream_Seek(s, 2); /* pad2Octets (2 bytes) */ |
651 | 0 | Stream_Read_UINT32(s, toggleFlags); /* toggleFlags (4 bytes) */ |
652 | 0 | return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, toggleFlags); |
653 | 0 | } |
654 | | |
655 | | static BOOL input_recv_keyboard_event(rdpInput* input, wStream* s) |
656 | 0 | { |
657 | 0 | UINT16 keyboardFlags = 0; |
658 | 0 | UINT16 keyCode = 0; |
659 | |
|
660 | 0 | WINPR_ASSERT(input); |
661 | 0 | WINPR_ASSERT(s); |
662 | | |
663 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
664 | 0 | return FALSE; |
665 | | |
666 | 0 | Stream_Read_UINT16(s, keyboardFlags); /* keyboardFlags (2 bytes) */ |
667 | 0 | Stream_Read_UINT16(s, keyCode); /* keyCode (2 bytes) */ |
668 | 0 | Stream_Seek(s, 2); /* pad2Octets (2 bytes) */ |
669 | |
|
670 | 0 | if (keyboardFlags & KBD_FLAGS_RELEASE) |
671 | 0 | keyboardFlags &= ~KBD_FLAGS_DOWN; |
672 | |
|
673 | 0 | if (keyCode & 0xFF00) |
674 | 0 | WLog_WARN(TAG, |
675 | 0 | "Problematic [MS-RDPBCGR] 2.2.8.1.1.3.1.1.1 Keyboard Event (TS_KEYBOARD_EVENT) " |
676 | 0 | "keyCode=0x%04" PRIx16 |
677 | 0 | ", high byte values should be sent in keyboardFlags field, ignoring.", |
678 | 0 | keyCode); |
679 | 0 | return IFCALLRESULT(TRUE, input->KeyboardEvent, input, keyboardFlags, keyCode & 0xFF); |
680 | 0 | } |
681 | | |
682 | | static BOOL input_recv_unicode_keyboard_event(rdpInput* input, wStream* s) |
683 | 0 | { |
684 | 0 | UINT16 keyboardFlags = 0; |
685 | 0 | UINT16 unicodeCode = 0; |
686 | |
|
687 | 0 | WINPR_ASSERT(input); |
688 | 0 | WINPR_ASSERT(s); |
689 | | |
690 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
691 | 0 | return FALSE; |
692 | | |
693 | 0 | Stream_Read_UINT16(s, keyboardFlags); /* keyboardFlags (2 bytes) */ |
694 | 0 | Stream_Read_UINT16(s, unicodeCode); /* unicodeCode (2 bytes) */ |
695 | 0 | Stream_Seek(s, 2); /* pad2Octets (2 bytes) */ |
696 | | |
697 | | /* "fix" keyboardFlags - see comment in input_recv_keyboard_event() */ |
698 | |
|
699 | 0 | if (keyboardFlags & KBD_FLAGS_RELEASE) |
700 | 0 | keyboardFlags &= ~KBD_FLAGS_DOWN; |
701 | |
|
702 | 0 | return IFCALLRESULT(TRUE, input->UnicodeKeyboardEvent, input, keyboardFlags, unicodeCode); |
703 | 0 | } |
704 | | |
705 | | static BOOL input_recv_mouse_event(rdpInput* input, wStream* s) |
706 | 0 | { |
707 | 0 | UINT16 pointerFlags = 0; |
708 | 0 | UINT16 xPos = 0; |
709 | 0 | UINT16 yPos = 0; |
710 | |
|
711 | 0 | WINPR_ASSERT(input); |
712 | 0 | WINPR_ASSERT(s); |
713 | | |
714 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
715 | 0 | return FALSE; |
716 | | |
717 | 0 | Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */ |
718 | 0 | Stream_Read_UINT16(s, xPos); /* xPos (2 bytes) */ |
719 | 0 | Stream_Read_UINT16(s, yPos); /* yPos (2 bytes) */ |
720 | 0 | return IFCALLRESULT(TRUE, input->MouseEvent, input, pointerFlags, xPos, yPos); |
721 | 0 | } |
722 | | |
723 | | static BOOL input_recv_relmouse_event(rdpInput* input, wStream* s) |
724 | 0 | { |
725 | 0 | UINT16 pointerFlags = 0; |
726 | 0 | INT16 xDelta = 0; |
727 | 0 | INT16 yDelta = 0; |
728 | |
|
729 | 0 | WINPR_ASSERT(input); |
730 | 0 | WINPR_ASSERT(s); |
731 | | |
732 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
733 | 0 | return FALSE; |
734 | | |
735 | 0 | Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */ |
736 | 0 | Stream_Read_INT16(s, xDelta); /* xPos (2 bytes) */ |
737 | 0 | Stream_Read_INT16(s, yDelta); /* yPos (2 bytes) */ |
738 | |
|
739 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasRelativeMouseEvent)) |
740 | 0 | { |
741 | 0 | WLog_ERR(TAG, |
742 | 0 | "Received relative mouse event(flags=0x%04" PRIx16 ", xPos=%" PRId16 |
743 | 0 | ", yPos=%" PRId16 "), but we did not announce support for that", |
744 | 0 | pointerFlags, xDelta, yDelta); |
745 | 0 | return FALSE; |
746 | 0 | } |
747 | | |
748 | 0 | return IFCALLRESULT(TRUE, input->RelMouseEvent, input, pointerFlags, xDelta, yDelta); |
749 | 0 | } |
750 | | |
751 | | static BOOL input_recv_extended_mouse_event(rdpInput* input, wStream* s) |
752 | 0 | { |
753 | 0 | UINT16 pointerFlags = 0; |
754 | 0 | UINT16 xPos = 0; |
755 | 0 | UINT16 yPos = 0; |
756 | |
|
757 | 0 | WINPR_ASSERT(input); |
758 | 0 | WINPR_ASSERT(s); |
759 | | |
760 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
761 | 0 | return FALSE; |
762 | | |
763 | 0 | Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */ |
764 | 0 | Stream_Read_UINT16(s, xPos); /* xPos (2 bytes) */ |
765 | 0 | Stream_Read_UINT16(s, yPos); /* yPos (2 bytes) */ |
766 | |
|
767 | 0 | if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasExtendedMouseEvent)) |
768 | 0 | { |
769 | 0 | WLog_ERR(TAG, |
770 | 0 | "Received extended mouse event(flags=0x%04" PRIx16 ", xPos=%" PRIu16 |
771 | 0 | ", yPos=%" PRIu16 "), but we did not announce support for that", |
772 | 0 | pointerFlags, xPos, yPos); |
773 | 0 | return FALSE; |
774 | 0 | } |
775 | | |
776 | 0 | return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, pointerFlags, xPos, yPos); |
777 | 0 | } |
778 | | |
779 | | static BOOL input_recv_event(rdpInput* input, wStream* s) |
780 | 0 | { |
781 | 0 | UINT16 messageType = 0; |
782 | |
|
783 | 0 | WINPR_ASSERT(input); |
784 | 0 | WINPR_ASSERT(s); |
785 | | |
786 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 6)) |
787 | 0 | return FALSE; |
788 | | |
789 | 0 | Stream_Seek(s, 4); /* eventTime (4 bytes), ignored by the server */ |
790 | 0 | Stream_Read_UINT16(s, messageType); /* messageType (2 bytes) */ |
791 | |
|
792 | 0 | switch (messageType) |
793 | 0 | { |
794 | 0 | case INPUT_EVENT_SYNC: |
795 | 0 | if (!input_recv_sync_event(input, s)) |
796 | 0 | return FALSE; |
797 | | |
798 | 0 | break; |
799 | | |
800 | 0 | case INPUT_EVENT_SCANCODE: |
801 | 0 | if (!input_recv_keyboard_event(input, s)) |
802 | 0 | return FALSE; |
803 | | |
804 | 0 | break; |
805 | | |
806 | 0 | case INPUT_EVENT_UNICODE: |
807 | 0 | if (!input_recv_unicode_keyboard_event(input, s)) |
808 | 0 | return FALSE; |
809 | | |
810 | 0 | break; |
811 | | |
812 | 0 | case INPUT_EVENT_MOUSE: |
813 | 0 | if (!input_recv_mouse_event(input, s)) |
814 | 0 | return FALSE; |
815 | | |
816 | 0 | break; |
817 | | |
818 | 0 | case INPUT_EVENT_MOUSEX: |
819 | 0 | if (!input_recv_extended_mouse_event(input, s)) |
820 | 0 | return FALSE; |
821 | | |
822 | 0 | break; |
823 | | |
824 | 0 | case INPUT_EVENT_MOUSEREL: |
825 | 0 | if (!input_recv_relmouse_event(input, s)) |
826 | 0 | return FALSE; |
827 | | |
828 | 0 | break; |
829 | | |
830 | 0 | default: |
831 | 0 | WLog_ERR(TAG, "Unknown messageType %" PRIu16 "", messageType); |
832 | | /* Each input event uses 6 bytes. */ |
833 | 0 | Stream_Seek(s, 6); |
834 | 0 | break; |
835 | 0 | } |
836 | | |
837 | 0 | return TRUE; |
838 | 0 | } |
839 | | |
840 | | BOOL input_recv(rdpInput* input, wStream* s) |
841 | 0 | { |
842 | 0 | UINT16 numberEvents = 0; |
843 | |
|
844 | 0 | WINPR_ASSERT(input); |
845 | 0 | WINPR_ASSERT(s); |
846 | | |
847 | 0 | if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) |
848 | 0 | return FALSE; |
849 | | |
850 | 0 | Stream_Read_UINT16(s, numberEvents); /* numberEvents (2 bytes) */ |
851 | 0 | Stream_Seek(s, 2); /* pad2Octets (2 bytes) */ |
852 | | |
853 | | /* Each input event uses 6 exactly bytes. */ |
854 | 0 | if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, numberEvents, 6ull)) |
855 | 0 | return FALSE; |
856 | | |
857 | 0 | for (UINT16 i = 0; i < numberEvents; i++) |
858 | 0 | { |
859 | 0 | if (!input_recv_event(input, s)) |
860 | 0 | return FALSE; |
861 | 0 | } |
862 | | |
863 | 0 | return TRUE; |
864 | 0 | } |
865 | | |
866 | | BOOL input_register_client_callbacks(rdpInput* input) |
867 | 0 | { |
868 | 0 | rdpSettings* settings = NULL; |
869 | |
|
870 | 0 | if (!input->context) |
871 | 0 | return FALSE; |
872 | | |
873 | 0 | settings = input->context->settings; |
874 | |
|
875 | 0 | if (!settings) |
876 | 0 | return FALSE; |
877 | | |
878 | 0 | if (freerdp_settings_get_bool(settings, FreeRDP_FastPathInput)) |
879 | 0 | { |
880 | 0 | input->SynchronizeEvent = input_send_fastpath_synchronize_event; |
881 | 0 | input->KeyboardEvent = input_send_fastpath_keyboard_event; |
882 | 0 | input->KeyboardPauseEvent = input_send_fastpath_keyboard_pause_event; |
883 | 0 | input->UnicodeKeyboardEvent = input_send_fastpath_unicode_keyboard_event; |
884 | 0 | input->MouseEvent = input_send_fastpath_mouse_event; |
885 | 0 | input->RelMouseEvent = input_send_fastpath_relmouse_event; |
886 | 0 | input->ExtendedMouseEvent = input_send_fastpath_extended_mouse_event; |
887 | 0 | input->FocusInEvent = input_send_fastpath_focus_in_event; |
888 | 0 | input->QoEEvent = input_send_fastpath_qoe_event; |
889 | 0 | } |
890 | 0 | else |
891 | 0 | { |
892 | 0 | input->SynchronizeEvent = input_send_synchronize_event; |
893 | 0 | input->KeyboardEvent = input_send_keyboard_event; |
894 | 0 | input->KeyboardPauseEvent = input_send_keyboard_pause_event; |
895 | 0 | input->UnicodeKeyboardEvent = input_send_unicode_keyboard_event; |
896 | 0 | input->MouseEvent = input_send_mouse_event; |
897 | 0 | input->RelMouseEvent = input_send_relmouse_event; |
898 | 0 | input->ExtendedMouseEvent = input_send_extended_mouse_event; |
899 | 0 | input->FocusInEvent = input_send_focus_in_event; |
900 | 0 | } |
901 | |
|
902 | 0 | return TRUE; |
903 | 0 | } |
904 | | |
905 | | /* Save last input timestamp and/or mouse position in prevent-session-lock mode */ |
906 | | static BOOL input_update_last_event(rdpInput* input, BOOL mouse, UINT16 x, UINT16 y) |
907 | 0 | { |
908 | 0 | rdp_input_internal* in = input_cast(input); |
909 | |
|
910 | 0 | WINPR_ASSERT(input); |
911 | 0 | WINPR_ASSERT(input->context); |
912 | | |
913 | 0 | if (freerdp_settings_get_uint32(input->context->settings, FreeRDP_FakeMouseMotionInterval) > 0) |
914 | 0 | { |
915 | 0 | const time_t now = time(NULL); |
916 | 0 | in->lastInputTimestamp = WINPR_ASSERTING_INT_CAST(UINT64, now); |
917 | | |
918 | 0 | if (mouse) |
919 | 0 | { |
920 | 0 | in->lastX = x; |
921 | 0 | in->lastY = y; |
922 | 0 | } |
923 | 0 | } |
924 | 0 | return TRUE; |
925 | 0 | } |
926 | | |
927 | | BOOL freerdp_input_send_synchronize_event(rdpInput* input, UINT32 flags) |
928 | 0 | { |
929 | 0 | if (!input || !input->context) |
930 | 0 | return FALSE; |
931 | | |
932 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
933 | 0 | return TRUE; |
934 | | |
935 | 0 | return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, flags); |
936 | 0 | } |
937 | | |
938 | | BOOL freerdp_input_send_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code) |
939 | 0 | { |
940 | 0 | if (!input || !input->context) |
941 | 0 | return FALSE; |
942 | | |
943 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
944 | 0 | return TRUE; |
945 | | |
946 | 0 | input_update_last_event(input, FALSE, 0, 0); |
947 | |
|
948 | 0 | return IFCALLRESULT(TRUE, input->KeyboardEvent, input, flags, code); |
949 | 0 | } |
950 | | |
951 | | BOOL freerdp_input_send_keyboard_event_ex(rdpInput* input, BOOL down, BOOL repeat, |
952 | | UINT32 rdp_scancode) |
953 | 0 | { |
954 | 0 | UINT16 flags = (RDP_SCANCODE_EXTENDED(rdp_scancode) ? KBD_FLAGS_EXTENDED : 0); |
955 | 0 | if (down && repeat) |
956 | 0 | flags |= KBD_FLAGS_DOWN; |
957 | 0 | else if (!down) |
958 | 0 | flags |= KBD_FLAGS_RELEASE; |
959 | |
|
960 | 0 | return freerdp_input_send_keyboard_event(input, flags, RDP_SCANCODE_CODE(rdp_scancode)); |
961 | 0 | } |
962 | | |
963 | | BOOL freerdp_input_send_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) |
964 | 0 | { |
965 | 0 | if (!input || !input->context) |
966 | 0 | return FALSE; |
967 | | |
968 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
969 | 0 | return TRUE; |
970 | | |
971 | 0 | input_update_last_event(input, FALSE, 0, 0); |
972 | |
|
973 | 0 | return IFCALLRESULT(TRUE, input->UnicodeKeyboardEvent, input, flags, code); |
974 | 0 | } |
975 | | |
976 | | BOOL freerdp_input_send_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) |
977 | 0 | { |
978 | 0 | if (!input || !input->context) |
979 | 0 | return FALSE; |
980 | | |
981 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
982 | 0 | return TRUE; |
983 | | |
984 | 0 | input_update_last_event( |
985 | 0 | input, flags & (PTR_FLAGS_MOVE | PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 | PTR_FLAGS_BUTTON3), |
986 | 0 | x, y); |
987 | |
|
988 | 0 | return IFCALLRESULT(TRUE, input->MouseEvent, input, flags, x, y); |
989 | 0 | } |
990 | | |
991 | | BOOL freerdp_input_send_rel_mouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, INT16 yDelta) |
992 | 0 | { |
993 | 0 | if (!input || !input->context) |
994 | 0 | return FALSE; |
995 | | |
996 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
997 | 0 | return TRUE; |
998 | | |
999 | 0 | return IFCALLRESULT(TRUE, input->RelMouseEvent, input, flags, xDelta, yDelta); |
1000 | 0 | } |
1001 | | |
1002 | | BOOL freerdp_input_send_qoe_timestamp(rdpInput* input, UINT32 timestampMS) |
1003 | 0 | { |
1004 | 0 | if (!input || !input->context) |
1005 | 0 | return FALSE; |
1006 | | |
1007 | 0 | return IFCALLRESULT(TRUE, input->QoEEvent, input, timestampMS); |
1008 | 0 | } |
1009 | | |
1010 | | BOOL freerdp_input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) |
1011 | 0 | { |
1012 | 0 | if (!input || !input->context) |
1013 | 0 | return FALSE; |
1014 | | |
1015 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
1016 | 0 | return TRUE; |
1017 | | |
1018 | 0 | input_update_last_event(input, TRUE, x, y); |
1019 | |
|
1020 | 0 | return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, flags, x, y); |
1021 | 0 | } |
1022 | | |
1023 | | BOOL freerdp_input_send_focus_in_event(rdpInput* input, UINT16 toggleStates) |
1024 | 0 | { |
1025 | 0 | if (!input || !input->context) |
1026 | 0 | return FALSE; |
1027 | | |
1028 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
1029 | 0 | return TRUE; |
1030 | | |
1031 | 0 | return IFCALLRESULT(TRUE, input->FocusInEvent, input, toggleStates); |
1032 | 0 | } |
1033 | | |
1034 | | BOOL freerdp_input_send_keyboard_pause_event(rdpInput* input) |
1035 | 0 | { |
1036 | 0 | if (!input || !input->context) |
1037 | 0 | return FALSE; |
1038 | | |
1039 | 0 | if (freerdp_settings_get_bool(input->context->settings, FreeRDP_SuspendInput)) |
1040 | 0 | return TRUE; |
1041 | | |
1042 | 0 | return IFCALLRESULT(TRUE, input->KeyboardPauseEvent, input); |
1043 | 0 | } |
1044 | | |
1045 | | int input_process_events(rdpInput* input) |
1046 | 0 | { |
1047 | 0 | if (!input) |
1048 | 0 | return FALSE; |
1049 | | |
1050 | 0 | return input_message_queue_process_pending_messages(input); |
1051 | 0 | } |
1052 | | |
1053 | | static void input_free_queued_message(void* obj) |
1054 | 0 | { |
1055 | 0 | wMessage* msg = (wMessage*)obj; |
1056 | 0 | input_message_queue_free_message(msg); |
1057 | 0 | } |
1058 | | |
1059 | | rdpInput* input_new(rdpRdp* rdp) |
1060 | 0 | { |
1061 | 0 | const wObject cb = { NULL, NULL, NULL, input_free_queued_message, NULL }; |
1062 | 0 | rdp_input_internal* input = (rdp_input_internal*)calloc(1, sizeof(rdp_input_internal)); |
1063 | |
|
1064 | 0 | WINPR_UNUSED(rdp); |
1065 | |
|
1066 | 0 | if (!input) |
1067 | 0 | return NULL; |
1068 | | |
1069 | 0 | input->common.context = rdp->context; |
1070 | 0 | input->queue = MessageQueue_New(&cb); |
1071 | |
|
1072 | 0 | if (!input->queue) |
1073 | 0 | { |
1074 | 0 | free(input); |
1075 | 0 | return NULL; |
1076 | 0 | } |
1077 | | |
1078 | 0 | return &input->common; |
1079 | 0 | } |
1080 | | |
1081 | | void input_free(rdpInput* input) |
1082 | 0 | { |
1083 | 0 | if (input != NULL) |
1084 | 0 | { |
1085 | 0 | rdp_input_internal* in = input_cast(input); |
1086 | |
|
1087 | 0 | MessageQueue_Free(in->queue); |
1088 | 0 | free(in); |
1089 | 0 | } |
1090 | 0 | } |