Coverage Report

Created: 2026-10-15 06:31

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
21.4k
#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(uint32_t 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 nullptr;
63
64
0
  if (!winpr_str_append("{", buffer, len, ""))
65
0
    return nullptr;
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] = WINPR_C_ARRAY_INIT;
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 nullptr;
77
0
    }
78
0
  }
79
0
  if (!winpr_str_append("}", &buffer[1], len - 2, ""))
80
0
    return nullptr;
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 nullptr;
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 = nullptr;
179
0
  rdpRdp* rdp = nullptr;
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 = nullptr;
209
0
  rdpRdp* rdp = nullptr;
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 = nullptr;
277
0
  rdpRdp* rdp = nullptr;
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 = nullptr;
388
0
  rdpRdp* rdp = nullptr;
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 = nullptr;
412
0
  BYTE eventFlags = 0;
413
0
  rdpRdp* rdp = nullptr;
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 = nullptr;
442
0
  BYTE eventFlags = 0;
443
0
  rdpRdp* rdp = nullptr;
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 = nullptr;
476
0
  rdpRdp* rdp = nullptr;
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 = nullptr;
514
0
  rdpRdp* rdp = nullptr;
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 = nullptr;
548
0
  rdpRdp* rdp = nullptr;
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 = nullptr;
615
0
  BYTE eventFlags = 0;
616
0
  rdpRdp* rdp = nullptr;
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 = nullptr;
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 = nullptr;
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
700
  /* only pass input if we are actually connected */
701
0
  if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
702
0
    return TRUE;
703
0
  return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, toggleFlags);
704
0
}
705
706
static BOOL input_recv_keyboard_event(rdpInput* input, wStream* s)
707
0
{
708
0
  UINT16 keyboardFlags = 0;
709
0
  UINT16 keyCode = 0;
710
711
0
  WINPR_ASSERT(input);
712
0
  WINPR_ASSERT(s);
713
714
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
715
0
    return FALSE;
716
717
0
  Stream_Read_UINT16(s, keyboardFlags); /* keyboardFlags (2 bytes) */
718
0
  Stream_Read_UINT16(s, keyCode);       /* keyCode (2 bytes) */
719
0
  Stream_Seek(s, 2);                    /* pad2Octets (2 bytes) */
720
721
0
  if (keyboardFlags & KBD_FLAGS_RELEASE)
722
0
    keyboardFlags &= ~KBD_FLAGS_DOWN;
723
724
0
  if (keyCode & 0xFF00)
725
0
    WLog_WARN(TAG,
726
0
              "Problematic [MS-RDPBCGR] 2.2.8.1.1.3.1.1.1 Keyboard Event (TS_KEYBOARD_EVENT) "
727
0
              "keyCode=0x%04" PRIx16
728
0
              ", high byte values should be sent in keyboardFlags field, ignoring.",
729
0
              keyCode);
730
731
  /* only pass input if we are actually connected */
732
0
  if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
733
0
    return TRUE;
734
0
  return IFCALLRESULT(TRUE, input->KeyboardEvent, input, keyboardFlags, keyCode & 0xFF);
735
0
}
736
737
static BOOL input_recv_unicode_keyboard_event(rdpInput* input, wStream* s)
738
0
{
739
0
  UINT16 keyboardFlags = 0;
740
0
  UINT16 unicodeCode = 0;
741
742
0
  WINPR_ASSERT(input);
743
0
  WINPR_ASSERT(s);
744
745
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
746
0
    return FALSE;
747
748
0
  Stream_Read_UINT16(s, keyboardFlags); /* keyboardFlags (2 bytes) */
749
0
  Stream_Read_UINT16(s, unicodeCode);   /* unicodeCode (2 bytes) */
750
0
  Stream_Seek(s, 2);                    /* pad2Octets (2 bytes) */
751
752
  /* "fix" keyboardFlags - see comment in input_recv_keyboard_event() */
753
754
0
  if (keyboardFlags & KBD_FLAGS_RELEASE)
755
0
    keyboardFlags &= ~KBD_FLAGS_DOWN;
756
757
  /* only pass input if we are actually connected */
758
0
  if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
759
0
    return TRUE;
760
0
  return IFCALLRESULT(TRUE, input->UnicodeKeyboardEvent, input, keyboardFlags, unicodeCode);
761
0
}
762
763
static BOOL input_recv_mouse_event(rdpInput* input, wStream* s)
764
0
{
765
0
  UINT16 pointerFlags = 0;
766
0
  UINT16 xPos = 0;
767
0
  UINT16 yPos = 0;
768
769
0
  WINPR_ASSERT(input);
770
0
  WINPR_ASSERT(s);
771
772
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
773
0
    return FALSE;
774
775
0
  Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
776
0
  Stream_Read_UINT16(s, xPos);         /* xPos (2 bytes) */
777
0
  Stream_Read_UINT16(s, yPos);         /* yPos (2 bytes) */
778
779
  /* only pass input if we are actually connected */
780
0
  if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
781
0
    return TRUE;
782
0
  return IFCALLRESULT(TRUE, input->MouseEvent, input, pointerFlags, xPos, yPos);
783
0
}
784
785
static BOOL input_recv_relmouse_event(rdpInput* input, wStream* s)
786
0
{
787
0
  UINT16 pointerFlags = 0;
788
0
  INT16 xDelta = 0;
789
0
  INT16 yDelta = 0;
790
791
0
  WINPR_ASSERT(input);
792
0
  WINPR_ASSERT(s);
793
794
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
795
0
    return FALSE;
796
797
0
  Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
798
0
  Stream_Read_INT16(s, xDelta);        /* xPos (2 bytes) */
799
0
  Stream_Read_INT16(s, yDelta);        /* yPos (2 bytes) */
800
801
0
  if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasRelativeMouseEvent))
