20 #include <freerdp/config.h>
28 #include <winpr/crt.h>
29 #include <winpr/path.h>
30 #include <winpr/assert.h>
31 #include <winpr/collections.h>
33 #include <freerdp/utils/string.h>
36 #include <X11/Xutil.h>
37 #include <X11/keysym.h>
38 #include <X11/XKBlib.h>
40 #include <freerdp/locale/keyboard.h>
44 #include "xf_keyboard.h"
48 #include <freerdp/log.h>
49 #define TAG CLIENT_TAG("x11")
51 static void xf_keyboard_modifier_map_free(xfContext* xfc)
56 XFreeModifiermap(xfc->modifierMap);
57 xfc->modifierMap = NULL;
61 BOOL xf_keyboard_update_modifier_map(xfContext* xfc)
64 xf_keyboard_modifier_map_free(xfc);
65 xfc->modifierMap = XGetModifierMapping(xfc->display);
66 return xfc->modifierMap != NULL;
69 static void xf_keyboard_send_key(xfContext* xfc, BOOL down, BOOL repeat,
const XKeyEvent* ev);
71 static BOOL xf_sync_kbd_state(xfContext* xfc)
73 const UINT32 syncFlags = xf_keyboard_get_toggle_keys_state(xfc);
76 return freerdp_input_send_synchronize_event(xfc->common.context.input, syncFlags);
79 static void xf_keyboard_clear(xfContext* xfc)
82 ZeroMemory(xfc->KeyboardState,
sizeof(xfc->KeyboardState));
85 static BOOL xf_action_script_append(xfContext* xfc,
const char* buffer,
size_t size,
void* user,
86 const char* what,
const char* arg)
92 if (!buffer || (size == 0))
94 return ArrayList_Append(xfc->keyCombinations, buffer);
97 static BOOL xf_keyboard_action_script_init(xfContext* xfc)
100 const rdpSettings* settings = NULL;
102 settings = xfc->common.context.settings;
103 WINPR_ASSERT(settings);
105 xfc->keyCombinations = ArrayList_New(TRUE);
107 if (!xfc->keyCombinations)
110 obj = ArrayList_Object(xfc->keyCombinations);
112 obj->fnObjectNew = winpr_ObjectStringClone;
113 obj->fnObjectFree = winpr_ObjectStringFree;
115 if (!run_action_script(xfc,
"key", NULL, xf_action_script_append, NULL))
118 return xf_event_action_script_init(xfc);
121 static void xf_keyboard_action_script_free(xfContext* xfc)
123 xf_event_action_script_free(xfc);
125 if (xfc->keyCombinations)
127 ArrayList_Free(xfc->keyCombinations);
128 xfc->keyCombinations = NULL;
129 xfc->actionScriptExists = FALSE;
133 BOOL xf_keyboard_init(xfContext* xfc)
135 rdpSettings* settings = NULL;
139 settings = xfc->common.context.settings;
140 WINPR_ASSERT(settings);
142 xf_keyboard_clear(xfc);
144 xfc->KeyboardLayout = freerdp_keyboard_init_ex(
149 if (!xf_keyboard_update_modifier_map(xfc))
152 xf_keyboard_action_script_init(xfc);
156 void xf_keyboard_free(xfContext* xfc)
158 xf_keyboard_modifier_map_free(xfc);
159 xf_keyboard_action_script_free(xfc);
162 void xf_keyboard_key_press(xfContext* xfc,
const XKeyEvent* event, KeySym keysym)
168 WINPR_ASSERT(event->keycode < ARRAYSIZE(xfc->KeyboardState));
170 last = xfc->KeyboardState[
event->keycode];
171 xfc->KeyboardState[
event->keycode] = TRUE;
173 if (xf_keyboard_handle_special_keys(xfc, keysym))
176 xf_keyboard_send_key(xfc, TRUE, last, event);
179 void xf_keyboard_key_release(xfContext* xfc,
const XKeyEvent* event, KeySym keysym)
183 WINPR_ASSERT(event->keycode < ARRAYSIZE(xfc->KeyboardState));
185 BOOL last = xfc->KeyboardState[
event->keycode];
186 xfc->KeyboardState[
event->keycode] = FALSE;
187 xf_keyboard_handle_special_keys_release(xfc, keysym);
188 xf_keyboard_send_key(xfc, FALSE, last, event);
191 void xf_keyboard_release_all_keypress(xfContext* xfc)
195 WINPR_STATIC_ASSERT(ARRAYSIZE(xfc->KeyboardState) <= UINT32_MAX);
196 for (
size_t keycode = 0; keycode < ARRAYSIZE(xfc->KeyboardState); keycode++)
198 if (xfc->KeyboardState[keycode])
200 const DWORD rdp_scancode =
201 freerdp_keyboard_get_rdp_scancode_from_x11_keycode((UINT32)keycode);
205 if (rdp_scancode == RDP_SCANCODE_LWIN)
206 freerdp_input_send_keyboard_event_ex(xfc->common.context.input, FALSE, FALSE,
209 freerdp_input_send_keyboard_event_ex(xfc->common.context.input, FALSE, FALSE,
211 xfc->KeyboardState[keycode] = FALSE;
214 xf_sync_kbd_state(xfc);
217 BOOL xf_keyboard_key_pressed(xfContext* xfc, KeySym keysym)
219 KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
220 WINPR_ASSERT(keycode < ARRAYSIZE(xfc->KeyboardState));
221 return xfc->KeyboardState[keycode];
224 void xf_keyboard_send_key(xfContext* xfc, BOOL down, BOOL repeat,
const XKeyEvent* event)
226 DWORD rdp_scancode = 0;
227 rdpInput* input = NULL;
232 input = xfc->common.context.input;
235 rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(event->keycode);
236 if (rdp_scancode == RDP_SCANCODE_PAUSE && !xf_keyboard_key_pressed(xfc, XK_Control_L) &&
237 !xf_keyboard_key_pressed(xfc, XK_Control_R))
245 freerdp_input_send_keyboard_pause_event(input);
252 wchar_t buffer[32] = { 0 };
255 switch (rdp_scancode)
257 case RDP_SCANCODE_RETURN:
261 XIM xim = XOpenIM(xfc->display, 0, 0, 0);
263 XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, NULL);
265 KeySym ignore = { 0 };
266 Status return_status = 0;
267 XKeyEvent ev = *event;
269 xwc = XwcLookupString(xic, &ev, buffer, ARRAYSIZE(buffer), &ignore,
277 if (rdp_scancode == RDP_SCANCODE_UNKNOWN)
278 WLog_ERR(TAG,
"Unknown key with X keycode 0x%02" PRIx8
"", event->keycode);
280 freerdp_input_send_keyboard_event_ex(input, down, repeat, rdp_scancode);
283 freerdp_input_send_unicode_keyboard_event(input, down ? 0 : KBD_FLAGS_RELEASE,
286 else if (rdp_scancode == RDP_SCANCODE_UNKNOWN)
287 WLog_ERR(TAG,
"Unknown key with X keycode 0x%02" PRIx8
"", event->keycode);
289 freerdp_input_send_keyboard_event_ex(input, down, repeat, rdp_scancode);
291 if ((rdp_scancode == RDP_SCANCODE_CAPSLOCK) && (down == FALSE))
293 xf_sync_kbd_state(xfc);
298 int xf_keyboard_read_keyboard_state(xfContext* xfc)
304 if (!xfc->remote_app && xfc->window)
306 XQueryPointer(xfc->display, xfc->window->handle, &wdummy, &wdummy, &dummy, &dummy, &dummy,
311 XQueryPointer(xfc->display, DefaultRootWindow(xfc->display), &wdummy, &wdummy, &dummy,
312 &dummy, &dummy, &dummy, &state);
318 static int xf_keyboard_get_keymask(xfContext* xfc,
int keysym)
321 KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
323 if (keycode == NoSymbol)
326 WINPR_ASSERT(xfc->modifierMap);
327 for (
int modifierpos = 0; modifierpos < 8; modifierpos++)
329 int offset = xfc->modifierMap->max_keypermod * modifierpos;
331 for (
int key = 0; key < xfc->modifierMap->max_keypermod; key++)
333 if (xfc->modifierMap->modifiermap[offset + key] == keycode)
335 keysymMask |= 1 << modifierpos;
343 BOOL xf_keyboard_get_key_state(xfContext* xfc,
int state,
int keysym)
345 int keysymMask = xf_keyboard_get_keymask(xfc, keysym);
350 return (state & keysymMask) ? TRUE : FALSE;
353 static BOOL xf_keyboard_set_key_state(xfContext* xfc, BOOL on,
int keysym)
355 if (!xfc->xkbAvailable)
358 const int keysymMask = xf_keyboard_get_keymask(xfc, keysym);
365 return XkbLockModifiers(xfc->display, XkbUseCoreKbd, keysymMask, on ? keysymMask : 0);
368 UINT32 xf_keyboard_get_toggle_keys_state(xfContext* xfc)
370 UINT32 toggleKeysState = 0;
371 const int state = xf_keyboard_read_keyboard_state(xfc);
373 if (xf_keyboard_get_key_state(xfc, state, XK_Scroll_Lock))
374 toggleKeysState |= KBD_SYNC_SCROLL_LOCK;
376 if (xf_keyboard_get_key_state(xfc, state, XK_Num_Lock))
377 toggleKeysState |= KBD_SYNC_NUM_LOCK;
379 if (xf_keyboard_get_key_state(xfc, state, XK_Caps_Lock))
380 toggleKeysState |= KBD_SYNC_CAPS_LOCK;
382 if (xf_keyboard_get_key_state(xfc, state, XK_Kana_Lock))
383 toggleKeysState |= KBD_SYNC_KANA_LOCK;
385 return toggleKeysState;
388 static void xk_keyboard_update_modifier_keys(xfContext* xfc)
390 const int keysyms[] = { XK_Shift_L, XK_Shift_R, XK_Alt_L, XK_Alt_R,
391 XK_Control_L, XK_Control_R, XK_Super_L, XK_Super_R };
393 xf_keyboard_clear(xfc);
395 const int state = xf_keyboard_read_keyboard_state(xfc);
397 for (
size_t i = 0; i < ARRAYSIZE(keysyms); i++)
399 if (xf_keyboard_get_key_state(xfc, state, keysyms[i]))
401 const KeyCode keycode = XKeysymToKeycode(xfc->display, keysyms[i]);
402 WINPR_ASSERT(keycode < ARRAYSIZE(xfc->KeyboardState));
403 xfc->KeyboardState[keycode] = TRUE;
408 void xf_keyboard_focus_in(xfContext* xfc)
417 if (!xfc->display || !xfc->window)
420 rdpInput* input = xfc->common.context.input;
423 const UINT32 syncFlags = xf_keyboard_get_toggle_keys_state(xfc);
424 freerdp_input_send_focus_in_event(input, syncFlags);
425 xk_keyboard_update_modifier_keys(xfc);
429 if (xfc->remote_app || !xfc->window)
432 if (XQueryPointer(xfc->display, xfc->window->handle, &w, &w, &d, &d, &x, &y, &state))
434 if ((x >= 0) && (x < xfc->window->width) && (y >= 0) && (y < xfc->window->height))
436 xf_event_adjust_coordinates(xfc, &x, &y);
437 freerdp_client_send_button_event(&xfc->common, FALSE, PTR_FLAGS_MOVE, x, y);
442 static BOOL action_script_run(xfContext* xfc,
const char* buffer,
size_t size,
void* user,
443 const char* what,
const char* arg)
453 WLog_WARN(TAG,
"ActionScript key: script did not return data");
457 if (strcmp(buffer,
"key-local") == 0)
459 else if (winpr_PathFileExists(buffer))
461 FILE* fp = popen(buffer,
"w");
464 WLog_ERR(TAG,
"Failed to execute '%s'", buffer);
468 *pstatus = pclose(fp);
471 WLog_ERR(TAG,
"Command '%s' returned %d", buffer, *pstatus);
477 WLog_WARN(TAG,
"ActionScript key: no such file '%s'", buffer);
483 static int xf_keyboard_execute_action_script(xfContext* xfc,
XF_MODIFIER_KEYS* mod, KeySym keysym)
487 char command[2048] = { 0 };
488 char combination[1024] = { 0 };
490 if (!xfc->actionScriptExists)
493 if ((keysym == XK_Shift_L) || (keysym == XK_Shift_R) || (keysym == XK_Alt_L) ||
494 (keysym == XK_Alt_R) || (keysym == XK_Control_L) || (keysym == XK_Control_R))
499 const char* keyStr = XKeysymToString(keysym);
507 winpr_str_append(
"Shift", combination,
sizeof(combination),
"+");
510 winpr_str_append(
"Ctrl", combination,
sizeof(combination),
"+");
513 winpr_str_append(
"Alt", combination,
sizeof(combination),
"+");
516 winpr_str_append(
"Super", combination,
sizeof(combination),
"+");
518 winpr_str_append(keyStr, combination,
sizeof(combination),
"+");
520 for (
size_t i = 0; i < strnlen(combination,
sizeof(combination)); i++)
521 combination[i] = tolower(combination[i]);
523 const size_t count = ArrayList_Count(xfc->keyCombinations);
525 for (
size_t index = 0; index < count; index++)
527 const char* keyCombination = (
const char*)ArrayList_GetItem(xfc->keyCombinations, index);
529 if (_stricmp(keyCombination, combination) == 0)
539 (void)sprintf_s(command,
sizeof(command),
"key %s", combination);
540 if (!run_action_script(xfc, command, NULL, action_script_run, &status))
546 static int xk_keyboard_get_modifier_keys(xfContext* xfc,
XF_MODIFIER_KEYS* mod)
548 mod->LeftShift = xf_keyboard_key_pressed(xfc, XK_Shift_L);
549 mod->RightShift = xf_keyboard_key_pressed(xfc, XK_Shift_R);
550 mod->Shift = mod->LeftShift || mod->RightShift;
551 mod->LeftAlt = xf_keyboard_key_pressed(xfc, XK_Alt_L);
552 mod->RightAlt = xf_keyboard_key_pressed(xfc, XK_Alt_R);
553 mod->Alt = mod->LeftAlt || mod->RightAlt;
554 mod->LeftCtrl = xf_keyboard_key_pressed(xfc, XK_Control_L);
555 mod->RightCtrl = xf_keyboard_key_pressed(xfc, XK_Control_R);
556 mod->Ctrl = mod->LeftCtrl || mod->RightCtrl;
557 mod->LeftSuper = xf_keyboard_key_pressed(xfc, XK_Super_L);
558 mod->RightSuper = xf_keyboard_key_pressed(xfc, XK_Super_R);
559 mod->Super = mod->LeftSuper || mod->RightSuper;
563 BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym)
566 xk_keyboard_get_modifier_keys(xfc, &mod);
570 if (keysym == XK_Control_R)
572 if (mod.RightCtrl && !xfc->wasRightCtrlAlreadyPressed)
575 xfc->ungrabKeyboardWithRightCtrl = TRUE;
576 xfc->wasRightCtrlAlreadyPressed = TRUE;
582 if (xfc->ungrabKeyboardWithRightCtrl)
583 xfc->ungrabKeyboardWithRightCtrl = FALSE;
586 const int rc = xf_keyboard_execute_action_script(xfc, &mod, keysym);
592 if (!xfc->remote_app && xfc->fullscreen_toggle)
597 if (mod.Ctrl && mod.Alt)
600 xf_toggle_fullscreen(xfc);
609 if (mod.Ctrl && mod.Alt)
620 if (freerdp_client_encomsp_toggle_control(xfc->common.encomsp))
633 rdpContext* ctx = &xfc->common.context;
635 if (mod.Ctrl && mod.Alt)
648 xfc->scaledWidth = sessionWidth;
649 xfc->scaledHeight = sessionHeight;
653 if (!xfc->fullscreen && (sessionWidth != xfc->window->width ||
654 sessionHeight != xfc->window->height))
656 xf_ResizeDesktopWindow(xfc, xfc->window, sessionWidth, sessionHeight);
659 xf_draw_screen(xfc, 0, 0, sessionWidth, sessionHeight);
688 if (pdx != 0 || pdy != 0)
690 PanningChangeEventArgs e;
691 EventArgsInit(&e,
"xfreerdp");
694 PubSub_OnPanningChange(ctx->pubSub, xfc, &e);
698 if (zdx != 0 || zdy != 0)
700 ZoomingChangeEventArgs e;
701 EventArgsInit(&e,
"xfreerdp");
704 PubSub_OnZoomingChange(ctx->pubSub, xfc, &e);
715 void xf_keyboard_handle_special_keys_release(xfContext* xfc, KeySym keysym)
717 if (keysym != XK_Control_R)
720 xfc->wasRightCtrlAlreadyPressed = FALSE;
722 if (!xfc->ungrabKeyboardWithRightCtrl)
727 xk_keyboard_get_modifier_keys(xfc, &mod);
731 if (!xfc->fullscreen)
733 freerdp_client_encomsp_toggle_control(xfc->common.encomsp);
736 xfc->mouse_active = FALSE;
741 xfc->ungrabKeyboardWithRightCtrl = FALSE;
744 BOOL xf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags)
746 xfContext* xfc = (xfContext*)context;
747 xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_SCROLL_LOCK, XK_Scroll_Lock);
748 xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_NUM_LOCK, XK_Num_Lock);
749 xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_CAPS_LOCK, XK_Caps_Lock);
750 xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_KANA_LOCK, XK_Kana_Lock);
754 BOOL xf_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
761 "KeyboardSetImeStatus(unitId=%04" PRIx16
", imeState=%08" PRIx32
762 ", imeConvMode=%08" PRIx32
") ignored",
763 imeId, imeState, imeConvMode);
767 BOOL xf_ungrab(xfContext* xfc)
770 XUngrabKeyboard(xfc->display, CurrentTime);
771 XUngrabPointer(xfc->display, CurrentTime);
772 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.