21#include <freerdp/config.h>
24#include <winpr/assert.h>
26#include <freerdp/input.h>
27#include <freerdp/log.h>
33#define TAG FREERDP_TAG("core")
36#define INPUT_EVENT_SYNC 0x0000
37#define INPUT_EVENT_SCANCODE 0x0004
38#define INPUT_EVENT_UNICODE 0x0005
39#define INPUT_EVENT_MOUSE 0x8001
40#define INPUT_EVENT_MOUSEX 0x8002
41#define INPUT_EVENT_MOUSEREL 0x8004
43static const char* SyncEventFlag2Str(uint32_t flag)
45 if (flag == KBD_SYNC_SCROLL_LOCK)
46 return "SYNC_SCROLL_LOCK";
47 if (flag == KBD_SYNC_NUM_LOCK)
48 return "SYNC_NUM_LOCK";
49 if (flag == KBD_SYNC_CAPS_LOCK)
50 return "SYNC_CAPS_LOCK";
51 if (flag == KBD_SYNC_KANA_LOCK)
52 return "SYNC_KANA_LOCK";
53 return "SYNC_UNKNOWN";
56static const char* SyncEventFlags2Str(
const char* prefix, uint32_t flags,
char* buffer,
size_t len)
58 const uint32_t tflags[] = { KBD_SYNC_SCROLL_LOCK, KBD_SYNC_NUM_LOCK, KBD_SYNC_CAPS_LOCK,
64 if (!winpr_str_append(
"{", buffer, len,
""))
68 for (
size_t x = 0; x < ARRAYSIZE(tflags); x++)
70 const uint32_t flag = tflags[x];
73 char ibuffer[64] = WINPR_C_ARRAY_INIT;
74 (void)_snprintf(ibuffer,
sizeof(ibuffer),
"%s%s", prefix, SyncEventFlag2Str(flag));
75 if (!winpr_str_append(ibuffer, &buffer[1], len - 2,
"|"))
79 if (!winpr_str_append(
"}", &buffer[1], len - 2,
""))
85const char* freerdp_input_keyboard_flags_string(uint32_t flags,
char* buffer,
size_t len)
87 return SyncEventFlags2Str(
"KBD_", flags, buffer, len);
90static void rdp_write_client_input_pdu_header(
wStream* s, UINT16 number)
93 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 4);
94 Stream_Write_UINT16(s, number);
95 Stream_Write_UINT16(s, 0);
98static void rdp_write_input_event_header(
wStream* s, UINT32 time, UINT16 type)
101 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 6);
102 Stream_Write_UINT32(s, time);
103 Stream_Write_UINT16(s, type);
106static wStream* rdp_client_input_pdu_init(rdpRdp* rdp, UINT16 type, UINT16* sec_flags)
108 wStream* s = rdp_data_pdu_init(rdp, sec_flags);
113 rdp_write_client_input_pdu_header(s, 1);
114 rdp_write_input_event_header(s, 0, type);
118static BOOL rdp_send_client_input_pdu(rdpRdp* rdp,
wStream* s, UINT16 sec_flags)
121 WINPR_ASSERT(rdp->mcs);
122 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_INPUT, rdp->mcs->userId, sec_flags);
125static void input_write_synchronize_event(
wStream* s, UINT32 flags)
128 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 6);
129 Stream_Write_UINT16(s, 0);
130 Stream_Write_UINT32(s, flags);
133static BOOL input_ensure_client_running(rdpInput* input)
136 if (freerdp_shall_disconnect_context(input->context))
138 WLog_WARN(TAG,
"[APPLICATION BUG] input functions called after the session terminated");
144static BOOL input_send_synchronize_event(rdpInput* input, UINT32 flags)
146 UINT16 sec_flags = 0;
148 if (!input || !input->context)
151 rdpRdp* rdp = input->context->rdp;
153 if (!input_ensure_client_running(input))
156 wStream* s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_SYNC, &sec_flags);
161 input_write_synchronize_event(s, flags);
162 return rdp_send_client_input_pdu(rdp, s, sec_flags);
165static void input_write_keyboard_event(
wStream* s, UINT16 flags, UINT16 code)
168 WINPR_ASSERT(code <= UINT8_MAX);
170 Stream_Write_UINT16(s, flags);
171 Stream_Write_UINT16(s, code);
172 Stream_Write_UINT16(s, 0);
175static BOOL input_send_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
177 UINT16 sec_flags = 0;
179 rdpRdp* rdp =
nullptr;
181 if (!input || !input->context)
184 rdp = input->context->rdp;
186 if (!input_ensure_client_running(input))
189 s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_SCANCODE, &sec_flags);
194 input_write_keyboard_event(s, flags, code);
195 return rdp_send_client_input_pdu(rdp, s, sec_flags);
198static void input_write_unicode_keyboard_event(
wStream* s, UINT16 flags, UINT16 code)
200 Stream_Write_UINT16(s, flags);
201 Stream_Write_UINT16(s, code);
202 Stream_Write_UINT16(s, 0);
205static BOOL input_send_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
207 UINT16 sec_flags = 0;
209 rdpRdp* rdp =
nullptr;
211 if (!input || !input->context)
214 if (!input_ensure_client_running(input))
219 WLog_WARN(TAG,
"Unicode input not supported by server.");
223 rdp = input->context->rdp;
224 s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_UNICODE, &sec_flags);
229 input_write_unicode_keyboard_event(s, flags, code);
230 return rdp_send_client_input_pdu(rdp, s, sec_flags);
233static void input_write_mouse_event(
wStream* s, UINT16 flags, UINT16 x, UINT16 y)
235 Stream_Write_UINT16(s, flags);
236 Stream_Write_UINT16(s, x);
237 Stream_Write_UINT16(s, y);
240static BOOL input_send_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
242 UINT16 sec_flags = 0;
244 if (!input || !input->context || !input->context->settings)
247 rdpRdp* rdp = input->context->rdp;
249 if (!input_ensure_client_running(input))
254 if (flags & PTR_FLAGS_HWHEEL)
257 "skip mouse event %" PRIu16
"x%" PRIu16
" flags=0x%04" PRIX16
258 ", no horizontal mouse wheel supported",
264 wStream* s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_MOUSE, &sec_flags);
269 input_write_mouse_event(s, flags, x, y);
270 return rdp_send_client_input_pdu(rdp, s, sec_flags);
273static BOOL input_send_relmouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, INT16 yDelta)
275 UINT16 sec_flags = 0;
277 rdpRdp* rdp =
nullptr;
279 if (!input || !input->context || !input->context->settings)
282 rdp = input->context->rdp;
284 if (!input_ensure_client_running(input))
289 WLog_ERR(TAG,
"Sending relative mouse event, but no support for that");
293 s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_MOUSEREL, &sec_flags);
298 Stream_Write_UINT16(s, flags);
299 Stream_Write_INT16(s, xDelta);
300 Stream_Write_INT16(s, yDelta);
302 return rdp_send_client_input_pdu(rdp, s, sec_flags);
305static void input_write_extended_mouse_event(
wStream* s, UINT16 flags, UINT16 x, UINT16 y)
307 Stream_Write_UINT16(s, flags);
308 Stream_Write_UINT16(s, x);
309 Stream_Write_UINT16(s, y);
312static BOOL input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
314 UINT16 sec_flags = 0;
317 WINPR_ASSERT(input->context);
318 WINPR_ASSERT(input->context->settings);
320 rdpRdp* rdp = input->context->rdp;
323 if (!input_ensure_client_running(input))
329 "skip extended mouse event %" PRIu16
"x%" PRIu16
" flags=0x%04" PRIX16
330 ", no extended mouse events supported",
335 wStream* s = rdp_client_input_pdu_init(rdp, INPUT_EVENT_MOUSEX, &sec_flags);
340 input_write_extended_mouse_event(s, flags, x, y);
341 return rdp_send_client_input_pdu(rdp, s, sec_flags);
344static BOOL input_send_focus_in_event(rdpInput* input, UINT16 toggleStates)
347 if (!input_send_keyboard_event(input, KBD_FLAGS_RELEASE, 0x0f))
351 if (!input_send_synchronize_event(input, (toggleStates & 0x1F)))
355 return input_send_keyboard_event(input, KBD_FLAGS_RELEASE, 0x0f);
358static BOOL input_send_keyboard_pause_event(rdpInput* input)
366 if (!input_send_keyboard_event(input, KBD_FLAGS_EXTENDED1,
367 RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)))
371 if (!input_send_keyboard_event(input, 0, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK)))
375 if (!input_send_keyboard_event(input, KBD_FLAGS_RELEASE | KBD_FLAGS_EXTENDED1,
376 RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL)))
380 return input_send_keyboard_event(input, KBD_FLAGS_RELEASE,
381 RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK));
384static BOOL input_send_fastpath_synchronize_event(rdpInput* input, UINT32 flags)
387 WINPR_ASSERT(input->context);
393 KBD_SYNC_SCROLL_LOCK | KBD_SYNC_NUM_LOCK | KBD_SYNC_CAPS_LOCK | KBD_SYNC_KANA_LOCK;
396 "Problematic [MS-RDPBCGR] 2.2.8.1.2.2.5 Fast-Path Synchronize Event "
397 "(TS_FP_SYNC_EVENT) flags=0x%08" PRIx32
", ignoring undefined bits.",
399 rdpRdp* rdp = input->context->rdp;
402 if (!input_ensure_client_running(input))
406 UINT16 sec_flags = 0;
408 fastpath_input_pdu_init(rdp->fastpath, (BYTE)flags, FASTPATH_INPUT_EVENT_SYNC, &sec_flags);
413 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
416static BOOL input_send_fastpath_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
418 UINT16 sec_flags = 0;
421 rdpRdp* rdp =
nullptr;
424 WINPR_ASSERT(input->context);
426 rdp = input->context->rdp;
429 if (!input_ensure_client_running(input))
432 eventFlags |= (flags & KBD_FLAGS_RELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0;
433 eventFlags |= (flags & KBD_FLAGS_EXTENDED) ? FASTPATH_INPUT_KBDFLAGS_EXTENDED : 0;
434 eventFlags |= (flags & KBD_FLAGS_EXTENDED1) ? FASTPATH_INPUT_KBDFLAGS_PREFIX_E1 : 0;
435 s = fastpath_input_pdu_init(rdp->fastpath, eventFlags, FASTPATH_INPUT_EVENT_SCANCODE,
441 WINPR_ASSERT(code <= UINT8_MAX);
442 Stream_Write_UINT8(s, code);
443 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
446static BOOL input_send_fastpath_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
448 UINT16 sec_flags = 0;
451 rdpRdp* rdp =
nullptr;
454 WINPR_ASSERT(input->context);
455 WINPR_ASSERT(input->context->settings);
457 rdp = input->context->rdp;
460 if (!input_ensure_client_running(input))
465 WLog_WARN(TAG,
"Unicode input not supported by server.");
469 eventFlags |= (flags & KBD_FLAGS_RELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0;
470 s = fastpath_input_pdu_init(rdp->fastpath, eventFlags, FASTPATH_INPUT_EVENT_UNICODE,
476 Stream_Write_UINT16(s, code);
477 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
480static BOOL input_send_fastpath_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
482 UINT16 sec_flags = 0;
484 rdpRdp* rdp =
nullptr;
487 WINPR_ASSERT(input->context);
488 WINPR_ASSERT(input->context->settings);
490 rdp = input->context->rdp;
493 if (!input_ensure_client_running(input))
498 if (flags & PTR_FLAGS_HWHEEL)
501 "skip mouse event %" PRIu16
"x%" PRIu16
" flags=0x%04" PRIX16
502 ", no horizontal mouse wheel supported",
508 s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSE, &sec_flags);
513 input_write_mouse_event(s, flags, x, y);
514 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
517static BOOL input_send_fastpath_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x,
520 UINT16 sec_flags = 0;
522 rdpRdp* rdp =
nullptr;
525 WINPR_ASSERT(input->context);
527 rdp = input->context->rdp;
530 if (!input_ensure_client_running(input))
536 "skip extended mouse event %" PRIu16
"x%" PRIu16
" flags=0x%04" PRIX16
537 ", no extended mouse events supported",
542 s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSEX, &sec_flags);
547 input_write_extended_mouse_event(s, flags, x, y);
548 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
551static BOOL input_send_fastpath_relmouse_event(rdpInput* input, UINT16 flags, INT16 xDelta,
554 UINT16 sec_flags = 0;
556 rdpRdp* rdp =
nullptr;
559 WINPR_ASSERT(input->context);
560 WINPR_ASSERT(input->context->settings);
562 rdp = input->context->rdp;
565 if (!input_ensure_client_running(input))
570 WLog_ERR(TAG,
"Sending relative fastpath mouse event, but no support for that announced");
574 s = fastpath_input_pdu_init(rdp->fastpath, 0, TS_FP_RELPOINTER_EVENT, &sec_flags);
579 Stream_Write_UINT16(s, flags);
580 Stream_Write_INT16(s, xDelta);
581 Stream_Write_INT16(s, yDelta);
582 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
585static BOOL input_send_fastpath_qoe_event(rdpInput* input, UINT32 timestampMS)
588 WINPR_ASSERT(input->context);
589 WINPR_ASSERT(input->context->settings);
591 rdpRdp* rdp = input->context->rdp;
594 if (!input_ensure_client_running(input))
599 WLog_ERR(TAG,
"Sending qoe event, but no support for that announced");
603 UINT16 sec_flags = 0;
604 wStream* s = fastpath_input_pdu_init(rdp->fastpath, 0, TS_FP_QOETIMESTAMP_EVENT, &sec_flags);
609 if (!Stream_EnsureRemainingCapacity(s, 4))
611 Stream_Free(s, TRUE);
615 Stream_Write_UINT32(s, timestampMS);
616 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
619static BOOL input_send_fastpath_focus_in_event(rdpInput* input, UINT16 toggleStates)
621 UINT16 sec_flags = 0;
624 rdpRdp* rdp =
nullptr;
627 WINPR_ASSERT(input->context);
629 rdp = input->context->rdp;
632 if (!input_ensure_client_running(input))
635 s = fastpath_input_pdu_init_header(rdp->fastpath, &sec_flags);
641 eventFlags = FASTPATH_INPUT_KBDFLAGS_RELEASE | FASTPATH_INPUT_EVENT_SCANCODE << 5;
642 Stream_Write_UINT8(s, eventFlags);
643 Stream_Write_UINT8(s, 0x0f);
645 eventFlags = (toggleStates & 0x1F) | FASTPATH_INPUT_EVENT_SYNC << 5;
646 Stream_Write_UINT8(s, eventFlags);
648 eventFlags = FASTPATH_INPUT_KBDFLAGS_RELEASE | FASTPATH_INPUT_EVENT_SCANCODE << 5;
649 Stream_Write_UINT8(s, eventFlags);
650 Stream_Write_UINT8(s, 0x0f);
651 return fastpath_send_multiple_input_pdu(rdp->fastpath, s, 3, sec_flags);
654static BOOL input_send_fastpath_keyboard_pause_event(rdpInput* input)
660 UINT16 sec_flags = 0;
662 const BYTE keyDownEvent = FASTPATH_INPUT_EVENT_SCANCODE << 5;
663 const BYTE keyUpEvent = (FASTPATH_INPUT_EVENT_SCANCODE << 5) | FASTPATH_INPUT_KBDFLAGS_RELEASE;
664 rdpRdp* rdp =
nullptr;
667 WINPR_ASSERT(input->context);
669 rdp = input->context->rdp;
672 if (!input_ensure_client_running(input))
675 s = fastpath_input_pdu_init_header(rdp->fastpath, &sec_flags);
681 Stream_Write_UINT8(s, keyDownEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1);
682 Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL));
684 Stream_Write_UINT8(s, keyDownEvent);
685 Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK));
687 Stream_Write_UINT8(s, keyUpEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1);
688 Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL));
690 Stream_Write_UINT8(s, keyUpEvent);
691 Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK));
692 return fastpath_send_multiple_input_pdu(rdp->fastpath, s, 4, sec_flags);
695static BOOL input_recv_sync_event(rdpInput* input,
wStream* s)
697 UINT32 toggleFlags = 0;
702 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
706 Stream_Read_UINT32(s, toggleFlags);
709 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
711 return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, toggleFlags);
714static BOOL input_recv_keyboard_event(rdpInput* input,
wStream* s)
716 UINT16 keyboardFlags = 0;
722 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
725 Stream_Read_UINT16(s, keyboardFlags);
726 Stream_Read_UINT16(s, keyCode);
729 if (keyboardFlags & KBD_FLAGS_RELEASE)
730 keyboardFlags &= ~KBD_FLAGS_DOWN;
732 if (keyCode & 0xFF00)
734 "Problematic [MS-RDPBCGR] 2.2.8.1.1.3.1.1.1 Keyboard Event (TS_KEYBOARD_EVENT) "
735 "keyCode=0x%04" PRIx16
736 ", high byte values should be sent in keyboardFlags field, ignoring.",
740 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
742 return IFCALLRESULT(TRUE, input->KeyboardEvent, input, keyboardFlags, keyCode & 0xFF);
745static BOOL input_recv_unicode_keyboard_event(rdpInput* input,
wStream* s)
747 UINT16 keyboardFlags = 0;
748 UINT16 unicodeCode = 0;
753 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
756 Stream_Read_UINT16(s, keyboardFlags);
757 Stream_Read_UINT16(s, unicodeCode);
762 if (keyboardFlags & KBD_FLAGS_RELEASE)
763 keyboardFlags &= ~KBD_FLAGS_DOWN;
766 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
768 return IFCALLRESULT(TRUE, input->UnicodeKeyboardEvent, input, keyboardFlags, unicodeCode);
771static BOOL input_recv_mouse_event(rdpInput* input,
wStream* s)
773 UINT16 pointerFlags = 0;
780 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
783 Stream_Read_UINT16(s, pointerFlags);
784 Stream_Read_UINT16(s, xPos);
785 Stream_Read_UINT16(s, yPos);
788 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
790 return IFCALLRESULT(TRUE, input->MouseEvent, input, pointerFlags, xPos, yPos);
793static BOOL input_recv_relmouse_event(rdpInput* input,
wStream* s)
795 UINT16 pointerFlags = 0;
802 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
805 Stream_Read_UINT16(s, pointerFlags);
806 Stream_Read_INT16(s, xDelta);
807 Stream_Read_INT16(s, yDelta);
812 "Received relative mouse event(flags=0x%04" PRIx16
", xPos=%" PRId16
813 ", yPos=%" PRId16
"), but we did not announce support for that",
814 pointerFlags, xDelta, yDelta);
819 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
822 return IFCALLRESULT(TRUE, input->RelMouseEvent, input, pointerFlags, xDelta, yDelta);
825static BOOL input_recv_extended_mouse_event(rdpInput* input,
wStream* s)
827 UINT16 pointerFlags = 0;
834 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
837 Stream_Read_UINT16(s, pointerFlags);
838 Stream_Read_UINT16(s, xPos);
839 Stream_Read_UINT16(s, yPos);
844 "Received extended mouse event(flags=0x%04" PRIx16
", xPos=%" PRIu16
845 ", yPos=%" PRIu16
"), but we did not announce support for that",
846 pointerFlags, xPos, yPos);
851 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
853 return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, pointerFlags, xPos, yPos);
856static BOOL input_recv_event(rdpInput* input,
wStream* s)
858 UINT16 messageType = 0;
863 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
867 Stream_Read_UINT16(s, messageType);
871 case INPUT_EVENT_SYNC:
872 if (!input_recv_sync_event(input, s))
877 case INPUT_EVENT_SCANCODE:
878 if (!input_recv_keyboard_event(input, s))
883 case INPUT_EVENT_UNICODE:
884 if (!input_recv_unicode_keyboard_event(input, s))
889 case INPUT_EVENT_MOUSE:
890 if (!input_recv_mouse_event(input, s))
895 case INPUT_EVENT_MOUSEX:
896 if (!input_recv_extended_mouse_event(input, s))
901 case INPUT_EVENT_MOUSEREL:
902 if (!input_recv_relmouse_event(input, s))
908 WLog_ERR(TAG,
"Unknown messageType %" PRIu16
"", messageType);
910 if (!Stream_SafeSeek(s, 6))
918BOOL input_recv(rdpInput* input,
wStream* s)
920 UINT16 numberEvents = 0;
925 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
928 Stream_Read_UINT16(s, numberEvents);
932 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, numberEvents, 6ull))
935 for (UINT16 i = 0; i < numberEvents; i++)
937 if (!input_recv_event(input, s))
944BOOL input_register_client_callbacks(rdpInput* input)
946 rdpSettings* settings =
nullptr;
951 settings = input->context->settings;
958 input->SynchronizeEvent = input_send_fastpath_synchronize_event;
959 input->KeyboardEvent = input_send_fastpath_keyboard_event;
960 input->KeyboardPauseEvent = input_send_fastpath_keyboard_pause_event;
961 input->UnicodeKeyboardEvent = input_send_fastpath_unicode_keyboard_event;
962 input->MouseEvent = input_send_fastpath_mouse_event;
963 input->RelMouseEvent = input_send_fastpath_relmouse_event;
964 input->ExtendedMouseEvent = input_send_fastpath_extended_mouse_event;
965 input->FocusInEvent = input_send_fastpath_focus_in_event;
966 input->QoEEvent = input_send_fastpath_qoe_event;
970 input->SynchronizeEvent = input_send_synchronize_event;
971 input->KeyboardEvent = input_send_keyboard_event;
972 input->KeyboardPauseEvent = input_send_keyboard_pause_event;
973 input->UnicodeKeyboardEvent = input_send_unicode_keyboard_event;
974 input->MouseEvent = input_send_mouse_event;
975 input->RelMouseEvent = input_send_relmouse_event;
976 input->ExtendedMouseEvent = input_send_extended_mouse_event;
977 input->FocusInEvent = input_send_focus_in_event;
984static BOOL input_update_last_event(rdpInput* input, BOOL mouse, UINT16 x, UINT16 y)
989 WINPR_ASSERT(input->context);
993 const time_t now = time(
nullptr);
994 in->lastInputTimestamp = WINPR_ASSERTING_INT_CAST(UINT64, now);
1006static const char* boolstr(
bool value)
1014WINPR_ATTR_FORMAT_ARG(2, 3)
1015static BOOL input_skip(const rdpInput* input, WINPR_FORMAT_ARG const
char* fmt, ...)
1017 WINPR_ASSERT(input);
1019 const rdpContext* context = input->context;
1020 WINPR_ASSERT(context);
1026 const BOOL connected = freerdp_is_active_state(context);
1027 const DWORD loglevel = WLOG_DEBUG;
1029 if (WLog_IsLevelActive(in->log, loglevel))
1031 char buffer[128] = WINPR_C_ARRAY_INIT;
1033 va_list args = WINPR_C_ARRAY_INIT;
1034 va_start(args, fmt);
1035 (void)vsnprintf(buffer,
sizeof(buffer), fmt, args);
1038 WLog_Print(in->log, loglevel,
"[connected=%s, suspended=%s] %s", boolstr(connected),
1039 boolstr(suspended), buffer);
1042 return suspended || !connected;
1045BOOL freerdp_input_send_synchronize_event(rdpInput* input, UINT32 flags)
1047 if (!input || !input->context)
1050 char buffer[128] = WINPR_C_ARRAY_INIT;
1051 if (input_skip(input,
"Keyboard {Sync} [%s]",
1052 freerdp_input_keyboard_flags_string(flags, buffer,
sizeof(buffer))))
1055 return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, flags);
1058BOOL freerdp_input_send_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
1060 if (!input || !input->context)
1063 char buffer[128] = WINPR_C_ARRAY_INIT;
1064 if (input_skip(input,
"Keyboard {Event} [%s]",
1065 freerdp_input_keypress_flags_string(flags, buffer,
sizeof(buffer))))
1068 input_update_last_event(input, FALSE, 0, 0);
1070 return IFCALLRESULT(TRUE, input->KeyboardEvent, input, flags, code);
1073BOOL freerdp_input_send_keyboard_event_ex(rdpInput* input, BOOL down, BOOL repeat,
1074 UINT32 rdp_scancode)
1076 UINT16 flags = (RDP_SCANCODE_EXTENDED(rdp_scancode) ? KBD_FLAGS_EXTENDED : 0);
1078 flags |= KBD_FLAGS_DOWN;
1080 flags |= KBD_FLAGS_RELEASE;
1082 return freerdp_input_send_keyboard_event(input, flags, RDP_SCANCODE_CODE(rdp_scancode));
1085BOOL freerdp_input_send_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
1087 if (!input || !input->context)
1090 char buffer[128] = WINPR_C_ARRAY_INIT;
1091 if (input_skip(input,
"Keyboard {Unicode} [%s]",
1092 freerdp_input_keypress_flags_string(flags, buffer, ARRAYSIZE(buffer))))
1095 input_update_last_event(input, FALSE, 0, 0);
1097 return IFCALLRESULT(TRUE, input->UnicodeKeyboardEvent, input, flags, code);
1100BOOL freerdp_input_send_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
1102 if (!input || !input->context)
1105 char buffer[128] = WINPR_C_ARRAY_INIT;
1106 if (input_skip(input,
"Mouse {Event} [%s]",
1107 freerdp_input_mouse_flags_string(flags,
false, buffer, ARRAYSIZE(buffer))))
1110 input_update_last_event(
1111 input, flags & (PTR_FLAGS_MOVE | PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 | PTR_FLAGS_BUTTON3),
1114 return IFCALLRESULT(TRUE, input->MouseEvent, input, flags, x, y);
1117BOOL freerdp_input_send_rel_mouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, INT16 yDelta)
1119 if (!input || !input->context)
1122 char buffer[128] = WINPR_C_ARRAY_INIT;
1123 if (input_skip(input,
"Mouse {RelativeEvent} [%s]",
1124 freerdp_input_mouse_flags_string(flags,
true, buffer, ARRAYSIZE(buffer))))
1127 return IFCALLRESULT(TRUE, input->RelMouseEvent, input, flags, xDelta, yDelta);
1130BOOL freerdp_input_send_qoe_timestamp(rdpInput* input, UINT32 timestampMS)
1132 if (!input || !input->context)
1135 if (input_skip(input,
"QOE timestamp %" PRIu32, timestampMS))
1138 return IFCALLRESULT(TRUE, input->QoEEvent, input, timestampMS);
1141BOOL freerdp_input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
1143 if (!input || !input->context)
1146 char buffer[128] = WINPR_C_ARRAY_INIT;
1147 if (input_skip(input,
"Mouse {ExtendedEvent} %s",
1148 freerdp_input_mouse_flags_string(flags,
true, buffer, ARRAYSIZE(buffer))))
1151 input_update_last_event(input, TRUE, x, y);
1153 return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, flags, x, y);
1156BOOL freerdp_input_send_focus_in_event(rdpInput* input, UINT16 toggleStates)
1158 if (!input || !input->context)
1161 char buffer[128] = WINPR_C_ARRAY_INIT;
1162 if (input_skip(input,
"Keyboard {FocusIn} [%s]",
1163 freerdp_input_keyboard_flags_string(toggleStates, buffer,
sizeof(buffer))))
1166 return IFCALLRESULT(TRUE, input->FocusInEvent, input, toggleStates);
1169BOOL freerdp_input_send_keyboard_pause_event(rdpInput* input)
1171 if (!input || !input->context)
1174 if (input_skip(input,
"Keyboard {Pause}"))
1177 return IFCALLRESULT(TRUE, input->KeyboardPauseEvent, input);
1180int input_process_events(rdpInput* input)
1185 return input_message_queue_process_pending_messages(input);
1188static void input_free_queued_message(
void* obj)
1190 wMessage* msg = (wMessage*)obj;
1191 input_message_queue_free_message(msg);
1194rdpInput* input_new(rdpRdp* rdp)
1196 const wObject cb = {
nullptr,
nullptr,
nullptr, input_free_queued_message,
nullptr };
1204 input->common.context = rdp->context;
1205 input->queue = MessageQueue_New(&cb);
1206 input->log = WLog_Get(TAG);
1214 return &input->common;
1217void input_free(rdpInput* input)
1219 if (input !=
nullptr)
1223 MessageQueue_Free(in->queue);
1228static const char* flag2str(uint32_t flag,
bool extended)
1238 EVCASE(PTR_XFLAGS_DOWN);
1239 EVCASE(PTR_XFLAGS_BUTTON1);
1240 EVCASE(PTR_XFLAGS_BUTTON2);
1242 return "PTR_XFLAGS_UNKNOWN";
1249 EVCASE(PTR_FLAGS_HWHEEL);
1250 EVCASE(PTR_FLAGS_WHEEL);
1251 EVCASE(PTR_FLAGS_WHEEL_NEGATIVE);
1252 EVCASE(PTR_FLAGS_MOVE);
1253 EVCASE(PTR_FLAGS_DOWN);
1254 EVCASE(PTR_FLAGS_BUTTON1);
1255 EVCASE(PTR_FLAGS_BUTTON2);
1256 EVCASE(PTR_FLAGS_BUTTON3);
1258 return "PTR_FLAGS_UNKNOWN";
1263const char* freerdp_input_mouse_flags_string(uint32_t flags,
bool extended,
char* buffer,
1269 if (!winpr_str_append(
"{", buffer, len,
""))
1273 for (
size_t x = 0; x < 32; x++)
1275 const uint32_t flag = 1u << x;
1278 char ibuffer[64] = WINPR_C_ARRAY_INIT;
1279 (void)_snprintf(ibuffer,
sizeof(ibuffer),
"%s", flag2str(flag, extended));
1280 if (!winpr_str_append(ibuffer, &buffer[1], len - 2,
"|"))
1284 if (!winpr_str_append(
"}", &buffer[1], len - 2,
""))
1290static const char* kbdflag2str(uint32_t flag)
1299 EVCASE(KBD_FLAGS_EXTENDED);
1300 EVCASE(KBD_FLAGS_EXTENDED1);
1301 EVCASE(KBD_FLAGS_DOWN);
1302 EVCASE(KBD_FLAGS_RELEASE);
1304 return "KBD_FLAGS_UNKNOWN";
1309const char* freerdp_input_keypress_flags_string(uint32_t flags,
char* buffer,
size_t len)
1314 if (!winpr_str_append(
"{", buffer, len,
""))
1318 for (
size_t x = 0; x < 32; x++)
1320 const uint32_t flag = 1u << x;
1323 char ibuffer[64] = WINPR_C_ARRAY_INIT;
1324 (void)_snprintf(ibuffer,
sizeof(ibuffer),
"%s", kbdflag2str(flag));
1325 if (!winpr_str_append(ibuffer, &buffer[1], len - 2,
"|"))
1329 if (!winpr_str_append(
"}", &buffer[1], len - 2,
""))
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
This struct contains function pointer to initialize/free objects.