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