802
0
  {
803
0
    WLog_ERR(TAG,
804
0
             "Received relative mouse event(flags=0x%04" PRIx16 ", xPos=%" PRId16
805
0
             ", yPos=%" PRId16 "), but we did not announce support for that",
806
0
             pointerFlags, xDelta, yDelta);
807
0
    return FALSE;
808
0
  }
809
810
  /* only pass input if we are actually connected */
811
0
  if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
812
0
    return TRUE;
813
814
0
  return IFCALLRESULT(TRUE, input->RelMouseEvent, input, pointerFlags, xDelta, yDelta);
815
0
}
816
817
static BOOL input_recv_extended_mouse_event(rdpInput* input, wStream* s)
818
0
{
819
0
  UINT16 pointerFlags = 0;
820
0
  UINT16 xPos = 0;
821
0
  UINT16 yPos = 0;
822
823
0
  WINPR_ASSERT(input);
824
0
  WINPR_ASSERT(s);
825
826
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
827
0
    return FALSE;
828
829
0
  Stream_Read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
830
0
  Stream_Read_UINT16(s, xPos);         /* xPos (2 bytes) */
831
0
  Stream_Read_UINT16(s, yPos);         /* yPos (2 bytes) */
832
833
0
  if (!freerdp_settings_get_bool(input->context->settings, FreeRDP_HasExtendedMouseEvent))
834
0
  {
835
0
    WLog_ERR(TAG,
836
0
             "Received extended mouse event(flags=0x%04" PRIx16 ", xPos=%" PRIu16
837
0
             ", yPos=%" PRIu16 "), but we did not announce support for that",
838
0
             pointerFlags, xPos, yPos);
839
0
    return FALSE;
840
0
  }
841
842
  /* only pass input if we are actually connected */
843
0
  if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
844
0
    return TRUE;
845
0
  return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, pointerFlags, xPos, yPos);
