Coverage Report

Created: 2025-11-24 06:38

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