[locale,keyboard] fix keyboard mapping on apple

This commit is contained in:
Armin Novak 2023-08-02 12:07:03 +02:00 committed by akallabeth
parent fe2595eaeb
commit 3ea38175b4
7 changed files with 155 additions and 127 deletions

View File

@ -179,9 +179,7 @@ void xf_keyboard_key_press(xfContext* xfc, const XKeyEvent* event, KeySym keysym
WINPR_ASSERT(xfc);
WINPR_ASSERT(event);
if (event->keycode < 8)
return;
WINPR_ASSERT(event->keycode <= ARRAYSIZE(xfc->KeyboardState));
last = xfc->KeyboardState[event->keycode];
xfc->KeyboardState[event->keycode] = TRUE;
@ -196,9 +194,7 @@ void xf_keyboard_key_release(xfContext* xfc, const XKeyEvent* event, KeySym keys
{
WINPR_ASSERT(xfc);
WINPR_ASSERT(event);
if (event->keycode < 8)
return;
WINPR_ASSERT(event->keycode <= ARRAYSIZE(xfc->KeyboardState));
BOOL last = xfc->KeyboardState[event->keycode];
xfc->KeyboardState[event->keycode] = FALSE;
@ -208,16 +204,13 @@ void xf_keyboard_key_release(xfContext* xfc, const XKeyEvent* event, KeySym keys
void xf_keyboard_release_all_keypress(xfContext* xfc)
{
size_t keycode;
DWORD rdp_scancode;
WINPR_ASSERT(xfc);
for (keycode = 0; keycode < ARRAYSIZE(xfc->KeyboardState); keycode++)
for (size_t keycode = 0; keycode < ARRAYSIZE(xfc->KeyboardState); keycode++)
{
if (xfc->KeyboardState[keycode])
{
rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(keycode);
const DWORD rdp_scancode = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(keycode);
// release tab before releasing the windows key.
// this stops the start menu from opening on unfocus event.
@ -236,6 +229,7 @@ void xf_keyboard_release_all_keypress(xfContext* xfc)
BOOL xf_keyboard_key_pressed(xfContext* xfc, KeySym keysym)
{
KeyCode keycode = XKeysymToKeycode(xfc->display, keysym);
WINPR_ASSERT(keycode <= ARRAYSIZE(xfc->KeyboardState));
return xfc->KeyboardState[keycode];
}
@ -417,6 +411,7 @@ static void xk_keyboard_update_modifier_keys(xfContext* xfc)
if (xf_keyboard_get_key_state(xfc, state, keysyms[i]))
{
const KeyCode keycode = XKeysymToKeycode(xfc->display, keysyms[i]);
WINPR_ASSERT(keycode <= ARRAYSIZE(xfc->KeyboardState));
xfc->KeyboardState[keycode] = TRUE;
}
}

View File

@ -39,7 +39,6 @@
#define TAG FREERDP_TAG("locale.keyboard")
#ifdef WITH_X11
#include "keyboard_x11.h"
#ifdef WITH_XKBFILE
@ -48,6 +47,7 @@
#endif
static WINPR_KEYCODE_TYPE maptype = WINPR_KEYCODE_TYPE_NONE;
static DWORD VIRTUAL_SCANCODE_TO_X11_KEYCODE[256][2] = { 0 };
static DWORD X11_KEYCODE_TO_VIRTUAL_SCANCODE[256] = { 0 };
static DWORD REMAPPING_TABLE[0x10000] = { 0 };
@ -255,42 +255,35 @@ static int freerdp_detect_keyboard(DWORD* keyboardLayoutId)
return 0;
}
static int freerdp_keyboard_init_apple(DWORD* keyboardLayoutId,
DWORD x11_keycode_to_rdp_scancode[256])
static int freerdp_keyboard_init_apple(DWORD* keyboardLayoutId, DWORD* x11_keycode_to_rdp_scancode,
size_t count)
{
DWORD vkcode;
DWORD keycode;
DWORD keycode_to_vkcode[256] = { 0 };
WINPR_ASSERT(x11_keycode_to_rdp_scancode);
WINPR_ASSERT(keyboardLayoutId);
for (keycode = 0; keycode < 256; keycode++)
for (size_t keycode = 8; keycode < count; keycode++)
{
vkcode = keycode_to_vkcode[keycode] =
GetVirtualKeyCodeFromKeycode(keycode, WINPR_KEYCODE_TYPE_APPLE);
const DWORD vkcode = GetVirtualKeyCodeFromKeycode(keycode - 8u, WINPR_KEYCODE_TYPE_APPLE);
x11_keycode_to_rdp_scancode[keycode] =
GetVirtualScanCodeFromVirtualKeyCode(vkcode, WINPR_KBD_TYPE_IBM_ENHANCED);
}
maptype = WINPR_KEYCODE_TYPE_APPLE;
return 0;
}
static int freerdp_keyboard_init_x11_evdev(DWORD* keyboardLayoutId,
DWORD x11_keycode_to_rdp_scancode[256])
DWORD* x11_keycode_to_rdp_scancode, size_t count)
{
DWORD vkcode;
DWORD keycode;
DWORD keycode_to_vkcode[256] = { 0 };
WINPR_ASSERT(keyboardLayoutId);
WINPR_ASSERT(x11_keycode_to_rdp_scancode);
for (keycode = 0; keycode < 256; keycode++)
for (size_t keycode = 0; keycode < count; keycode++)
{
vkcode = keycode_to_vkcode[keycode] =
GetVirtualKeyCodeFromKeycode(keycode, WINPR_KEYCODE_TYPE_XKB);
const DWORD vkcode = GetVirtualKeyCodeFromKeycode(keycode, WINPR_KEYCODE_TYPE_EVDEV);
x11_keycode_to_rdp_scancode[keycode] =
GetVirtualScanCodeFromVirtualKeyCode(vkcode, WINPR_KBD_TYPE_IBM_ENHANCED);
}
maptype = WINPR_KEYCODE_TYPE_EVDEV;
return 0;
}
@ -300,21 +293,27 @@ DWORD freerdp_keyboard_init(DWORD keyboardLayoutId)
DWORD keycode;
int status = -1;
#ifdef __APPLE__
#if defined(__APPLE__)
if (status < 0)
status = freerdp_keyboard_init_apple(&keyboardLayoutId, X11_KEYCODE_TO_VIRTUAL_SCANCODE);
status = freerdp_keyboard_init_apple(&keyboardLayoutId, X11_KEYCODE_TO_VIRTUAL_SCANCODE,
ARRAYSIZE(X11_KEYCODE_TO_VIRTUAL_SCANCODE));
#endif
#if defined(WITH_X11) || defined(WITH_WAYLAND)
#ifdef WITH_XKBFILE
if (status < 0)
status = freerdp_keyboard_init_xkbfile(&keyboardLayoutId, X11_KEYCODE_TO_VIRTUAL_SCANCODE);
{
status = freerdp_keyboard_init_xkbfile(&keyboardLayoutId, X11_KEYCODE_TO_VIRTUAL_SCANCODE,
ARRAYSIZE(X11_KEYCODE_TO_VIRTUAL_SCANCODE));
if (status >= 0)
maptype = WINPR_KEYCODE_TYPE_XKB;
}
#endif
if (status < 0)
status =
freerdp_keyboard_init_x11_evdev(&keyboardLayoutId, X11_KEYCODE_TO_VIRTUAL_SCANCODE);
status = freerdp_keyboard_init_x11_evdev(&keyboardLayoutId, X11_KEYCODE_TO_VIRTUAL_SCANCODE,
ARRAYSIZE(X11_KEYCODE_TO_VIRTUAL_SCANCODE));
#endif
@ -327,9 +326,10 @@ DWORD freerdp_keyboard_init(DWORD keyboardLayoutId)
for (keycode = 0; keycode < ARRAYSIZE(VIRTUAL_SCANCODE_TO_X11_KEYCODE); keycode++)
{
VIRTUAL_SCANCODE_TO_X11_KEYCODE
[RDP_SCANCODE_CODE(X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode])]
[RDP_SCANCODE_EXTENDED(X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode]) ? 1 : 0] = keycode;
const DWORD x11 = X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode];
const DWORD sc = RDP_SCANCODE_CODE(x11);
const BOOL ex = RDP_SCANCODE_EXTENDED(x11);
VIRTUAL_SCANCODE_TO_X11_KEYCODE[sc][ex ? 1 : 0] = keycode;
}
return keyboardLayoutId;
@ -375,17 +375,24 @@ DWORD freerdp_keyboard_get_rdp_scancode_from_x11_keycode(DWORD keycode)
{
const DWORD scancode = X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode];
const DWORD remapped = REMAPPING_TABLE[scancode];
#if defined(WITH_DEBUG_KBD)
const BOOL ex = RDP_SCANCODE_EXTENDED(scancode);
const DWORD sc = RDP_SCANCODE_CODE(scancode);
#endif
DEBUG_KBD("x11 keycode: %02" PRIX32 " -> rdp code: [%04" PRIx16 "] %02" PRIX8 "%s", keycode,
scancode, RDP_SCANCODE_CODE(scancode),
RDP_SCANCODE_EXTENDED(scancode) ? " extended" : "");
scancode, sc, ex ? " extended" : "");
if (remapped != 0)
{
#if defined(WITH_DEBUG_KBD)
const DWORD rsc = RDP_SCANCODE_CODE(remapped);
const BOOL rex = RDP_SCANCODE_EXTENDED(remapped);
#endif
DEBUG_KBD("remapped scancode: [%04" PRIx16 "] %02" PRIX8 "[%s] -> [%04" PRIx16 "] %02" PRIX8
"[%s]",
scancode, RDP_SCANCODE_CODE(scancode),
RDP_SCANCODE_EXTENDED(scancode) ? " extended" : "", remapped,
RDP_SCANCODE_CODE(remapped), RDP_SCANCODE_EXTENDED(remapped) ? " extended" : "");
scancode, sc, ex ? " extended" : "", remapped, rsc, rex ? " extended" : "");
return remapped;
}
return scancode;
@ -393,10 +400,13 @@ DWORD freerdp_keyboard_get_rdp_scancode_from_x11_keycode(DWORD keycode)
DWORD freerdp_keyboard_get_x11_keycode_from_rdp_scancode(DWORD scancode, BOOL extended)
{
const DWORD* x11 = VIRTUAL_SCANCODE_TO_X11_KEYCODE[scancode];
WINPR_ASSERT(x11);
if (extended)
return VIRTUAL_SCANCODE_TO_X11_KEYCODE[scancode][1];
return x11[1];
else
return VIRTUAL_SCANCODE_TO_X11_KEYCODE[scancode][0];
return x11[0];
}
const char* freerdp_keyboard_scancode_name(DWORD scancode)