846
0
}
847
848
static BOOL input_recv_event(rdpInput* input, wStream* s)
849
0
{
850
0
  UINT16 messageType = 0;
851
852
0
  WINPR_ASSERT(input);
853
0
  WINPR_ASSERT(s);
854
855
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
856
0
    return FALSE;
857
858
0
  Stream_Seek(s, 4);                  /* eventTime (4 bytes), ignored by the server */
859
0
  Stream_Read_UINT16(s, messageType); /* messageType (2 bytes) */
860
861
0
  switch (messageType)
862
0
  {
863
0
    case INPUT_EVENT_SYNC:
864
0
      if (!input_recv_sync_event(input, s))
865
0
        return FALSE;
866
867
0
      break;
868
869
0
    case INPUT_EVENT_SCANCODE:
870
0
      if (!input_recv_keyboard_event(input, s))
871
0
        return FALSE;
872
873
0
      break;
874
875
0
    case INPUT_EVENT_UNICODE:
876
0
      if (!input_recv_unicode_keyboard_event(input, s))
877
0
        return FALSE;
878
879
0
      break;
880
881
0
    case INPUT_EVENT_MOUSE:
882
0
      if (!input_recv_mouse_event(input, s))
883
0
        return FALSE;
884
885
0
      break;
886
887
0
    case INPUT_EVENT_MOUSEX:
888
0
      if (!input_recv_extended_mouse_event(input, s))
889
0
        return FALSE;
890
891
0
      break;
892
893
0
    case INPUT_EVENT_MOUSEREL:
894
0
      if (!input_recv_relmouse_event(input, s))
895
0
        return FALSE;
896
897
0
      break;
898
899
0
    default:
900
0
      WLog_ERR(TAG, "Unknown messageType %" PRIu16 "", messageType);
901
      /* Each input event uses 6 bytes. */
902
0
      if (!Stream_SafeSeek(s, 6))
903
0
        return FALSE;
904
0
      break;
905
0
  }
906
907
0
  return TRUE;
908
0
}
909
910
BOOL input_recv(rdpInput* input, wStream* s)
911
0
{
912
0
  UINT16 numberEvents = 0;
913
914
0
  WINPR_ASSERT(input);
915
0
  WINPR_ASSERT(s);
916
917
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
918
0
    return FALSE;
919
920
0
  Stream_Read_UINT16(s, numberEvents); /* numberEvents (2 bytes) */
921
0
  Stream_Seek(s, 2);                   /* pad2Octets (2 bytes) */
922
923
  /* Each input event uses 6 exactly bytes. */
924
0
  if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, numberEvents, 6ull))
925
0
    return FALSE;
926
927
0
  for (UINT16 i = 0; i < numberEvents; i++)
928
0
  {
929
0
    if (!input_recv_event(input, s))
930
0
      return FALSE;
931
0
  }
932
933
0
  return TRUE;
