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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <winpr/crt.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 #define INPUT_EVENT_SYNC 0x0000
37 #define INPUT_EVENT_SCANCODE 0x0004
38 #define INPUT_EVENT_UNICODE 0x0005
39 #define INPUT_EVENT_MOUSE 0x8001
40 #define INPUT_EVENT_MOUSEX 0x8002
41
42 #define RDP_CLIENT_INPUT_PDU_HEADER_LENGTH 4
43
rdp_write_client_input_pdu_header(wStream * s,UINT16 number)44 static void rdp_write_client_input_pdu_header(wStream* s, UINT16 number)
45 {
46 Stream_Write_UINT16(s, 1); /* numberEvents (2 bytes) */
47 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
48 }
49
rdp_write_input_event_header(wStream * s,UINT32 time,UINT16 type)50 static void rdp_write_input_event_header(wStream* s, UINT32 time, UINT16 type)
51 {
52 Stream_Write_UINT32(s, time); /* eventTime (4 bytes) */
53 Stream_Write_UINT16(s, type); /* messageType (2 bytes) */
54 }
55
rdp_client_input_pdu_init(rdpRdp * rdp,UINT16 type)56 static wStream* rdp_client_input_pdu_init(rdpRdp* rdp, UINT16 type)
57 {
58 wStream* s;
59 s = rdp_data_pdu_init(rdp);
60
61 if (!s)
62 return NULL;
63
64 rdp_write_client_input_pdu_header(s, 1);
65 rdp_write_input_event_header(s, 0, type);
66 return s;
67 }
68
rdp_send_client_input_pdu(rdpRdp * rdp,wStream * s)69 static BOOL rdp_send_client_input_pdu(rdpRdp* rdp, wStream* s)
70 {
71 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_INPUT, rdp->mcs->userId);
72 }
73
input_write_synchronize_event(wStream * s,UINT32 flags)74 static void input_write_synchronize_event(wStream* s, UINT32 flags)
75 {
76 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
77 Stream_Write_UINT32(s, flags); /* toggleFlags (4 bytes) */
78 }
79
input_send_synchronize_event(rdpInput * input,UINT32 flags)80 static BOOL input_send_synchronize_event(rdpInput* input, UINT32 flags)
81 {
82 wStream* s;
83 rdpRdp* rdp;
84
85 if (!input || !input->context)
86 return FALSE;
87
88 rdp = input->context->rdp;
89 s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_SYNC);
90
91 if (!s)
92 return FALSE;
93
94 input_write_synchronize_event(s, flags);
95 return rdp_send_client_input_pdu(rdp, s);
96 }
97
input_write_keyboard_event(wStream * s,UINT16 flags,UINT16 code)98 static void input_write_keyboard_event(wStream* s, UINT16 flags, UINT16 code)
99 {
100 Stream_Write_UINT16(s, flags); /* keyboardFlags (2 bytes) */
101 Stream_Write_UINT16(s, code); /* keyCode (2 bytes) */
102 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
103 }
104
input_send_keyboard_event(rdpInput * input,UINT16 flags,UINT16 code)105 static BOOL input_send_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
106 {
107 wStream* s;
108 rdpRdp* rdp;
109
110 if (!input || !input->context)
111 return FALSE;
112
113 rdp = input->context->rdp;
114 s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_SCANCODE);
115
116 if (!s)
117 return FALSE;
118
119 input_write_keyboard_event(s, flags, code);
120 return rdp_send_client_input_pdu(rdp, s);
121 }
122
input_write_unicode_keyboard_event(wStream * s,UINT16 flags,UINT16 code)123 static void input_write_unicode_keyboard_event(wStream* s, UINT16 flags, UINT16 code)
124 {
125 Stream_Write_UINT16(s, flags); /* keyboardFlags (2 bytes) */
126 Stream_Write_UINT16(s, code); /* unicodeCode (2 bytes) */
127 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
128 }
129
input_send_unicode_keyboard_event(rdpInput * input,UINT16 flags,UINT16 code)130 static BOOL input_send_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
131 {
132 wStream* s;
133 rdpRdp* rdp;
134
135 if (!input || !input->context)
136 return FALSE;
137
138 if (!input->context->settings->UnicodeInput)
139 {
140 WLog_WARN(TAG, "Unicode input not supported by server.");
141 return FALSE;
142 }
143
144 rdp = input->context->rdp;
145 s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_UNICODE);
146
147 if (!s)
148 return FALSE;
149
150 input_write_unicode_keyboard_event(s, flags, code);
151 return rdp_send_client_input_pdu(rdp, s);
152 }
153
input_write_mouse_event(wStream * s,UINT16 flags,UINT16 x,UINT16 y)154 static void input_write_mouse_event(wStream* s, UINT16 flags, UINT16 x, UINT16 y)
155 {
156 Stream_Write_UINT16(s, flags); /* pointerFlags (2 bytes) */
157 Stream_Write_UINT16(s, x); /* xPos (2 bytes) */
158 Stream_Write_UINT16(s, y); /* yPos (2 bytes) */
159 }
160
input_send_mouse_event(rdpInput * input,UINT16 flags,UINT16 x,UINT16 y)161 static BOOL input_send_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
162 {
163 wStream* s;
164 rdpRdp* rdp;
165
166 if (!input || !input->context || !input->context->settings)
167 return FALSE;
168
169 rdp = input->context->rdp;
170
171 if (!input->context->settings->HasHorizontalWheel)
172 {
173 if (flags & PTR_FLAGS_HWHEEL)
174 {
175 WLog_WARN(TAG,
176 "skip mouse event %" PRIu16 "x%" PRIu16 " flags=0x%04" PRIX16
177 ", no horizontal mouse wheel supported",
178 x, y, flags);
179 return TRUE;
180 }
181 }
182
183 s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_MOUSE);
184
185 if (!s)
186 return FALSE;
187
188 input_write_mouse_event(s, flags, x, y);
189 return rdp_send_client_input_pdu(rdp, s);
190 }
191
input_write_extended_mouse_event(wStream * s,UINT16 flags,UINT16 x,UINT16 y)192 static void input_write_extended_mouse_event(wStream* s, UINT16 flags, UINT16 x, UINT16 y)
193 {
194 Stream_Write_UINT16(s, flags); /* pointerFlags (2 bytes) */
195 Stream_Write_UINT16(s, x); /* xPos (2 bytes) */
196 Stream_Write_UINT16(s, y); /* yPos (2 bytes) */
197 }
198
input_send_extended_mouse_event(rdpInput * input,UINT16 flags,UINT16 x,UINT16 y)199 static BOOL input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
200 {
201 wStream* s;
202 rdpRdp* rdp;
203
204 if (!input || !input->context)
205 return FALSE;
206
207 if (!input->context->settings->HasExtendedMouseEvent)
208 {
209 WLog_WARN(TAG,
210 "skip extended mouse event %" PRIu16 "x%" PRIu16 " flags=0x%04" PRIX16
211 ", no extended mouse events supported",
212 x, y, flags);
213 return TRUE;
214 }
215
216 rdp = input->context->rdp;
217 s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_MOUSEX);
218
219 if (!s)
220 return FALSE;
221
222 input_write_extended_mouse_event(s, flags, x, y);
223 return rdp_send_client_input_pdu(rdp, s);
224 }
225
input_send_focus_in_event(rdpInput * input,UINT16 toggleStates)226 static BOOL input_send_focus_in_event(rdpInput* input, UINT16 toggleStates)
227 {
228 /* send a tab up like mstsc.exe */
229 if (!input_send_keyboard_event(input, KBD_FLAGS_RELEASE, 0x0f))
230 return FALSE;
231
232 /* send the toggle key states */
233 if (!input_send_synchronize_event(input, (toggleStates & 0x1F)))
234 return FALSE;
235
236 /* send another tab up like mstsc.exe */
237 return input_send_keyboard_event(input, KBD_FLAGS_RELEASE, 0x0f);
238 }
239
input_send_keyboard_pause_event(rdpInput * input)240 static BOOL input_send_keyboard_pause_event(rdpInput* input)
241 {
242 /* In ancient days, pause-down without control sent E1 1D 45 E1 9D C5,
243 * and pause-up sent nothing. However, reverse engineering mstsc shows
244 * it sending the following sequence:
245 */
246
247 /* Control down (0x1D) */
248 if (!input_send_keyboard_event(input, KBD_FLAGS_EXTENDED1,
249 RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)))
250 return FALSE;
251
252 /* Numlock down (0x45) */
253 if (!input_send_keyboard_event(input, 0, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)))
254 return FALSE;
255
256 /* Control up (0x1D) */
257 if (!input_send_keyboard_event(input, KBD_FLAGS_RELEASE | KBD_FLAGS_EXTENDED1,
258 RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)))
259 return FALSE;
260
261 /* Numlock up (0x45) */
262 return input_send_keyboard_event(input, KBD_FLAGS_RELEASE,
263 RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK));
264 }
265
input_send_fastpath_synchronize_event(rdpInput * input,UINT32 flags)266 static BOOL input_send_fastpath_synchronize_event(rdpInput* input, UINT32 flags)
267 {
268 wStream* s;
269 rdpRdp* rdp;
270
271 if (!input || !input->context)
272 return FALSE;
273
274 rdp = input->context->rdp;
275 /* The FastPath Synchronization eventFlags has identical values as SlowPath */
276 s = fastpath_input_pdu_init(rdp->fastpath, (BYTE)flags, FASTPATH_INPUT_EVENT_SYNC);
277
278 if (!s)
279 return FALSE;
280
281 return fastpath_send_input_pdu(rdp->fastpath, s);
282 }
283
input_send_fastpath_keyboard_event(rdpInput * input,UINT16 flags,UINT16 code)284 static BOOL input_send_fastpath_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
285 {
286 wStream* s;
287 BYTE eventFlags = 0;
288 rdpRdp* rdp;
289
290 if (!input || !input->context)
291 return FALSE;
292
293 rdp = input->context->rdp;
294 eventFlags |= (flags & KBD_FLAGS_RELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0;
295 eventFlags |= (flags & KBD_FLAGS_EXTENDED) ? FASTPATH_INPUT_KBDFLAGS_EXTENDED : 0;
296 eventFlags |= (flags & KBD_FLAGS_EXTENDED1) ? FASTPATH_INPUT_KBDFLAGS_PREFIX_E1 : 0;
297 s = fastpath_input_pdu_init(rdp->fastpath, eventFlags, FASTPATH_INPUT_EVENT_SCANCODE);
298
299 if (!s)
300 return FALSE;
301
302 Stream_Write_UINT8(s, code); /* keyCode (1 byte) */
303 return fastpath_send_input_pdu(rdp->fastpath, s);
304 }
305
input_send_fastpath_unicode_keyboard_event(rdpInput * input,UINT16 flags,UINT16 code)306 static BOOL input_send_fastpath_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
307 {
308 wStream* s;
309 BYTE eventFlags = 0;
310 rdpRdp* rdp;
311
312 if (!input || !input->context)
313 return FALSE;
314
315 if (!input->context->settings->UnicodeInput)
316 {
317 WLog_WARN(TAG, "Unicode input not supported by server.");
318 return FALSE;
319 }
320
321 rdp = input->context->rdp;
322 eventFlags |= (flags & KBD_FLAGS_RELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0;
323 s = fastpath_input_pdu_init(rdp->fastpath, eventFlags, FASTPATH_INPUT_EVENT_UNICODE);
324
325 if (!s)
326 return FALSE;
327
328 Stream_Write_UINT16(s, code); /* unicodeCode (2 bytes) */
329 return fastpath_send_input_pdu(rdp->fastpath, s);
330 }
331
input_send_fastpath_mouse_event(rdpInput * input,UINT16 flags,UINT16 x,UINT16 y)332 static BOOL input_send_fastpath_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
333 {
334 wStream* s;
335 rdpRdp* rdp;
336
337 if (!input || !input->context || !input->context->settings)
338 return FALSE;
339
340 rdp = input->context->rdp;
341
342 if (!input->context->settings->HasHorizontalWheel)
343 {
344 if (flags & PTR_FLAGS_HWHEEL)
345 {
346 WLog_WARN(TAG,
347 "skip mouse event %" PRIu16 "x%" PRIu16 " flags=0x%04" PRIX16
348 ", no horizontal mouse wheel supported",
349 x, y, flags);
350 return TRUE;
351 }
352 }
353
354 s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSE);
355
356 if (!s)
357 return FALSE;
358
359 input_write_mouse_event(s, flags, x, y);
360 return fastpath_send_input_pdu(rdp->fastpath, s);
361 }
362
input_send_fastpath_extended_mouse_event(rdpInput * input,UINT16 flags,UINT16 x,UINT16 y)363 static BOOL input_send_fastpath_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x,
364 UINT16 y)
365 {
366 wStream* s;
367 rdpRdp* rdp;
368
369 if (!input || !input->context)
370 return FALSE;
371
372 if (!input->context->settings->HasExtendedMouseEvent)
373 {
374 WLog_WARN(TAG,
375 "skip extended mouse event %" PRIu16 "x%" PRIu16 " flags=0x%04" PRIX16
376 ", no extended mouse events supported",
377 x, y, flags);
378 return TRUE;
379 }
380
381 rdp = input->context->rdp;
382 s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSEX);
383
384 if (!s)
385 return FALSE;
386
387 input_write_extended_mouse_event(s, flags, x, y);
388 return fastpath_send_input_pdu(rdp->fastpath, s);
389 }
390
input_send_fastpath_focus_in_event(rdpInput * input,UINT16 toggleStates)391 static BOOL input_send_fastpath_focus_in_event(rdpInput* input, UINT16 toggleStates)
392 {
393 wStream* s;
394 BYTE eventFlags = 0;
395 rdpRdp* rdp;
396
397 if (!input || !input->context)
398 return FALSE;
399
400 rdp = input->context->rdp;
401 s = fastpath_input_pdu_init_header(rdp->fastpath);
402
403 if (!s)
404 return FALSE;
405
406 /* send a tab up like mstsc.exe */
407 eventFlags = FASTPATH_INPUT_KBDFLAGS_RELEASE | FASTPATH_INPUT_EVENT_SCANCODE << 5;
408 Stream_Write_UINT8(s, eventFlags); /* Key Release event (1 byte) */
409 Stream_Write_UINT8(s, 0x0f); /* keyCode (1 byte) */
410 /* send the toggle key states */
411 eventFlags = (toggleStates & 0x1F) | FASTPATH_INPUT_EVENT_SYNC << 5;
412 Stream_Write_UINT8(s, eventFlags); /* toggle state (1 byte) */
413 /* send another tab up like mstsc.exe */
414 eventFlags = FASTPATH_INPUT_KBDFLAGS_RELEASE | FASTPATH_INPUT_EVENT_SCANCODE << 5;
415 Stream_Write_UINT8(s, eventFlags); /* Key Release event (1 byte) */
416 Stream_Write_UINT8(s, 0x0f); /* keyCode (1 byte) */
417 return fastpath_send_multiple_input_pdu(rdp->fastpath, s, 3);
418 }
419
input_send_fastpath_keyboard_pause_event(rdpInput * input)420 static BOOL input_send_fastpath_keyboard_pause_event(rdpInput* input)
421 {
422 /* In ancient days, pause-down without control sent E1 1D 45 E1 9D C5,
423 * and pause-up sent nothing. However, reverse engineering mstsc shows
424 * it sending the following sequence:
425 */
426 wStream* s;
427 const BYTE keyDownEvent = FASTPATH_INPUT_EVENT_SCANCODE << 5;
428 const BYTE keyUpEvent = (FASTPATH_INPUT_EVENT_SCANCODE << 5) | FASTPATH_INPUT_KBDFLAGS_RELEASE;
429 rdpRdp* rdp;
430
431 if (!input || !input->context)
432 return FALSE;
433
434 rdp = input->context->rdp;
435 s = fastpath_input_pdu_init_header(rdp->fastpath);
436
437 if (!s)
438 return FALSE;
439
440 /* Control down (0x1D) */
441 Stream_Write_UINT8(s, keyDownEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1);
442 Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL));
443 /* Numlock down (0x45) */
444 Stream_Write_UINT8(s, keyDownEvent);
445 Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK));
446 /* Control up (0x1D) */
447 Stream_Write_UINT8(s, keyUpEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1);
448 Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL));
449 /* Numlock down (0x45) */
450 Stream_Write_UINT8(s, keyUpEvent);
451 Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK));
452 return fastpath_send_multiple_input_pdu(rdp->fastpath, s, 4);
453 }
454
input_recv_sync_event(rdpInput * input,wStream * s)455 static BOOL input_recv_sync_event(rdpInput* input, wStream* s)
456 {
457 UINT32 toggleFlags;
458
459 if (Stream_GetRemainingLength(s) < 6)
460 return FALSE;
461
462 Stream_Seek(s, 2); /* pad2Octets (2 bytes) */
463 Stream_Read_UINT32(s, toggleFlags); /* toggleFlags (4 bytes) */
464 return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, toggleFlags);
465 }
466
input_recv_keyboard_event(rdpInput * input,wStream * s)467 static BOOL input_recv_keyboard_event(rdpInput* input, wStream* s)
468 {
469 UINT16 keyboardFlags, keyCode;
470
471 if (Stream_GetRemainingLength(s) < 6)
472 return FALSE;
473
474 Stream_Read_UINT16(s, keyboardFlags); /* keyboardFlags (2 bytes) */
475 Stream_Read_UINT16(s, keyCode); /* keyCode (2 bytes) */
476 Stream_Seek(s, 2); /* pad2Octets (2 bytes) */
477
478 /**
479 * Note: A lot of code in FreeRDP and in dependent projects checks the
480 * KBDFLAGS_DOWN flag in order to detect a key press.
481 * According to the specs only the absence of the slow-path
482 * KBDFLAGS_RELEASE flag indicates a key-down event.
483 * The slow-path KBDFLAGS_DOWN flag merely indicates that the key was
484 * down prior to this event.
485 * The checks for KBDFLAGS_DOWN only work successfully because the code
486 * handling the fast-path keyboard input sets the KBDFLAGS_DOWN flag if
487 * the FASTPATH_INPUT_KBDFLAGS_RELEASE flag is missing.
488 * Since the same input callback is used for slow- and fast-path events
489 * we have to follow that "convention" here.
490 */
491
492 if (keyboardFlags & KBD_FLAGS_RELEASE)
493 keyboardFlags &= ~KBD_FLAGS_DOWN;
494 else
495 keyboardFlags |= KBD_FLAGS_DOWN;
496
497 return IFCALLRESULT(TRUE, input->KeyboardEvent, input, keyboardFlags, keyCode);
498 }
499
input_recv_unicode_keyboard_event(rdpInput * input,wStream * s)500 static BOOL input_recv_unicode_keyboard_event(rdpInput* input, wStream* s)
501 {
502 UINT16 keyboardFlags, unicodeCode;
503
504 if (Stream_GetRemainingLength(s) < 6)
505 return FALSE;
506
507 Stream_Read_UINT16(s, keyboardFlags); /* keyboardFlags (2 bytes) */
508 Stream_Read_UINT16(s, unicodeCode); /* unicodeCode (2 bytes) */
509 Stream_Seek(s, 2); /* pad2Octets (2 bytes) */
510
511 /* "fix" keyboardFlags - see comment in input_recv_keyboard_event() */
512
513 if (keyboardFlags & KBD_FLAGS_RELEASE)
514 keyboardFlags &= ~KBD_FLAGS_DOWN;
515 else
516 keyboardFlags |= KBD_FLAGS_DOWN;
517
518 return IFCALLRESULT(TRUE, input->UnicodeKeyboardEvent, input, keyboardFlags, unicodeCode);
519 }
520
input_recv_mouse_event(rdpInput * input,wStream * s)521 static BOOL input_recv_mouse_event(rdpInput* input, wStream* s)
522 {
523 UINT16 pointerFlags, xPos, yPos;
524
525 if (Stream_GetRemainingLength(s) < 6)
526 return FALSE;
527
528 Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
529 Stream_Read_UINT16(s, xPos); /* xPos (2 bytes) */
530 Stream_Read_UINT16(s, yPos); /* yPos (2 bytes) */
531 return IFCALLRESULT(TRUE, input->MouseEvent, input, pointerFlags, xPos, yPos);
532 }
533
input_recv_extended_mouse_event(rdpInput * input,wStream * s)534 static BOOL input_recv_extended_mouse_event(rdpInput* input, wStream* s)
535 {
536 UINT16 pointerFlags, xPos, yPos;
537
538 if (Stream_GetRemainingLength(s) < 6)
539 return FALSE;
540
541 Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
542 Stream_Read_UINT16(s, xPos); /* xPos (2 bytes) */
543 Stream_Read_UINT16(s, yPos); /* yPos (2 bytes) */
544 return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, pointerFlags, xPos, yPos);
545 }
546
input_recv_event(rdpInput * input,wStream * s)547 static BOOL input_recv_event(rdpInput* input, wStream* s)
548 {
549 UINT16 messageType;
550
551 if (Stream_GetRemainingLength(s) < 6)
552 return FALSE;
553
554 Stream_Seek(s, 4); /* eventTime (4 bytes), ignored by the server */
555 Stream_Read_UINT16(s, messageType); /* messageType (2 bytes) */
556
557 switch (messageType)
558 {
559 case INPUT_EVENT_SYNC:
560 if (!input_recv_sync_event(input, s))
561 return FALSE;
562
563 break;
564
565 case INPUT_EVENT_SCANCODE:
566 if (!input_recv_keyboard_event(input, s))
567 return FALSE;
568
569 break;
570
571 case INPUT_EVENT_UNICODE:
572 if (!input_recv_unicode_keyboard_event(input, s))
573 return FALSE;
574
575 break;
576
577 case INPUT_EVENT_MOUSE:
578 if (!input_recv_mouse_event(input, s))
579 return FALSE;
580
581 break;
582
583 case INPUT_EVENT_MOUSEX:
584 if (!input_recv_extended_mouse_event(input, s))
585 return FALSE;
586
587 break;
588
589 default:
590 WLog_ERR(TAG, "Unknown messageType %" PRIu16 "", messageType);
591 /* Each input event uses 6 bytes. */
592 Stream_Seek(s, 6);
593 break;
594 }
595
596 return TRUE;
597 }
598
input_recv(rdpInput * input,wStream * s)599 BOOL input_recv(rdpInput* input, wStream* s)
600 {
601 UINT16 i, numberEvents;
602
603 if (!input || !s)
604 return FALSE;
605
606 if (Stream_GetRemainingLength(s) < 4)
607 return FALSE;
608
609 Stream_Read_UINT16(s, numberEvents); /* numberEvents (2 bytes) */
610 Stream_Seek(s, 2); /* pad2Octets (2 bytes) */
611
612 /* Each input event uses 6 exactly bytes. */
613 if (Stream_GetRemainingLength(s) < (size_t)(6 * numberEvents))
614 return FALSE;
615
616 for (i = 0; i < numberEvents; i++)
617 {
618 if (!input_recv_event(input, s))
619 return FALSE;
620 }
621
622 return TRUE;
623 }
624
input_register_client_callbacks(rdpInput * input)625 BOOL input_register_client_callbacks(rdpInput* input)
626 {
627 rdpSettings* settings;
628
629 if (!input || !input->context)
630 return FALSE;
631
632 settings = input->context->settings;
633
634 if (!settings)
635 return FALSE;
636
637 if (settings->FastPathInput)
638 {
639 input->SynchronizeEvent = input_send_fastpath_synchronize_event;
640 input->KeyboardEvent = input_send_fastpath_keyboard_event;
641 input->KeyboardPauseEvent = input_send_fastpath_keyboard_pause_event;
642 input->UnicodeKeyboardEvent = input_send_fastpath_unicode_keyboard_event;
643 input->MouseEvent = input_send_fastpath_mouse_event;
644 input->ExtendedMouseEvent = input_send_fastpath_extended_mouse_event;
645 input->FocusInEvent = input_send_fastpath_focus_in_event;
646 }
647 else
648 {
649 input->SynchronizeEvent = input_send_synchronize_event;
650 input->KeyboardEvent = input_send_keyboard_event;
651 input->KeyboardPauseEvent = input_send_keyboard_pause_event;
652 input->UnicodeKeyboardEvent = input_send_unicode_keyboard_event;
653 input->MouseEvent = input_send_mouse_event;
654 input->ExtendedMouseEvent = input_send_extended_mouse_event;
655 input->FocusInEvent = input_send_focus_in_event;
656 }
657
658 input->asynchronous = settings->AsyncInput;
659
660 if (input->asynchronous)
661 {
662 input->proxy = input_message_proxy_new(input);
663
664 if (!input->proxy)
665 return FALSE;
666 }
667
668 return TRUE;
669 }
670
freerdp_input_send_synchronize_event(rdpInput * input,UINT32 flags)671 BOOL freerdp_input_send_synchronize_event(rdpInput* input, UINT32 flags)
672 {
673 if (!input)
674 return FALSE;
675
676 return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, flags);
677 }
678
freerdp_input_send_keyboard_event(rdpInput * input,UINT16 flags,UINT16 code)679 BOOL freerdp_input_send_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
680 {
681 if (!input)
682 return FALSE;
683
684 return IFCALLRESULT(TRUE, input->KeyboardEvent, input, flags, code);
685 }
686
freerdp_input_send_keyboard_event_ex(rdpInput * input,BOOL down,UINT32 rdp_scancode)687 BOOL freerdp_input_send_keyboard_event_ex(rdpInput* input, BOOL down, UINT32 rdp_scancode)
688 {
689 return freerdp_input_send_keyboard_event(
690 input,
691 (RDP_SCANCODE_EXTENDED(rdp_scancode) ? KBD_FLAGS_EXTENDED : 0) |
692 ((down) ? KBD_FLAGS_DOWN : KBD_FLAGS_RELEASE),
693 RDP_SCANCODE_CODE(rdp_scancode));
694 }
695
freerdp_input_send_unicode_keyboard_event(rdpInput * input,UINT16 flags,UINT16 code)696 BOOL freerdp_input_send_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
697 {
698 if (!input)
699 return FALSE;
700
701 return IFCALLRESULT(TRUE, input->UnicodeKeyboardEvent, input, flags, code);
702 }
703
freerdp_input_send_mouse_event(rdpInput * input,UINT16 flags,UINT16 x,UINT16 y)704 BOOL freerdp_input_send_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
705 {
706 if (!input)
707 return FALSE;
708
709 return IFCALLRESULT(TRUE, input->MouseEvent, input, flags, x, y);
710 }
711
freerdp_input_send_extended_mouse_event(rdpInput * input,UINT16 flags,UINT16 x,UINT16 y)712 BOOL freerdp_input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
713 {
714 if (!input)
715 return FALSE;
716
717 return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, flags, x, y);
718 }
719
freerdp_input_send_focus_in_event(rdpInput * input,UINT16 toggleStates)720 BOOL freerdp_input_send_focus_in_event(rdpInput* input, UINT16 toggleStates)
721 {
722 if (!input)
723 return FALSE;
724
725 return IFCALLRESULT(TRUE, input->FocusInEvent, input, toggleStates);
726 }
727
freerdp_input_send_keyboard_pause_event(rdpInput * input)728 BOOL freerdp_input_send_keyboard_pause_event(rdpInput* input)
729 {
730 if (!input)
731 return FALSE;
732
733 return IFCALLRESULT(TRUE, input->KeyboardPauseEvent, input);
734 }
735
input_process_events(rdpInput * input)736 int input_process_events(rdpInput* input)
737 {
738 if (!input)
739 return FALSE;
740
741 return input_message_queue_process_pending_messages(input);
742 }
743
input_free_queued_message(void * obj)744 static void input_free_queued_message(void* obj)
745 {
746 wMessage* msg = (wMessage*)obj;
747 input_message_queue_free_message(msg);
748 }
749
input_new(rdpRdp * rdp)750 rdpInput* input_new(rdpRdp* rdp)
751 {
752 const wObject cb = { NULL, NULL, NULL, input_free_queued_message, NULL };
753 rdpInput* input;
754 input = (rdpInput*)calloc(1, sizeof(rdpInput));
755
756 if (!input)
757 return NULL;
758
759 input->queue = MessageQueue_New(&cb);
760
761 if (!input->queue)
762 {
763 free(input);
764 return NULL;
765 }
766
767 return input;
768 }
769
input_free(rdpInput * input)770 void input_free(rdpInput* input)
771 {
772 if (input != NULL)
773 {
774 if (input->asynchronous)
775 input_message_proxy_free(input->proxy);
776
777 MessageQueue_Free(input->queue);
778 free(input);
779 }
780 }
781