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)
386 UINT16 sec_flags = 0;
388 rdpRdp* rdp =
nullptr;
391 WINPR_ASSERT(input->context);
393 rdp = input->context->rdp;
396 if (!input_ensure_client_running(input))
400 s = fastpath_input_pdu_init(rdp->fastpath, (BYTE)flags, FASTPATH_INPUT_EVENT_SYNC, &sec_flags);
405 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
408static BOOL input_send_fastpath_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
410 UINT16 sec_flags = 0;
413 rdpRdp* rdp =
nullptr;
416 WINPR_ASSERT(input->context);
418 rdp = input->context->rdp;
421 if (!input_ensure_client_running(input))
424 eventFlags |= (flags & KBD_FLAGS_RELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0;
425 eventFlags |= (flags & KBD_FLAGS_EXTENDED) ? FASTPATH_INPUT_KBDFLAGS_EXTENDED : 0;
426 eventFlags |= (flags & KBD_FLAGS_EXTENDED1) ? FASTPATH_INPUT_KBDFLAGS_PREFIX_E1 : 0;
427 s = fastpath_input_pdu_init(rdp->fastpath, eventFlags, FASTPATH_INPUT_EVENT_SCANCODE,
433 WINPR_ASSERT(code <= UINT8_MAX);
434 Stream_Write_UINT8(s, code);
435 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
438static BOOL input_send_fastpath_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
440 UINT16 sec_flags = 0;
443 rdpRdp* rdp =
nullptr;
446 WINPR_ASSERT(input->context);
447 WINPR_ASSERT(input->context->settings);
449 rdp = input->context->rdp;
452 if (!input_ensure_client_running(input))
457 WLog_WARN(TAG,
"Unicode input not supported by server.");
461 eventFlags |= (flags & KBD_FLAGS_RELEASE) ? FASTPATH_INPUT_KBDFLAGS_RELEASE : 0;
462 s = fastpath_input_pdu_init(rdp->fastpath, eventFlags, FASTPATH_INPUT_EVENT_UNICODE,
468 Stream_Write_UINT16(s, code);
469 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
472static BOOL input_send_fastpath_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
474 UINT16 sec_flags = 0;
476 rdpRdp* rdp =
nullptr;
479 WINPR_ASSERT(input->context);
480 WINPR_ASSERT(input->context->settings);
482 rdp = input->context->rdp;
485 if (!input_ensure_client_running(input))
490 if (flags & PTR_FLAGS_HWHEEL)
493 "skip mouse event %" PRIu16
"x%" PRIu16
" flags=0x%04" PRIX16
494 ", no horizontal mouse wheel supported",
500 s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSE, &sec_flags);
505 input_write_mouse_event(s, flags, x, y);
506 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
509static BOOL input_send_fastpath_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x,
512 UINT16 sec_flags = 0;
514 rdpRdp* rdp =
nullptr;
517 WINPR_ASSERT(input->context);
519 rdp = input->context->rdp;
522 if (!input_ensure_client_running(input))
528 "skip extended mouse event %" PRIu16
"x%" PRIu16
" flags=0x%04" PRIX16
529 ", no extended mouse events supported",
534 s = fastpath_input_pdu_init(rdp->fastpath, 0, FASTPATH_INPUT_EVENT_MOUSEX, &sec_flags);
539 input_write_extended_mouse_event(s, flags, x, y);
540 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
543static BOOL input_send_fastpath_relmouse_event(rdpInput* input, UINT16 flags, INT16 xDelta,
546 UINT16 sec_flags = 0;
548 rdpRdp* rdp =
nullptr;
551 WINPR_ASSERT(input->context);
552 WINPR_ASSERT(input->context->settings);
554 rdp = input->context->rdp;
557 if (!input_ensure_client_running(input))
562 WLog_ERR(TAG,
"Sending relative fastpath mouse event, but no support for that announced");
566 s = fastpath_input_pdu_init(rdp->fastpath, 0, TS_FP_RELPOINTER_EVENT, &sec_flags);
571 Stream_Write_UINT16(s, flags);
572 Stream_Write_INT16(s, xDelta);
573 Stream_Write_INT16(s, yDelta);
574 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
577static BOOL input_send_fastpath_qoe_event(rdpInput* input, UINT32 timestampMS)
580 WINPR_ASSERT(input->context);
581 WINPR_ASSERT(input->context->settings);
583 rdpRdp* rdp = input->context->rdp;
586 if (!input_ensure_client_running(input))
591 WLog_ERR(TAG,
"Sending qoe event, but no support for that announced");
595 UINT16 sec_flags = 0;
596 wStream* s = fastpath_input_pdu_init(rdp->fastpath, 0, TS_FP_QOETIMESTAMP_EVENT, &sec_flags);
601 if (!Stream_EnsureRemainingCapacity(s, 4))
603 Stream_Free(s, TRUE);
607 Stream_Write_UINT32(s, timestampMS);
608 return fastpath_send_input_pdu(rdp->fastpath, s, sec_flags);
611static BOOL input_send_fastpath_focus_in_event(rdpInput* input, UINT16 toggleStates)
613 UINT16 sec_flags = 0;
616 rdpRdp* rdp =
nullptr;
619 WINPR_ASSERT(input->context);
621 rdp = input->context->rdp;
624 if (!input_ensure_client_running(input))
627 s = fastpath_input_pdu_init_header(rdp->fastpath, &sec_flags);
633 eventFlags = FASTPATH_INPUT_KBDFLAGS_RELEASE | FASTPATH_INPUT_EVENT_SCANCODE << 5;
634 Stream_Write_UINT8(s, eventFlags);
635 Stream_Write_UINT8(s, 0x0f);
637 eventFlags = (toggleStates & 0x1F) | FASTPATH_INPUT_EVENT_SYNC << 5;
638 Stream_Write_UINT8(s, eventFlags);
640 eventFlags = FASTPATH_INPUT_KBDFLAGS_RELEASE | FASTPATH_INPUT_EVENT_SCANCODE << 5;
641 Stream_Write_UINT8(s, eventFlags);
642 Stream_Write_UINT8(s, 0x0f);
643 return fastpath_send_multiple_input_pdu(rdp->fastpath, s, 3, sec_flags);
646static BOOL input_send_fastpath_keyboard_pause_event(rdpInput* input)
652 UINT16 sec_flags = 0;
654 const BYTE keyDownEvent = FASTPATH_INPUT_EVENT_SCANCODE << 5;
655 const BYTE keyUpEvent = (FASTPATH_INPUT_EVENT_SCANCODE << 5) | FASTPATH_INPUT_KBDFLAGS_RELEASE;
656 rdpRdp* rdp =
nullptr;
659 WINPR_ASSERT(input->context);
661 rdp = input->context->rdp;
664 if (!input_ensure_client_running(input))
667 s = fastpath_input_pdu_init_header(rdp->fastpath, &sec_flags);
673 Stream_Write_UINT8(s, keyDownEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1);
674 Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL));
676 Stream_Write_UINT8(s, keyDownEvent);
677 Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK));
679 Stream_Write_UINT8(s, keyUpEvent | FASTPATH_INPUT_KBDFLAGS_PREFIX_E1);
680 Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_LCONTROL));
682 Stream_Write_UINT8(s, keyUpEvent);
683 Stream_Write_UINT8(s, RDP_SCANCODE_CODE(RDP_SCANCODE_NUMLOCK));
684 return fastpath_send_multiple_input_pdu(rdp->fastpath, s, 4, sec_flags);
687static BOOL input_recv_sync_event(rdpInput* input,
wStream* s)
689 UINT32 toggleFlags = 0;
694 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
698 Stream_Read_UINT32(s, toggleFlags);
701 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
703 return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, toggleFlags);
706static BOOL input_recv_keyboard_event(rdpInput* input,
wStream* s)
708 UINT16 keyboardFlags = 0;
714 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
717 Stream_Read_UINT16(s, keyboardFlags);
718 Stream_Read_UINT16(s, keyCode);
721 if (keyboardFlags & KBD_FLAGS_RELEASE)
722 keyboardFlags &= ~KBD_FLAGS_DOWN;
724 if (keyCode & 0xFF00)
726 "Problematic [MS-RDPBCGR] 2.2.8.1.1.3.1.1.1 Keyboard Event (TS_KEYBOARD_EVENT) "
727 "keyCode=0x%04" PRIx16
728 ", high byte values should be sent in keyboardFlags field, ignoring.",
732 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
734 return IFCALLRESULT(TRUE, input->KeyboardEvent, input, keyboardFlags, keyCode & 0xFF);
737static BOOL input_recv_unicode_keyboard_event(rdpInput* input,
wStream* s)
739 UINT16 keyboardFlags = 0;
740 UINT16 unicodeCode = 0;
745 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
748 Stream_Read_UINT16(s, keyboardFlags);
749 Stream_Read_UINT16(s, unicodeCode);
754 if (keyboardFlags & KBD_FLAGS_RELEASE)
755 keyboardFlags &= ~KBD_FLAGS_DOWN;
758 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
760 return IFCALLRESULT(TRUE, input->UnicodeKeyboardEvent, input, keyboardFlags, unicodeCode);
763static BOOL input_recv_mouse_event(rdpInput* input,
wStream* s)
765 UINT16 pointerFlags = 0;
772 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
775 Stream_Read_UINT16(s, pointerFlags);
776 Stream_Read_UINT16(s, xPos);
777 Stream_Read_UINT16(s, yPos);
780 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
782 return IFCALLRESULT(TRUE, input->MouseEvent, input, pointerFlags, xPos, yPos);
785static BOOL input_recv_relmouse_event(rdpInput* input,
wStream* s)
787 UINT16 pointerFlags = 0;
794 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
797 Stream_Read_UINT16(s, pointerFlags);
798 Stream_Read_INT16(s, xDelta);
799 Stream_Read_INT16(s, yDelta);
804 "Received relative mouse event(flags=0x%04" PRIx16
", xPos=%" PRId16
805 ", yPos=%" PRId16
"), but we did not announce support for that",
806 pointerFlags, xDelta, yDelta);
811 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
814 return IFCALLRESULT(TRUE, input->RelMouseEvent, input, pointerFlags, xDelta, yDelta);
817static BOOL input_recv_extended_mouse_event(rdpInput* input,
wStream* s)
819 UINT16 pointerFlags = 0;
826 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
829 Stream_Read_UINT16(s, pointerFlags);
830 Stream_Read_UINT16(s, xPos);
831 Stream_Read_UINT16(s, yPos);
836 "Received extended mouse event(flags=0x%04" PRIx16
", xPos=%" PRIu16
837 ", yPos=%" PRIu16
"), but we did not announce support for that",
838 pointerFlags, xPos, yPos);
843 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
845 return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, pointerFlags, xPos, yPos);
848static BOOL input_recv_event(rdpInput* input,
wStream* s)
850 UINT16 messageType = 0;
855 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
859 Stream_Read_UINT16(s, messageType);
863 case INPUT_EVENT_SYNC:
864 if (!input_recv_sync_event(input, s))
869 case INPUT_EVENT_SCANCODE:
870 if (!input_recv_keyboard_event(input, s))
875 case INPUT_EVENT_UNICODE:
876 if (!input_recv_unicode_keyboard_event(input, s))
881 case INPUT_EVENT_MOUSE:
882 if (!input_recv_mouse_event(input, s))
887 case INPUT_EVENT_MOUSEX:
888 if (!input_recv_extended_mouse_event(input, s))
893 case INPUT_EVENT_MOUSEREL:
894 if (!input_recv_relmouse_event(input, s))
900 WLog_ERR(TAG,
"Unknown messageType %" PRIu16
"", messageType);
909BOOL input_recv(rdpInput* input,
wStream* s)
911 UINT16 numberEvents = 0;
916 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
919 Stream_Read_UINT16(s, numberEvents);
923 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, numberEvents, 6ull))
926 for (UINT16 i = 0; i < numberEvents; i++)
928 if (!input_recv_event(input, s))
935BOOL input_register_client_callbacks(rdpInput* input)
937 rdpSettings* settings =
nullptr;
942 settings = input->context->settings;
949 input->SynchronizeEvent = input_send_fastpath_synchronize_event;
950 input->KeyboardEvent = input_send_fastpath_keyboard_event;
951 input->KeyboardPauseEvent = input_send_fastpath_keyboard_pause_event;
952 input->UnicodeKeyboardEvent = input_send_fastpath_unicode_keyboard_event;
953 input->MouseEvent = input_send_fastpath_mouse_event;
954 input->RelMouseEvent = input_send_fastpath_relmouse_event;
955 input->ExtendedMouseEvent = input_send_fastpath_extended_mouse_event;
956 input->FocusInEvent = input_send_fastpath_focus_in_event;
957 input->QoEEvent = input_send_fastpath_qoe_event;
961 input->SynchronizeEvent = input_send_synchronize_event;
962 input->KeyboardEvent = input_send_keyboard_event;
963 input->KeyboardPauseEvent = input_send_keyboard_pause_event;
964 input->UnicodeKeyboardEvent = input_send_unicode_keyboard_event;
965 input->MouseEvent = input_send_mouse_event;
966 input->RelMouseEvent = input_send_relmouse_event;
967 input->ExtendedMouseEvent = input_send_extended_mouse_event;
968 input->FocusInEvent = input_send_focus_in_event;
975static BOOL input_update_last_event(rdpInput* input, BOOL mouse, UINT16 x, UINT16 y)
980 WINPR_ASSERT(input->context);
984 const time_t now = time(
nullptr);
985 in->lastInputTimestamp = WINPR_ASSERTING_INT_CAST(UINT64, now);
997static const char* boolstr(
bool value)
1005WINPR_ATTR_FORMAT_ARG(2, 3)
1006static BOOL input_skip(const rdpInput* input, WINPR_FORMAT_ARG const
char* fmt, ...)
1008 WINPR_ASSERT(input);
1010 const rdpContext* context = input->context;
1011 WINPR_ASSERT(context);
1017 const BOOL connected = freerdp_is_active_state(context);
1018 const DWORD loglevel = WLOG_DEBUG;
1020 if (WLog_IsLevelActive(in->log, loglevel))
1022 char buffer[128] = WINPR_C_ARRAY_INIT;
1024 va_list args = WINPR_C_ARRAY_INIT;
1025 va_start(args, fmt);
1026 (void)vsnprintf(buffer,
sizeof(buffer), fmt, args);
1029 WLog_Print(in->log, loglevel,
"[connected=%s, suspended=%s] %s", boolstr(connected),
1030 boolstr(suspended), buffer);
1033 return suspended || !connected;
1036BOOL freerdp_input_send_synchronize_event(rdpInput* input, UINT32 flags)
1038 if (!input || !input->context)
1041 char buffer[128] = WINPR_C_ARRAY_INIT;
1042 if (input_skip(input,
"Keyboard {Sync} [%s]",
1043 freerdp_input_keyboard_flags_string(flags, buffer,
sizeof(buffer))))
1046 return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, flags);
1049BOOL freerdp_input_send_keyboard_event(rdpInput* input, UINT16 flags, UINT8 code)
1051 if (!input || !input->context)
1054 char buffer[128] = WINPR_C_ARRAY_INIT;
1055 if (input_skip(input,
"Keyboard {Event} [%s]",
1056 freerdp_input_keypress_flags_string(flags, buffer,
sizeof(buffer))))
1059 input_update_last_event(input, FALSE, 0, 0);
1061 return IFCALLRESULT(TRUE, input->KeyboardEvent, input, flags, code);
1064BOOL freerdp_input_send_keyboard_event_ex(rdpInput* input, BOOL down, BOOL repeat,
1065 UINT32 rdp_scancode)
1067 UINT16 flags = (RDP_SCANCODE_EXTENDED(rdp_scancode) ? KBD_FLAGS_EXTENDED : 0);
1069 flags |= KBD_FLAGS_DOWN;
1071 flags |= KBD_FLAGS_RELEASE;
1073 return freerdp_input_send_keyboard_event(input, flags, RDP_SCANCODE_CODE(rdp_scancode));
1076BOOL freerdp_input_send_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
1078 if (!input || !input->context)
1081 char buffer[128] = WINPR_C_ARRAY_INIT;
1082 if (input_skip(input,
"Keyboard {Unicode} [%s]",
1083 freerdp_input_keypress_flags_string(flags, buffer, ARRAYSIZE(buffer))))
1086 input_update_last_event(input, FALSE, 0, 0);
1088 return IFCALLRESULT(TRUE, input->UnicodeKeyboardEvent, input, flags, code);
1091BOOL freerdp_input_send_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
1093 if (!input || !input->context)
1096 char buffer[128] = WINPR_C_ARRAY_INIT;
1097 if (input_skip(input,
"Mouse {Event} [%s]",
1098 freerdp_input_mouse_flags_string(flags,
false, buffer, ARRAYSIZE(buffer))))
1101 input_update_last_event(
1102 input, flags & (PTR_FLAGS_MOVE | PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 | PTR_FLAGS_BUTTON3),
1105 return IFCALLRESULT(TRUE, input->MouseEvent, input, flags, x, y);
1108BOOL freerdp_input_send_rel_mouse_event(rdpInput* input, UINT16 flags, INT16 xDelta, INT16 yDelta)
1110 if (!input || !input->context)
1113 char buffer[128] = WINPR_C_ARRAY_INIT;
1114 if (input_skip(input,
"Mouse {RelativeEvent} [%s]",
1115 freerdp_input_mouse_flags_string(flags,
true, buffer, ARRAYSIZE(buffer))))
1118 return IFCALLRESULT(TRUE, input->RelMouseEvent, input, flags, xDelta, yDelta);
1121BOOL freerdp_input_send_qoe_timestamp(rdpInput* input, UINT32 timestampMS)
1123 if (!input || !input->context)
1126 return IFCALLRESULT(TRUE, input->QoEEvent, input, timestampMS);
1129BOOL freerdp_input_send_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
1131 if (!input || !input->context)
1134 char buffer[128] = WINPR_C_ARRAY_INIT;
1135 if (input_skip(input,
"Mouse {ExtendedEvent} %s",
1136 freerdp_input_mouse_flags_string(flags,
true, buffer, ARRAYSIZE(buffer))))
1139 input_update_last_event(input, TRUE, x, y);
1141 return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, flags, x, y);
1144BOOL freerdp_input_send_focus_in_event(rdpInput* input, UINT16 toggleStates)
1146 if (!input || !input->context)
1149 char buffer[128] = WINPR_C_ARRAY_INIT;
1150 if (input_skip(input,
"Keyboard {FocusIn} [%s]",
1151 freerdp_input_keyboard_flags_string(toggleStates, buffer,
sizeof(buffer))))
1154 return IFCALLRESULT(TRUE, input->FocusInEvent, input, toggleStates);
1157BOOL freerdp_input_send_keyboard_pause_event(rdpInput* input)
1159 if (!input || !input->context)
1162 if (input_skip(input,
"Keyboard {Pause}"))
1165 return IFCALLRESULT(TRUE, input->KeyboardPauseEvent, input);
1168int input_process_events(rdpInput* input)
1173 return input_message_queue_process_pending_messages(input);
1176static void input_free_queued_message(
void* obj)
1178 wMessage* msg = (wMessage*)obj;
1179 input_message_queue_free_message(msg);
1182rdpInput* input_new(rdpRdp* rdp)
1184 const wObject cb = {
nullptr,
nullptr,
nullptr, input_free_queued_message,
nullptr };
1192 input->common.context = rdp->context;
1193 input->queue = MessageQueue_New(&cb);
1194 input->log = WLog_Get(TAG);
1202 return &input->common;
1205void input_free(rdpInput* input)
1207 if (input !=
nullptr)
1211 MessageQueue_Free(in->queue);
1216static const char* flag2str(uint32_t flag,
bool extended)
1226 EVCASE(PTR_XFLAGS_DOWN);
1227 EVCASE(PTR_XFLAGS_BUTTON1);
1228 EVCASE(PTR_XFLAGS_BUTTON2);
1230 return "PTR_XFLAGS_UNKNOWN";
1237 EVCASE(PTR_FLAGS_HWHEEL);
1238 EVCASE(PTR_FLAGS_WHEEL);
1239 EVCASE(PTR_FLAGS_WHEEL_NEGATIVE);
1240 EVCASE(PTR_FLAGS_MOVE);
1241 EVCASE(PTR_FLAGS_DOWN);
1242 EVCASE(PTR_FLAGS_BUTTON1);
1243 EVCASE(PTR_FLAGS_BUTTON2);
1244 EVCASE(PTR_FLAGS_BUTTON3);
1246 return "PTR_FLAGS_UNKNOWN";
1251const char* freerdp_input_mouse_flags_string(uint32_t flags,
bool extended,
char* buffer,
1257 if (!winpr_str_append(
"{", buffer, len,
""))
1261 for (
size_t x = 0; x < 32; x++)
1263 const uint32_t flag = 1u << x;
1266 char ibuffer[64] = WINPR_C_ARRAY_INIT;
1267 (void)_snprintf(ibuffer,
sizeof(ibuffer),
"%s", flag2str(flag, extended));
1268 if (!winpr_str_append(ibuffer, &buffer[1], len - 2,
"|"))
1272 if (!winpr_str_append(
"}", &buffer[1], len - 2,
""))
1278static const char* kbdflag2str(uint32_t flag)
1287 EVCASE(KBD_FLAGS_EXTENDED);
1288 EVCASE(KBD_FLAGS_EXTENDED1);
1289 EVCASE(KBD_FLAGS_DOWN);
1290 EVCASE(KBD_FLAGS_RELEASE);
1292 return "KBD_FLAGS_UNKNOWN";
1297const char* freerdp_input_keypress_flags_string(uint32_t flags,
char* buffer,
size_t len)
1302 if (!winpr_str_append(
"{", buffer, len,
""))
1306 for (
size_t x = 0; x < 32; x++)
1308 const uint32_t flag = 1u << x;
1311 char ibuffer[64] = WINPR_C_ARRAY_INIT;
1312 (void)_snprintf(ibuffer,
sizeof(ibuffer),
"%s", kbdflag2str(flag));
1313 if (!winpr_str_append(ibuffer, &buffer[1], len - 2,
"|"))
1317 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.