View File

@ -19,6 +19,8 @@
*/
#include <string.h>
#include <X11/X.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
@ -109,20 +111,24 @@ static DWORD kbd_layout_id_from_x_property(Display* display, Window root, char*
int freerdp_detect_keyboard_layout_from_xkb(DWORD* keyboardLayoutId)
{
Window root;
Display* display = XOpenDisplay(NULL);
if (!display)
return 0;
root = DefaultRootWindow(display);
Window root = DefaultRootWindow(display);
if (!root)
return 0;
/* We start by looking for _XKB_RULES_NAMES_BACKUP which appears to be used by libxklavier */
*keyboardLayoutId = kbd_layout_id_from_x_property(display, root, "_XKB_RULES_NAMES_BACKUP");
DWORD id = kbd_layout_id_from_x_property(display, root, "_XKB_RULES_NAMES_BACKUP");
if (0 == *keyboardLayoutId)
*keyboardLayoutId = kbd_layout_id_from_x_property(display, root, "_XKB_RULES_NAMES");
if (0 == id)
id = kbd_layout_id_from_x_property(display, root, "_XKB_RULES_NAMES");
if (0 != id)
*keyboardLayoutId = id;
XCloseDisplay(display);
return (int)*keyboardLayoutId;
return (int)id;
}

View File

@ -34,6 +34,7 @@
#include "xkb_layout_ids.h"
#include "liblocale.h"
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#include <X11/extensions/XKBfile.h>
@ -308,8 +309,8 @@ static const XKB_KEY_NAME_SCANCODE XKB_KEY_NAME_SCANCODE_TABLE[] = {
};
static int detect_keyboard_layout_from_xkbfile(void* display, DWORD* keyboardLayoutId);
static int freerdp_keyboard_load_map_from_xkbfile(void* display,
DWORD x11_keycode_to_rdp_scancode[256]);
static int freerdp_keyboard_load_map_from_xkbfile(void* display, DWORD* x11_keycode_to_rdp_scancode,
size_t count);
static void* freerdp_keyboard_xkb_init(void)
{
@ -328,15 +329,14 @@ static void* freerdp_keyboard_xkb_init(void)
return (void*)display;
}
int freerdp_keyboard_init_xkbfile(DWORD* keyboardLayoutId, DWORD x11_keycode_to_rdp_scancode[256])
int freerdp_keyboard_init_xkbfile(DWORD* keyboardLayoutId, DWORD* x11_keycode_to_rdp_scancode,
size_t count)
{
void* display;
WINPR_ASSERT(keyboardLayoutId);
WINPR_ASSERT(x11_keycode_to_rdp_scancode);
ZeroMemory(x11_keycode_to_rdp_scancode, sizeof(DWORD) * 256);
ZeroMemory(x11_keycode_to_rdp_scancode, sizeof(DWORD) * count);
display = freerdp_keyboard_xkb_init();
void* display = freerdp_keyboard_xkb_init();
if (!display)
{
@ -351,11 +351,12 @@ int freerdp_keyboard_init_xkbfile(DWORD* keyboardLayoutId, DWORD x11_keycode_to_
*keyboardLayoutId, *keyboardLayoutId);
}
freerdp_keyboard_load_map_from_xkbfile(display, x11_keycode_to_rdp_scancode);
const int rc =
freerdp_keyboard_load_map_from_xkbfile(display, x11_keycode_to_rdp_scancode, count);
XCloseDisplay(display);
return 0;
return rc;
}
/* return substring starting after nth comma, ending at following comma */
@ -382,19 +383,27 @@ static char* comma_substring(char* s, size_t n)
int detect_keyboard_layout_from_xkbfile(void* display, DWORD* keyboardLayoutId)
{
DWORD group = 0;
XkbStateRec state = { 0 };
XKeyboardState coreKbdState;
XkbRF_VarDefsRec rules_names = { 0 };
DEBUG_KBD("display: %p", display);
if (!display)
return -2;
char* rules = NULL;
if (display && XkbRF_GetNamesProp(display, &rules, &rules_names))
XkbRF_VarDefsRec rules_names = { 0 };
const Bool rc = XkbRF_GetNamesProp(display, &rules, &rules_names);
if (!rc)
{
DEBUG_KBD("XkbRF_GetNamesProp == False");
}
else
{
DEBUG_KBD("rules: %s", rules ? rules : "");
DEBUG_KBD("model: %s", rules_names.model ? rules_names.model : "");
DEBUG_KBD("layouts: %s", rules_names.layout ? rules_names.layout : "");
DEBUG_KBD("variants: %s", rules_names.variant ? rules_names.variant : "");
DWORD group = 0;
XkbStateRec state = { 0 };
XKeyboardState coreKbdState = { 0 };
XGetKeyboardControl(display, &coreKbdState);
if (XkbGetState(display, XkbUseCoreKbd, &state) == Success)
@ -409,67 +418,78 @@ int detect_keyboard_layout_from_xkbfile(void* display, DWORD* keyboardLayoutId)
DEBUG_KBD("variant: %s", variant ? variant : "");
*keyboardLayoutId = find_keyboard_layout_in_xorg_rules(layout, variant);
free(rules_names.model);
free(rules_names.layout);
free(rules_names.variant);
free(rules_names.options);
}
free(rules_names.model);
free(rules_names.layout);
free(rules_names.variant);
free(rules_names.options);
free(rules);
return 0;
}
int freerdp_keyboard_load_map_from_xkbfile(void* display, DWORD x11_keycode_to_rdp_scancode[256])
int freerdp_keyboard_load_map_from_xkbfile(void* display, DWORD* x11_keycode_to_rdp_scancode,
size_t count)
{
size_t i, j;
BOOL found;
XkbDescPtr xkb;
BOOL status = FALSE;
int status = -1;
if (display && (xkb = XkbGetMap(display, 0, XkbUseCoreKbd)))
if (!display)
return -2;
XkbDescPtr xkb = XkbGetMap(display, 0, XkbUseCoreKbd);
if (!xkb)
{
if (XkbGetNames(display, XkbKeyNamesMask, xkb) == Success)
DEBUG_KBD("XkbGetMap() == NULL");
return -3;
}
if (XkbGetNames(display, XkbKeyNamesMask, xkb) != Success)
{
DEBUG_KBD("XkbGetNames() != Success");
}
else
{
char xkb_keyname[XkbKeyNameLength + 1] = { 42, 42, 42, 42,
0 }; /* end-of-string at index 5 */
DEBUG_KBD("XkbGetNames() == Success, min=%" PRIu8 ", max=%" PRIu8, xkb->min_key_code,
xkb->max_key_code);
for (size_t i = xkb->min_key_code; i <= MIN(xkb->max_key_code, count); i++)
{
char xkb_keyname[5] = { 42, 42, 42, 42, 0 }; /* end-of-string at index 5 */
BOOL found = FALSE;
strncpy(xkb_keyname, xkb->names->keys[i].name, XkbKeyNameLength);
for (i = xkb->min_key_code; i <= xkb->max_key_code; i++)
DEBUG_KBD("KeyCode %" PRIuz " -> %s", i, xkb_keyname);
if (strnlen(xkb_keyname, ARRAYSIZE(xkb_keyname)) < 1)
continue;
for (size_t j = 0; j < ARRAYSIZE(XKB_KEY_NAME_SCANCODE_TABLE); j++)
{
found = FALSE;
CopyMemory(xkb_keyname, xkb->names->keys[i].name, 4);
if (strnlen(xkb_keyname, sizeof(xkb_keyname)) < 1)
continue;
for (j = 0; j < ARRAYSIZE(XKB_KEY_NAME_SCANCODE_TABLE); j++)
if (!strcmp(xkb_keyname, XKB_KEY_NAME_SCANCODE_TABLE[j].xkb_keyname))
{
if (!strcmp(xkb_keyname, XKB_KEY_NAME_SCANCODE_TABLE[j].xkb_keyname))
DEBUG_KBD("%4s: keycode: 0x%02X -> rdp scancode: 0x%08" PRIX32 "", xkb_keyname,
i, XKB_KEY_NAME_SCANCODE_TABLE[j].rdp_scancode);
if (found)
{
DEBUG_KBD("%4s: keycode: 0x%02X -> rdp scancode: 0x%08" PRIX32 "",
xkb_keyname, i, XKB_KEY_NAME_SCANCODE_TABLE[j].rdp_scancode);
if (found)
{
DEBUG_KBD("Internal error! duplicate key %s!", xkb_keyname);
}
x11_keycode_to_rdp_scancode[i] =
XKB_KEY_NAME_SCANCODE_TABLE[j].rdp_scancode;
found = TRUE;
DEBUG_KBD("Internal error! duplicate key %s!", xkb_keyname);
}
}
if (!found)
{
DEBUG_KBD("%4s: keycode: 0x%02X -> no RDP scancode found", xkb_keyname, i);
x11_keycode_to_rdp_scancode[i] = XKB_KEY_NAME_SCANCODE_TABLE[j].rdp_scancode;
found = TRUE;
}
}
status = TRUE;
if (!found)
{
DEBUG_KBD("%4s: keycode: 0x%02X -> no RDP scancode found", xkb_keyname, i);
}
else
status = 0;
}
XkbFreeKeyboard(xkb, 0, 1);
}
XkbFreeKeyboard(xkb, 0, 1);
return status;
}

View File

@ -25,6 +25,6 @@
#include <freerdp/api.h>
FREERDP_LOCAL int freerdp_keyboard_init_xkbfile(DWORD* keyboardLayoutId,
DWORD x11_keycode_to_rdp_scancode[256]);
DWORD* x11_keycode_to_rdp_scancode, size_t count);
#endif /* FREERDP_LIB_LOCALE_KEYBOARD_XKB_H */