934
0
}
935
936
BOOL input_register_client_callbacks(rdpInput* input)
937
0
{
938
0
  rdpSettings* settings = nullptr;
939
940
0
  if (!input->context)
941
0
    return FALSE;
942
943
0
  settings = input->context->settings;
944
945
0
  if (!settings)
946
0
    return FALSE;
947
948
0
  if (freerdp_settings_get_bool(settings, FreeRDP_FastPathInput))
949
0
  {
950
0
    input->SynchronizeEvent = input_send_fastpath_synchronize_event;
951
0
    input->KeyboardEvent = input_send_fastpath_keyboard_event;
952
0
    input->KeyboardPauseEvent = input_send_fastpath_keyboard_pause_event;
953
0
    input->UnicodeKeyboardEvent = input_send_fastpath_unicode_keyboard_event;
954
0
    input->MouseEvent = input_send_fastpath_mouse_event;
955
0
    input->RelMouseEvent = input_send_fastpath_relmouse_event;
956
0
    input->ExtendedMouseEvent = input_send_fastpath_extended_mouse_event;
957
0
    input->FocusInEvent = input_send_fastpath_focus_in_event;
958
0
    input->QoEEvent = input_send_fastpath_qoe_event;
959
0
  }
960
0
  else
961
0
  {
962
0
    input->SynchronizeEvent = input_send_synchronize_event;
963
0
    input->KeyboardEvent = input_send_keyboard_event;
964
0
    input->KeyboardPauseEvent = input_send_keyboard_pause_event;
965
0
    input->UnicodeKeyboardEvent = input_send_unicode_keyboard_event;
966
0
    input->MouseEvent = input_send_mouse_event;
967
0
    input->RelMouseEvent = input_send_relmouse_event;
968
0
    input->ExtendedMouseEvent = input_send_extended_mouse_event;
969
0
    input->FocusInEvent = input_send_focus_in_event;
970
0
  }
971
972
0
  return TRUE;
973
0
}
974
975
/* Save last input timestamp and/or mouse position in prevent-session-lock mode */
976
static BOOL input_update_last_event(rdpInput* input, BOOL mouse, UINT16 x, UINT16 y)
977
0
{
978
0
  rdp_input_internal* in = input_cast(input);
979
980
0
  WINPR_ASSERT(input);
981
0
  WINPR_ASSERT(input->context);
982
983
0
  if (freerdp_settings_get_uint32(input->context->settings, FreeRDP_FakeMouseMotionInterval) > 0)
984
0
  {
985
0
    const time_t now = time(nullptr);
986
0
    in->lastInputTimestamp = WINPR_ASSERTING_INT_CAST(UINT64, now);
987
988
0
    if (mouse)
989
0
    {
990
0
      in->lastX = x;
991
0
      in->lastY = y;
992
0
    }
993
0
  }
994
0
  return TRUE;
995
0
}
996
997
WINPR_ATTR_NODISCARD
998
static const char* boolstr(bool value)
999
0
{
1000
0
  if (value)
1001
0
    return "true";
1002
0
  return "false";
1003
0
}
1004
1005
WINPR_ATTR_NODISCARD
1006
WINPR_ATTR_FORMAT_ARG(2, 3)
1007
static BOOL input_skip(const rdpInput* input, WINPR_FORMAT_ARG const char* fmt, ...)
1008
0
{
1009
0
  WINPR_ASSERT(input);
1010
1011
0
  const rdpContext* context = input->context;
1012
0
  WINPR_ASSERT(context);
1013
1014
0
  const rdp_input_internal* in = (const rdp_input_internal*)input;
1015
0
  WINPR_ASSERT(in);
1016
1017
0
  const BOOL suspended = freerdp_settings_get_bool(context->settings, FreeRDP_SuspendInput);
1018
0
  const BOOL connected = freerdp_is_active_state(context);
1019
0
  const DWORD loglevel = WLOG_DEBUG;
1020
1021
0
  if (WLog_IsLevelActive(in->log, loglevel))
1022
0
  {
1023
0
    char buffer[128] = WINPR_C_ARRAY_INIT;
1024
1025
0
    va_list args = WINPR_C_ARRAY_INIT;
1026
0
    va_start(args, fmt);
1027
0
    (void)vsnprintf(buffer, sizeof(buffer), fmt, args);
1028
0
    va_end(args);
1029
1030
0
    WLog_Print(in->log, loglevel, "[connected=%s, suspended=%s] %s", boolstr(connected),
1031
0
               boolstr(suspended), buffer);
1032
0
  }
1033
1034
0
  return suspended || !connected;
1035
0
}
1036
1037
BOOL freerdp_input_send_synchronize_event(rdpInput* input, UINT32 flags)
1038
0
{
1039
0
  if (!input || !input->context)
1040
0
    return FALSE;
1041
1042
0
  char buffer[128] = WINPR_C_ARRAY_INIT;
1043
0
  if (input_skip(input, "Keyboard {Sync} [%s]",
1044
0
                 freerdp_input_keyboard_flags_string(flags, buffer, sizeof(buffer))))
1045
0
    return TRUE;
1046
1047
0
  return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, flags);
