20 #include <freerdp/config.h>
28 #include <winpr/crt.h>
29 #include <winpr/path.h>
30 #include <winpr/assert.h>
31 #include <winpr/cast.h>
32 #include <winpr/collections.h>
34 #include <freerdp/utils/string.h>
37 #include <X11/Xutil.h>
38 #include <X11/keysym.h>
39 #include <X11/XKBlib.h>
41 #include <freerdp/locale/keyboard.h>
45 #include "xf_keyboard.h"
49 #include <freerdp/log.h>
50 #define TAG CLIENT_TAG("x11")
68 static UINT32 xf_keyboard_get_toggle_keys_state(xfContext* xfc);
69 static BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym);
70 static void xf_keyboard_handle_special_keys_release(xfContext* xfc, KeySym keysym);
72 static void xf_keyboard_modifier_map_free(xfContext* xfc)
77 XFreeModifiermap(xfc->modifierMap);
78 xfc->modifierMap = NULL;
82 BOOL xf_keyboard_update_modifier_map(xfContext* xfc)
85 xf_keyboard_modifier_map_free(xfc);
86 xfc->modifierMap = XGetModifierMapping(xfc->display);
87 return xfc->modifierMap != NULL;
90 static void xf_keyboard_send_key(xfContext* xfc, BOOL down, BOOL repeat,
const XKeyEvent* ev);
92 static BOOL xf_sync_kbd_state(xfContext* xfc)
94 const UINT32 syncFlags = xf_keyboard_get_toggle_keys_state(xfc);
97 return freerdp_input_send_synchronize_event(xfc->common.context.input, syncFlags);
100 static void xf_keyboard_clear(xfContext* xfc)
103 ZeroMemory(xfc->KeyboardState,
sizeof(xfc->KeyboardState));
106 static BOOL xf_action_script_append(xfContext* xfc,
const char* buffer,
size_t size,
void* user,
107 const char* what,
const char* arg)
113 if (!buffer || (size == 0))
115 return ArrayList_Append(xfc->keyCombinations, buffer);
118 static BOOL xf_keyboard_action_script_init(xfContext* xfc)
121 const rdpSettings* settings = NULL;
123 settings = xfc->common.context.settings;
124 WINPR_ASSERT(settings);
126 xfc->keyCombinations = ArrayList_New(TRUE);
128 if (!xfc->keyCombinations)
131 obj = ArrayList_Object(xfc->keyCombinations);
133 obj->fnObjectNew = winpr_ObjectStringClone;
134 obj->fnObjectFree = winpr_ObjectStringFree;
136 if (!run_action_script(xfc,
"key", NULL, xf_action_script_append, NULL))
139 return xf_event_action_script_init(xfc);
142 static void xf_keyboard_action_script_free(xfContext* xfc)
144 xf_event_action_script_free(xfc);
146 if (xfc->keyCombinations)
148 ArrayList_Free(xfc->keyCombinations);
149 xfc->keyCombinations = NULL;
150 xfc->actionScriptExists = FALSE;
154 BOOL xf_keyboard_init(xfContext* xfc)
156 rdpSettings* settings = NULL;
160 settings = xfc->common.context.settings;
161 WINPR_ASSERT(settings);
163 xf_keyboard_clear(xfc);
165 xfc->KeyboardLayout = freerdp_keyboard_init_ex(
170 if (!xf_keyboard_update_modifier_map(xfc))
173 xf_keyboard_action_script_init(xfc);
177 void xf_keyboard_free(xfContext* xfc)
179 xf_keyboard_modifier_map_free(xfc);
180 xf_keyboard_action_script_free(xfc);
183 void xf_keyboard_key_press(xfContext* xfc,
const XKeyEvent* event, KeySym keysym)
189 WINPR_ASSERT(event->keycode < ARRAYSIZE(xfc->KeyboardState));
191 last = xfc->KeyboardState[
event->keycode];
192 xfc->KeyboardState[
event->keycode] = TRUE;
194 if (xf_keyboard_handle_special_keys(xfc, keysym))
197 xf_keyboard_send_key(xfc, TRUE, last, event);
200 void xf_keyboard_key_release(xfContext* xfc,
const XKeyEvent* event, KeySym keysym)
204 WINPR_ASSERT(event->keycode < ARRAYSIZE(xfc->KeyboardState));
206 BOOL last = xfc->KeyboardState[
event->keycode];
207 xfc->KeyboardState[
event->keycode] = FALSE;
208 xf_keyboard_handle_special_keys_release(xfc, keysym);
209 xf_keyboard_send_key(xfc, FALSE, last, event);
212 void xf_keyboard_release_all_keypress(xfContext* xfc)
216 WINPR_STATIC_ASSERT(ARRAYSIZE(xfc->KeyboardState) <= UINT32_MAX);
217 for (
size_t keycode = 0; keycode < ARRAYSIZE(xfc->KeyboardState); keycode++)
219 if (xfc->KeyboardState[keycode])
221 const DWORD rdp_scancode =
222 freerdp_keyboard_get_rdp_scancode_from_x11_keycode((UINT32)keycode);
226 if (rdp_scancode == RDP_SCANCODE_LWIN)
227 freerdp_input_send_keyboard_event_ex(xfc->common.context.input, FALSE, FALSE,
230 freerdp_input_send_keyboard_event_ex(xfc->common.context.input, FALSE, FALSE,
232 xfc->KeyboardState[keycode] = FALSE;
235 xf_sync_kbd_state(xfc);
238 static BOOL xf_keyboard_key_pressed(xfContext* xfc, KeySym keysym)
240 KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
241 WINPR_ASSERT(keycode < ARRAYSIZE(xfc->KeyboardState));
242 return xfc->KeyboardState[keycode];
245 void xf_keyboard_send_key(xfContext* xfc, BOOL down, BOOL repeat,
const XKeyEvent* event)
250 rdpInput* input = xfc->common.context.input;
253 const DWORD rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(event->keycode);
254 if (rdp_scancode == RDP_SCANCODE_PAUSE && !xf_keyboard_key_pressed(xfc, XK_Control_L) &&
255 !xf_keyboard_key_pressed(xfc, XK_Control_R))
263 (void)freerdp_input_send_keyboard_pause_event(input);
270 wchar_t buffer[32] = { 0 };
273 switch (rdp_scancode)
275 case RDP_SCANCODE_RETURN:
279 XIM xim = XOpenIM(xfc->display, 0, 0, 0);
281 XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, NULL);
283 KeySym ignore = { 0 };
284 Status return_status = 0;
285 XKeyEvent ev = *event;
287 xwc = XwcLookupString(xic, &ev, buffer, ARRAYSIZE(buffer), &ignore,
295 if (rdp_scancode == RDP_SCANCODE_UNKNOWN)
296 WLog_ERR(TAG,
"Unknown key with X keycode 0x%02" PRIx8
"", event->keycode);
298 (
void)freerdp_input_send_keyboard_event_ex(input, down, repeat, rdp_scancode);
302 char str[3 * ARRAYSIZE(buffer)] = { 0 };
303 const size_t rc = wcstombs(str, buffer, ARRAYSIZE(buffer));
305 WCHAR wbuffer[ARRAYSIZE(buffer)] = { 0 };
306 (void)ConvertUtf8ToWChar(str, wbuffer, rc);
307 (void)freerdp_input_send_unicode_keyboard_event(input, down ? 0 : KBD_FLAGS_RELEASE,
311 else if (rdp_scancode == RDP_SCANCODE_UNKNOWN)
312 WLog_ERR(TAG,
"Unknown key with X keycode 0x%02" PRIx8
"", event->keycode);
314 (
void)freerdp_input_send_keyboard_event_ex(input, down, repeat, rdp_scancode);
316 if ((rdp_scancode == RDP_SCANCODE_CAPSLOCK) && (down == FALSE))
318 (void)xf_sync_kbd_state(xfc);
323 static int xf_keyboard_read_keyboard_state(xfContext* xfc)
329 if (!xfc->remote_app && xfc->window)
331 XQueryPointer(xfc->display, xfc->window->handle, &wdummy, &wdummy, &dummy, &dummy, &dummy,
336 XQueryPointer(xfc->display, DefaultRootWindow(xfc->display), &wdummy, &wdummy, &dummy,
337 &dummy, &dummy, &dummy, &state);
340 return WINPR_ASSERTING_INT_CAST(
int, state);
343 static int xf_keyboard_get_keymask(xfContext* xfc, KeySym keysym)
346 KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
348 if (keycode == NoSymbol)
351 WINPR_ASSERT(xfc->modifierMap);
352 for (
int modifierpos = 0; modifierpos < 8; modifierpos++)
354 int offset = xfc->modifierMap->max_keypermod * modifierpos;
356 for (
int key = 0; key < xfc->modifierMap->max_keypermod; key++)
358 if (xfc->modifierMap->modifiermap[offset + key] == keycode)
360 keysymMask |= 1 << modifierpos;
368 static BOOL xf_keyboard_get_key_state(xfContext* xfc,
int state, KeySym keysym)
370 int keysymMask = xf_keyboard_get_keymask(xfc, keysym);
375 return (state & keysymMask) ? TRUE : FALSE;
378 static BOOL xf_keyboard_set_key_state(xfContext* xfc, BOOL on, KeySym keysym)
380 if (!xfc->xkbAvailable)
383 const int keysymMask = xf_keyboard_get_keymask(xfc, keysym);
390 return XkbLockModifiers(xfc->display, XkbUseCoreKbd,
391 WINPR_ASSERTING_INT_CAST(uint32_t, keysymMask),
392 on ? WINPR_ASSERTING_INT_CAST(uint32_t, keysymMask) : 0);
395 UINT32 xf_keyboard_get_toggle_keys_state(xfContext* xfc)
397 UINT32 toggleKeysState = 0;
398 const int state = xf_keyboard_read_keyboard_state(xfc);
400 if (xf_keyboard_get_key_state(xfc, state, XK_Scroll_Lock))
401 toggleKeysState |= KBD_SYNC_SCROLL_LOCK;
403 if (xf_keyboard_get_key_state(xfc, state, XK_Num_Lock))
404 toggleKeysState |= KBD_SYNC_NUM_LOCK;
406 if (xf_keyboard_get_key_state(xfc, state, XK_Caps_Lock))
407 toggleKeysState |= KBD_SYNC_CAPS_LOCK;
409 if (xf_keyboard_get_key_state(xfc, state, XK_Kana_Lock))
410 toggleKeysState |= KBD_SYNC_KANA_LOCK;
412 return toggleKeysState;
415 static void xk_keyboard_update_modifier_keys(xfContext* xfc)
417 const KeySym keysyms[] = { XK_Shift_L, XK_Shift_R, XK_Alt_L, XK_Alt_R,
418 XK_Control_L, XK_Control_R, XK_Super_L, XK_Super_R };
420 xf_keyboard_clear(xfc);
422 const int state = xf_keyboard_read_keyboard_state(xfc);
424 for (
size_t i = 0; i < ARRAYSIZE(keysyms); i++)
426 if (xf_keyboard_get_key_state(xfc, state, keysyms[i]))
428 const KeyCode keycode = XKeysymToKeycode(xfc->display, keysyms[i]);
429 WINPR_ASSERT(keycode < ARRAYSIZE(xfc->KeyboardState));
430 xfc->KeyboardState[keycode] = TRUE;
435 void xf_keyboard_focus_in(xfContext* xfc)
444 if (!xfc->display || !xfc->window)
447 rdpInput* input = xfc->common.context.input;
450 const UINT32 syncFlags = xf_keyboard_get_toggle_keys_state(xfc);
451 freerdp_input_send_focus_in_event(input, WINPR_ASSERTING_INT_CAST(UINT16, syncFlags));
452 xk_keyboard_update_modifier_keys(xfc);
456 if (xfc->remote_app || !xfc->window)
459 if (XQueryPointer(xfc->display, xfc->window->handle, &w, &w, &d, &d, &x, &y, &state))
461 if ((x >= 0) && (x < xfc->window->width) && (y >= 0) && (y < xfc->window->height))
463 xf_event_adjust_coordinates(xfc, &x, &y);
464 freerdp_client_send_button_event(&xfc->common, FALSE, PTR_FLAGS_MOVE, x, y);
469 static BOOL action_script_run(xfContext* xfc,
const char* buffer,
size_t size,
void* user,
470 const char* what,
const char* arg)
480 WLog_WARN(TAG,
"ActionScript key: script did not return data");
484 if (strcmp(buffer,
"key-local") == 0)
486 else if (winpr_PathFileExists(buffer))
488 FILE* fp = popen(buffer,
"w");
491 WLog_ERR(TAG,
"Failed to execute '%s'", buffer);
495 *pstatus = pclose(fp);
498 WLog_ERR(TAG,
"Command '%s' returned %d", buffer, *pstatus);
504 WLog_WARN(TAG,
"ActionScript key: no such file '%s'", buffer);
510 static int xf_keyboard_execute_action_script(xfContext* xfc, XF_MODIFIER_KEYS* mod, KeySym keysym)
514 char command[2048] = { 0 };
515 char combination[1024] = { 0 };
517 if (!xfc->actionScriptExists)
520 if ((keysym == XK_Shift_L) || (keysym == XK_Shift_R) || (keysym == XK_Alt_L) ||
521 (keysym == XK_Alt_R) || (keysym == XK_Control_L) || (keysym == XK_Control_R))
526 const char* keyStr = XKeysymToString(keysym);
534 winpr_str_append(
"Shift", combination,
sizeof(combination),
"+");
537 winpr_str_append(
"Ctrl", combination,
sizeof(combination),
"+");
540 winpr_str_append(
"Alt", combination,
sizeof(combination),
"+");
543 winpr_str_append(
"Super", combination,
sizeof(combination),
"+");
545 winpr_str_append(keyStr, combination,
sizeof(combination),
"+");
547 for (
size_t i = 0; i < strnlen(combination,
sizeof(combination)); i++)
548 combination[i] = WINPR_ASSERTING_INT_CAST(
char, tolower(combination[i]));
550 const size_t count = ArrayList_Count(xfc->keyCombinations);
552 for (
size_t index = 0; index < count; index++)
554 const char* keyCombination = (
const char*)ArrayList_GetItem(xfc->keyCombinations, index);
556 if (_stricmp(keyCombination, combination) == 0)
566 (void)sprintf_s(command,
sizeof(command),
"key %s", combination);
567 if (!run_action_script(xfc, command, NULL, action_script_run, &status))
573 static int xk_keyboard_get_modifier_keys(xfContext* xfc, XF_MODIFIER_KEYS* mod)
575 mod->LeftShift = xf_keyboard_key_pressed(xfc, XK_Shift_L);
576 mod->RightShift = xf_keyboard_key_pressed(xfc, XK_Shift_R);
577 mod->Shift = mod->LeftShift || mod->RightShift;
578 mod->LeftAlt = xf_keyboard_key_pressed(xfc, XK_Alt_L);
579 mod->RightAlt = xf_keyboard_key_pressed(xfc, XK_Alt_R);
580 mod->Alt = mod->LeftAlt || mod->RightAlt;
581 mod->LeftCtrl = xf_keyboard_key_pressed(xfc, XK_Control_L);
582 mod->RightCtrl = xf_keyboard_key_pressed(xfc, XK_Control_R);
583 mod->Ctrl = mod->LeftCtrl || mod->RightCtrl;
584 mod->LeftSuper = xf_keyboard_key_pressed(xfc, XK_Super_L);
585 mod->RightSuper = xf_keyboard_key_pressed(xfc, XK_Super_R);
586 mod->Super = mod->LeftSuper || mod->RightSuper;
590 BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym)
592 XF_MODIFIER_KEYS mod = { 0 };
593 xk_keyboard_get_modifier_keys(xfc, &mod);
597 if (keysym == XK_Control_R)
599 if (mod.RightCtrl && !xfc->wasRightCtrlAlreadyPressed)
602 xfc->ungrabKeyboardWithRightCtrl = TRUE;
603 xfc->wasRightCtrlAlreadyPressed = TRUE;
609 if (xfc->ungrabKeyboardWithRightCtrl)
610 xfc->ungrabKeyboardWithRightCtrl = FALSE;
613 const int rc = xf_keyboard_execute_action_script(xfc, &mod, keysym);
619 if (!xfc->remote_app && xfc->fullscreen_toggle)
624 if (mod.Ctrl && mod.Alt)
627 xf_toggle_fullscreen(xfc);
636 if (mod.Ctrl && mod.Alt)
647 if (freerdp_client_encomsp_toggle_control(xfc->common.encomsp))
660 rdpContext* ctx = &xfc->common.context;
662 if (mod.Ctrl && mod.Alt)
675 xfc->scaledWidth = sessionWidth;
676 xfc->scaledHeight = sessionHeight;
680 if (!xfc->fullscreen && (sessionWidth != xfc->window->width ||
681 sessionHeight != xfc->window->height))
683 xf_ResizeDesktopWindow(xfc, xfc->window, sessionWidth, sessionHeight);
686 xf_draw_screen(xfc, 0, 0, sessionWidth, sessionHeight);
715 if (pdx != 0 || pdy != 0)
717 PanningChangeEventArgs e;
718 EventArgsInit(&e,
"xfreerdp");
721 PubSub_OnPanningChange(ctx->pubSub, xfc, &e);
725 if (zdx != 0 || zdy != 0)
727 ZoomingChangeEventArgs e;
728 EventArgsInit(&e,
"xfreerdp");
731 PubSub_OnZoomingChange(ctx->pubSub, xfc, &e);
742 void xf_keyboard_handle_special_keys_release(xfContext* xfc, KeySym keysym)
744 if (keysym != XK_Control_R)
747 xfc->wasRightCtrlAlreadyPressed = FALSE;
749 if (!xfc->ungrabKeyboardWithRightCtrl)
753 XF_MODIFIER_KEYS mod = { 0 };
754 xk_keyboard_get_modifier_keys(xfc, &mod);
758 if (!xfc->fullscreen)
760 freerdp_client_encomsp_toggle_control(xfc->common.encomsp);
763 xfc->mouse_active = FALSE;
768 xfc->ungrabKeyboardWithRightCtrl = FALSE;
771 BOOL xf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags)
773 xfContext* xfc = (xfContext*)context;
774 xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_SCROLL_LOCK, XK_Scroll_Lock);
775 xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_NUM_LOCK, XK_Num_Lock);
776 xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_CAPS_LOCK, XK_Caps_Lock);
777 xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_KANA_LOCK, XK_Kana_Lock);
781 BOOL xf_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
788 "KeyboardSetImeStatus(unitId=%04" PRIx16
", imeState=%08" PRIx32
789 ", imeConvMode=%08" PRIx32
") ignored",
790 imeId, imeState, imeConvMode);
794 BOOL xf_ungrab(xfContext* xfc)
797 XUngrabKeyboard(xfc->display, CurrentTime);
798 XUngrabPointer(xfc->display, CurrentTime);
799 xfc->common.mouse_grabbed = FALSE;
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
This struct contains function pointer to initialize/free objects.