Coverage Report

Created: 2024-05-20 06:11

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