1048
0
}
1049
1050
BOOL freerdp_input_send_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
1051
0
{
1052
0
  if (!input || !input->context)
1053
0
    return FALSE;
1054
1055
0
  char buffer[128] = WINPR_C_ARRAY_INIT;
1056
0
  if (input_skip(input, "Keyboard {Event} [%s]",
1057
0
                 freerdp_input_keypress_flags_string(flags, buffer, sizeof(buffer))))
1058
0
    return TRUE;
1059
1060
0
  input_update_last_event(input, FALSE, 0, 0);
1061
1062
0
  return IFCALLRESULT(TRUE, input->KeyboardEvent, input, flags, code);
1063
0
}
1064
1065
BOOL freerdp_input_send_keyboard_event_ex(rdpInput* input, BOOL down, BOOL repeat,
1066
                                          UINT32 rdp_scancode)
1067
0
{
1068
0
  UINT16 flags = (RDP_SCANCODE_EXTENDED(rdp_scancode) ? KBD_FLAGS_EXTENDED : 0);
1069
0
  if (down && repeat)
1070
0
    flags |= KBD_FLAGS_DOWN;
1071
0
  else if (!down)
1072
0
    flags |= KBD_FLAGS_RELEASE;
1073
1074
0
  return freerdp_input_send_keyboard_event(input, flags, RDP_SCANCODE_CODE(rdp_scancode));
1075
0
}
1076
1077
BOOL freerdp_input_send_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
1078
0
{
1079
0
  if (!input || !input->context)
1080
0
    return FALSE;
1081
1082
0
  char buffer[128] = WINPR_C_ARRAY_INIT;
1083
0
  if (input_skip(input, "Keyboard {Unicode} [%s]",
1084
0
                 freerdp_input_keypress_flags_string(flags, buffer, ARRAYSIZE(buffer))))
1085
0
    return TRUE;
1086
1087
0
  input_update_last_event(input, FALSE, 0, 0);
1088
1089
0
  return IFCALLRESULT(TRUE, input->UnicodeKeyboardEvent, input, flags, code);
1090
0
}
1091
1092
BOOL freerdp_input_send_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
1093
0
{
1094
0
  if (!input || !input->context)
1095
0
    return FALSE;
1096
1097
0
  char buffer[128] = WINPR_C_ARRAY_INIT;
1098
0
  if (input_skip(input, "Mouse {Event} [%s]",
1099
0
                 freerdp_input_mouse_flags_string(flags, false, buffer, ARRAYSIZE(buffer))))
1100
0
    return TRUE;
1101
1102
0
  input_update_last_event(
1103
0
      input, flags & (PTR_FLAGS_MOVE | PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 | PTR_FLAGS_BUTTON3),
1104
0
      x, y);
1105
1106
0
  return IFCALLRESULT(TRUE, input->MouseEvent, input, flags, x, y);
1107
0
}
1108
1109
BOOL freerdp_input_send_rel_mouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, INT16 yDelta)
1110
0
{
1111
0
  if (!input || !input->context)
1112
0
    return FALSE;
1113
1114
0
  char buffer[128] = WINPR_C_ARRAY_INIT;
1115
0
  if (input_skip(input, "Mouse {RelativeEvent} [%s]",
1116
0
                 freerdp_input_mouse_flags_string(flags, true, buffer, ARRAYSIZE(buffer))))
1117
0
    return TRUE;
1118
1119
0
  return IFCALLRESULT(TRUE, input->RelMouseEvent, input, flags, xDelta, yDelta);
1120
0
}
1121
1122
BOOL freerdp_input_send_qoe_timestamp(rdpInput* input, UINT32 timestampMS)
1123
0
{
1124
0
  if (!input || !input->context)
1125
0
    return FALSE;
1126
1127
0
  return IFCALLRESULT(TRUE, input->QoEEvent, input, timestampMS);
1128
0
}
1129
1130
BOOL freerdp_input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
1131
0
{
1132
0
  if (!input || !input->context)
1133
0
    return FALSE;
1134
1135
0
  char buffer[128] = WINPR_C_ARRAY_INIT;
1136
0
  if (input_skip(input, "Mouse {ExtendedEvent} %s",
1137
0
                 freerdp_input_mouse_flags_string(flags, true, buffer, ARRAYSIZE(buffer))))
1138
0
    return TRUE;
1139
1140
0
  input_update_last_event(input, TRUE, x, y);
1141
1142
0
  return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, flags, x, y);