View File

@ -796,10 +796,8 @@ const char* freerdp_get_system_locale_name_from_id(DWORD localeId)
int freerdp_detect_keyboard_layout_from_system_locale(DWORD* keyboardLayoutId)
{
size_t i, j;
char language[LOCALE_LANGUAGE_LEN] = { 0 };
char country[LOCALE_COUNTRY_LEN] = { 0 };
const SYSTEM_LOCALE* locale;
freerdp_get_system_language_and_country_codes(language, ARRAYSIZE(language), country,
ARRAYSIZE(country));
@ -810,21 +808,22 @@ int freerdp_detect_keyboard_layout_from_system_locale(DWORD* keyboardLayoutId)
return 0;
}
locale = freerdp_detect_system_locale();
const SYSTEM_LOCALE* locale = freerdp_detect_system_locale();
if (!locale)
return -1;
DEBUG_KBD("Found locale : %s_%s", locale->language, locale->country);
for (i = 0; i < ARRAYSIZE(LOCALE_KEYBOARD_LAYOUTS_TABLE); i++)
for (size_t i = 0; i < ARRAYSIZE(LOCALE_KEYBOARD_LAYOUTS_TABLE); i++)
{
const LOCALE_KEYBOARD_LAYOUTS* const current = &LOCALE_KEYBOARD_LAYOUTS_TABLE[i];
WINPR_ASSERT(current);
if (current->locale == locale->code)
{
/* Locale found in list of default keyboard layouts */
for (j = 0; j < 5; j++)
for (size_t j = 0; j < 5; j++)
{
if (current->keyboardLayouts[j] == ENGLISH_UNITED_STATES)
{
@ -832,7 +831,19 @@ int freerdp_detect_keyboard_layout_from_system_locale(DWORD* keyboardLayoutId)
}
else if (current->keyboardLayouts[j] == 0)
{
break; /* No more keyboard layouts */
/*
* If we skip the ENGLISH_UNITED_STATES keyboard layout but there are no
* other possible keyboard layout for the locale, we end up here with k > 1
*/
if (j >= 1)
{
*keyboardLayoutId = ENGLISH_UNITED_STATES;
return 0;
}
/* No more keyboard layouts */
break;
}
else
{
@ -840,21 +851,6 @@ int freerdp_detect_keyboard_layout_from_system_locale(DWORD* keyboardLayoutId)
return 0;
}
}
/*
* If we skip the ENGLISH_UNITED_STATES keyboard layout but there are no
* other possible keyboard layout for the locale, we end up here with k > 1
*/
if (j >= 1)
{
*keyboardLayoutId = ENGLISH_UNITED_STATES;
return 0;
}
else
{
return -1;
}
}
}

View File

@ -893,6 +893,7 @@ extern "C"
typedef enum
{
WINPR_KEYCODE_TYPE_NONE = 0x00000000,
WINPR_KEYCODE_TYPE_APPLE = 0x00000001,
WINPR_KEYCODE_TYPE_EVDEV = 0x00000002,
WINPR_KEYCODE_TYPE_XKB = 0x00000003