1143
0
}
1144
1145
BOOL freerdp_input_send_focus_in_event(rdpInput* input, UINT16 toggleStates)
1146
0
{
1147
0
  if (!input || !input->context)
1148
0
    return FALSE;
1149
1150
0
  char buffer[128] = WINPR_C_ARRAY_INIT;
1151
0
  if (input_skip(input, "Keyboard {FocusIn} [%s]",
1152
0
                 freerdp_input_keyboard_flags_string(toggleStates, buffer, sizeof(buffer))))
1153
0
    return TRUE;
1154
1155
0
  return IFCALLRESULT(TRUE, input->FocusInEvent, input, toggleStates);
1156
0
}
1157
1158
BOOL freerdp_input_send_keyboard_pause_event(rdpInput* input)
1159
0
{
1160
0
  if (!input || !input->context)
1161
0
    return FALSE;
1162
1163
0
  if (input_skip(input, "Keyboard {Pause}"))
1164
0
    return TRUE;
1165
1166
0
  return IFCALLRESULT(TRUE, input->KeyboardPauseEvent, input);
1167
0
}
1168
1169
int input_process_events(rdpInput* input)
1170
0
{
1171
0
  if (!input)
1172
0
    return FALSE;
1173
1174
0
  return input_message_queue_process_pending_messages(input);
1175
0
}
1176
1177
static void input_free_queued_message(void* obj)
1178
0
{
1179
0
  wMessage* msg = (wMessage*)obj;
1180
0
  input_message_queue_free_message(msg);
1181
0
}
1182
1183
rdpInput* input_new(rdpRdp* rdp)
1184
21.4k
{
1185
21.4k
  const wObject cb = { nullptr, nullptr, nullptr, input_free_queued_message, nullptr };
1186
21.4k
  rdp_input_internal* input = (rdp_input_internal*)calloc(1, sizeof(rdp_input_internal));
1187
1188
21.4k
  WINPR_UNUSED(rdp);
1189
1190
21.4k
  if (!input)
1191
0
    return nullptr;
1192
1193
21.4k
  input->common.context = rdp->context;
1194
21.4k
  input->queue = MessageQueue_New(&cb);
1195
21.4k
  input->log = WLog_Get(TAG);
1196
1197
21.4k
  if (!input->queue)
1198
0
  {
1199
0
    free(input);
1200
0
    return nullptr;
1201
0
  }
1202
1203
21.4k
  return &input->common;
1204
21.4k
}
1205
1206
void input_free(rdpInput* input)
1207
21.4k
{
1208
21.4k
  if (input != nullptr)
1209
21.4k
  {
1210
21.4k
    rdp_input_internal* in = input_cast(input);
1211
1212
21.4k
    MessageQueue_Free(in->queue);
1213
21.4k
    free(in);
1214
21.4k
  }
1215
21.4k
}
1216
1217
static const char* flag2str(uint32_t flag, bool extended)
1218
0
{
1219
0
#define EVCASE(x) \
1220
0
  case x:       \
1221
0
    return #x
1222
0
  if (extended)
1223
0
  {
1224
0
    switch (flag)
1225
0
    {
1226
      /* Extended Pointer Flags */
1227
0
      EVCASE(PTR_XFLAGS_DOWN);
1228
0
      EVCASE(PTR_XFLAGS_BUTTON1);
1229
0
      EVCASE(PTR_XFLAGS_BUTTON2);
1230
0
      default:
1231
0
        return "PTR_XFLAGS_UNKNOWN";
1232
0
    }
1233
0
  }
1234
1235
0
  switch (flag)
1236
0
  {
1237
    /* Pointer Flags */
1238
0
    EVCASE(PTR_FLAGS_HWHEEL);
1239
0
    EVCASE(PTR_FLAGS_WHEEL);
1240
0
    EVCASE(PTR_FLAGS_WHEEL_NEGATIVE);
1241
0
    EVCASE(PTR_FLAGS_MOVE);
1242
0
    EVCASE(PTR_FLAGS_DOWN);
1243
0
    EVCASE(PTR_FLAGS_BUTTON1);
1244
0
    EVCASE(PTR_FLAGS_BUTTON2);
1245
0
    EVCASE(PTR_FLAGS_BUTTON3);
1246
0
    default:
1247
0
      return "PTR_FLAGS_UNKNOWN";
1248
0
  }
1249
0
#undef EVCASE
1250
0
}
1251
1252
const char* freerdp_input_mouse_flags_string(uint32_t flags, bool extended, char* buffer,
1253
                                             size_t len)
1254
0
{
1255
0
  if (len <= 2)
1256
0
    return nullptr;
1257
1258
0
  if (!winpr_str_append("{", buffer, len, ""))
1259
0
    return nullptr;
1260
1261
  /* Strip initial symbol so we do not get duplicate separators */
1262
0
  for (size_t x = 0; x < 32; x++)
1263
0
  {
1264
0
    const uint32_t flag = 1u << x;
1265
0
    if (flags & flag)
1266
0
    {
1267
0
      char ibuffer[64] = WINPR_C_ARRAY_INIT;
1268
0
      (void)_snprintf(ibuffer, sizeof(ibuffer), "%s", flag2str(flag, extended));
1269
0
      if (!winpr_str_append(ibuffer, &buffer[1], len - 2, "|"))
1270
0
        return nullptr;
1271
0
    }
1272
0
  }
1273
0
  if (!winpr_str_append("}", &buffer[1], len - 2, ""))
1274
0
    return nullptr;
1275
1276
0
  return buffer;
1277
0
}
1278
1279
static const char* kbdflag2str(uint32_t flag)
1280
0
{
1281
0
#define EVCASE(x) \
1282
0
  case x:       \
1283
0
    return #x
1284
1285
0
  switch (flag)
1286
0
  {
1287
    /* Pointer Flags */
1288
0
    EVCASE(KBD_FLAGS_EXTENDED);
1289
0
    EVCASE(KBD_FLAGS_EXTENDED1);
1290
0
    EVCASE(KBD_FLAGS_DOWN);
1291
0
    EVCASE(KBD_FLAGS_RELEASE);
1292
0
    default:
1293
0
      return "KBD_FLAGS_UNKNOWN";
1294
0
  }
1295
0
#undef EVCASE
1296
0
}
1297
1298
const char* freerdp_input_keypress_flags_string(uint32_t flags, char* buffer, size_t len)
1299
0
{
1300
0
  if (len <= 2)
1301
0
    return nullptr;
1302
1303
0
  if (!winpr_str_append("{", buffer, len, ""))
1304
0
    return nullptr;
1305
1306
  /* Strip initial symbol so we do not get duplicate separators */
1307
0
  for (size_t x = 0; x < 32; x++)
1308
0
  {
1309
0
    const uint32_t flag = 1u << x;
1310
0
    if (flags & flag)
1311
0
    {
1312
0
      char ibuffer[64] = WINPR_C_ARRAY_INIT;
1313
0
      (void)_snprintf(ibuffer, sizeof(ibuffer), "%s", kbdflag2str(flag));
1314
0
      if (!winpr_str_append(ibuffer, &buffer[1], len - 2, "|"))
1315
0
        return nullptr;
1316
0
    }
1317
0
  }
1318
0
  if (!winpr_str_append("}", &buffer[1], len - 2, ""))
1319
0
    return nullptr;
1320
1321
0
  return buffer;
1322
0
}