[PATCH 1/1] winex11: Use XKB key names to map key codes to scan codes.
Timo Zuccarello
wine at gitlab.winehq.org
Fri Jun 3 05:41:12 CDT 2022
From: Timo Zuccarello <timo at zuccarello.eu>
Use XKB, if available, to map key codes to scan codes using key names
instead of using hard coded keyboard layouts.
Signed-off-by: Timo Zuccarello <timo at zuccarello.eu>
---
dlls/winex11.drv/keyboard.c | 311 +++++++++++++++++++++++++++++++++++-
1 file changed, 307 insertions(+), 4 deletions(-)
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c
index 7b4ad9acd8d..f70c5c16f2a 100644
--- a/dlls/winex11.drv/keyboard.c
+++ b/dlls/winex11.drv/keyboard.c
@@ -1128,6 +1128,283 @@ static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e)
return keyc2vkey[e->keycode];
}
+/**********************************************************************
+ * scancode_from_key_name
+ *
+ * Maps XKB names to scancodes.
+ */
+static WORD
+scancode_from_key_name( char* keyn )
+{
+ /* Comments assume US QWERTY layout. */
+ /* These are obtained from the Keyboard Scan Code Specification. */
+#ifdef HAVE_XKB
+ if (strcmp(keyn, "TLDE") == 0) { /* Tilde */
+ return 0x29;
+ } else if (strcmp(keyn, "AE01") == 0) { /* 1 */
+ return 0x02;
+ } else if (strcmp(keyn, "AE02") == 0) {
+ return 0x03;
+ } else if (strcmp(keyn, "AE03") == 0) {
+ return 0x04;
+ } else if (strcmp(keyn, "AE04") == 0) {
+ return 0x05;
+ } else if (strcmp(keyn, "AE05") == 0) {
+ return 0x06;
+ } else if (strcmp(keyn, "AE06") == 0) {
+ return 0x07;
+ } else if (strcmp(keyn, "AE07") == 0) {
+ return 0x08;
+ } else if (strcmp(keyn, "AE08") == 0) {
+ return 0x09;
+ } else if (strcmp(keyn, "AE09") == 0) { /* 9 */
+ return 0x0a;
+ } else if (strcmp(keyn, "AE10") == 0) { /* 0 */
+ return 0x0b;
+ } else if (strcmp(keyn, "AE11") == 0) { /* Minus */
+ return 0x0c;
+ } else if (strcmp(keyn, "AE12") == 0) { /* Equals */
+ return 0x0d;
+ } else if (strcmp(keyn, "BKSP") == 0) { /* Backspace */
+ return 0x0e;
+ } else if (strcmp(keyn, "TAB") == 0) { /* Tab */
+ return 0x0f;
+ } else if (strcmp(keyn, "AD01") == 0) { /* Q */
+ return 0x10;
+ } else if (strcmp(keyn, "AD02") == 0) {
+ return 0x11;
+ } else if (strcmp(keyn, "AD03") == 0) {
+ return 0x12;
+ } else if (strcmp(keyn, "AD04") == 0) {
+ return 0x13;
+ } else if (strcmp(keyn, "AD05") == 0) {
+ return 0x14;
+ } else if (strcmp(keyn, "AD06") == 0) {
+ return 0x15;
+ } else if (strcmp(keyn, "AD07") == 0) {
+ return 0x16;
+ } else if (strcmp(keyn, "AD08") == 0) {
+ return 0x17;
+ } else if (strcmp(keyn, "AD09") == 0) {
+ return 0x18;
+ } else if (strcmp(keyn, "AD10") == 0) {
+ return 0x19;
+ } else if (strcmp(keyn, "AD11") == 0) { /* Left Bracket */
+ return 0x1a;
+ } else if (strcmp(keyn, "AD12") == 0) { /* Right Bracket */
+ return 0x1b;
+ } else if (strcmp(keyn, "BKSL") == 0) { /* Backslash (See key 29 in Scancode Specification.) */
+ return 0x2b;
+ } else if (strcmp(keyn, "CAPS") == 0) { /* Caps Lock */
+ return 0x3a;
+ } else if (strcmp(keyn, "AC01") == 0) { /* A */
+ return 0x1e;
+ } else if (strcmp(keyn, "AC02") == 0) {
+ return 0x1f;
+ } else if (strcmp(keyn, "AC03") == 0) {
+ return 0x20;
+ } else if (strcmp(keyn, "AC04") == 0) {
+ return 0x21;
+ } else if (strcmp(keyn, "AC05") == 0) {
+ return 0x22;
+ } else if (strcmp(keyn, "AC06") == 0) {
+ return 0x23;
+ } else if (strcmp(keyn, "AC07") == 0) {
+ return 0x24;
+ } else if (strcmp(keyn, "AC08") == 0) {
+ return 0x25;
+ } else if (strcmp(keyn, "AC09") == 0) { /* L */
+ return 0x26;
+ } else if (strcmp(keyn, "AC10") == 0) { /* Semicolon */
+ return 0x27;
+ } else if (strcmp(keyn, "AC11") == 0) { /* Apostrophe */
+ return 0x28;
+ } else if (strcmp(keyn, "AC12") == 0) { /* Key on international keyboards left of enter.
+ (See key 42 in Scancode specification.) */
+ return 0x2B;
+ } else if (strcmp(keyn, "RTRN") == 0) { /* Enter */
+ return 0x1c;
+ } else if (strcmp(keyn, "LFSH") == 0) { /* Left Shift */
+ return 0x2a;
+ } else if (strcmp(keyn, "LSGT") == 0) { /* <> key (See key 45 in Scancode specification.) */
+ return 0x56;
+ } else if (strcmp(keyn, "AB01") == 0) { /* Z */
+ return 0x2c;
+ } else if (strcmp(keyn, "AB02") == 0) { /* X */
+ return 0x2d;
+ } else if (strcmp(keyn, "AB03") == 0) {
+ return 0x2e;
+ } else if (strcmp(keyn, "AB04") == 0) {
+ return 0x2f;
+ } else if (strcmp(keyn, "AB05") == 0) {
+ return 0x30;
+ } else if (strcmp(keyn, "AB06") == 0) {
+ return 0x31;
+ } else if (strcmp(keyn, "AB07") == 0) {
+ return 0x32;
+ } else if (strcmp(keyn, "AB08") == 0) { /* Comma */
+ return 0x33;
+ } else if (strcmp(keyn, "AB09") == 0) { /* Period */
+ return 0x34;
+ } else if (strcmp(keyn, "AB10") == 0) { /* Slash */
+ return 0x35;
+ } else if (strcmp(keyn, "AB11") == 0) { /* Brazilian key (See key 56 in Scancode specification.) */
+ return 0x73;
+ } else if (strcmp(keyn, "RTSH") == 0) { /* Right Shift */
+ return 0x36;
+ } else if (strcmp(keyn, "LCTL") == 0) { /* Left Control */
+ return 0x1d;
+ } else if (strcmp(keyn, "LALT") == 0) { /* Left Alt */
+ return 0x38;
+ } else if (strcmp(keyn, "SPCE") == 0) { /* Space */
+ return 0x39;
+ } else if (strcmp(keyn, "RALT") == 0) { /* Right Alt */
+ return 0x138;
+ } else if (strcmp(keyn, "LVL3") == 0) { /* More names of Right Alt */
+ return 0x138;
+ } else if (strcmp(keyn, "MDSW") == 0) { /* More names of Right Alt */
+ return 0x138;
+ } else if (strcmp(keyn, "ALGR") == 0) { /* More names of Right Alt */
+ return 0x138;
+ } else if (strcmp(keyn, "RCTL") == 0) { /* Right Control */
+ return 0x11d;
+ } else if (strcmp(keyn, "INS") == 0) { /* Insert */
+ return 0x152;
+ } else if (strcmp(keyn, "DELE") == 0) { /* Delete */
+ return 0x153;
+ } else if (strcmp(keyn, "LEFT") == 0) { /* Left Arrow */
+ return 0x14b;
+ } else if (strcmp(keyn, "HOME") == 0) { /* Home */
+ return 0x147;
+ } else if (strcmp(keyn, "END") == 0) { /* End */
+ return 0x14f;
+ } else if (strcmp(keyn, "UP") == 0) { /* Up Arrow */
+ return 0x148;
+ } else if (strcmp(keyn, "DOWN") == 0) { /* Down Arrow */
+ return 0x150;
+ } else if (strcmp(keyn, "PGUP") == 0) { /* Page Up */
+ return 0x149;
+ } else if (strcmp(keyn, "PGDN") == 0) { /* Page Down */
+ return 0x151;
+ } else if (strcmp(keyn, "RGHT") == 0) { /* Right Arrow */
+ return 0x14d;
+ } else if (strcmp(keyn, "NMLK") == 0) { /* Num Lock */
+ return 0x45;
+ } else if (strcmp(keyn, "KP7") == 0) {
+ return 0x47;
+ } else if (strcmp(keyn, "KP4") == 0) {
+ return 0x4b;
+ } else if (strcmp(keyn, "KP1") == 0) {
+ return 0x4f;
+ } else if (strcmp(keyn, "KPDV") == 0) { /* Numeric / */
+ return 0x00;
+ } else if (strcmp(keyn, "KP8") == 0) {
+ return 0x48;
+ } else if (strcmp(keyn, "KP5") == 0) {
+ return 0x4c;
+ } else if (strcmp(keyn, "KP2") == 0) {
+ return 0x50;
+ } else if (strcmp(keyn, "KP0") == 0) {
+ return 0x52;
+ } else if (strcmp(keyn, "KPMU") == 0) { /* Numeric * */
+ return 0x37;
+ } else if (strcmp(keyn, "KP9") == 0) { /* Numeric 9 */
+ return 0x49;
+ } else if (strcmp(keyn, "KP6") == 0) { /* Numeric 6 */
+ return 0x4d;
+ } else if (strcmp(keyn, "KP3") == 0) { /* Numeric 3 */
+ return 0x51;
+ } else if (strcmp(keyn, "KPDL") == 0) { /* Numeric . */
+ return 0x53;
+ } else if (strcmp(keyn, "KPCO") == 0) { /* Numeric . */
+ return 0x53;
+ } else if (strcmp(keyn, "KPSU") == 0) { /* Numeric - */
+ return 0x4a;
+ } else if (strcmp(keyn, "KPAD") == 0) { /* Numeric + */
+ return 0x4e;
+ } else if (strcmp(keyn, "KPEQ") == 0) {
+ return 0x00;
+ } else if (strcmp(keyn, "KPEN") == 0) { /* Numeric Enter */
+ return 0x11c;
+ } else if (strcmp(keyn, "ESC") == 0) { /* Escape */
+ return 0x01;
+ } else if (strcmp(keyn, "FK01") == 0) { /* F1 */
+ return 0x3b;
+ } else if (strcmp(keyn, "FK02") == 0) {
+ return 0x3c;
+ } else if (strcmp(keyn, "FK03") == 0) {
+ return 0x3d;
+ } else if (strcmp(keyn, "FK04") == 0) {
+ return 0x3e;
+ } else if (strcmp(keyn, "FK05") == 0) {
+ return 0x3f;
+ } else if (strcmp(keyn, "FK06") == 0) {
+ return 0x40;
+ } else if (strcmp(keyn, "FK07") == 0) {
+ return 0x41;
+ } else if (strcmp(keyn, "FK08") == 0) {
+ return 0x42;
+ } else if (strcmp(keyn, "FK09") == 0) {
+ return 0x43;
+ } else if (strcmp(keyn, "FK10") == 0) {
+ return 0x44;
+ } else if (strcmp(keyn, "FK11") == 0) {
+ return 0x57;
+ } else if (strcmp(keyn, "FK12") == 0) { /* F12 */
+ return 0x58;
+ } else if (strcmp(keyn, "FK13") == 0) { /* F13 */
+ return 0x00;
+ } else if (strcmp(keyn, "FK14") == 0) {
+ return 0x00;
+ } else if (strcmp(keyn, "FK15") == 0) {
+ return 0x00;
+ } else if (strcmp(keyn, "FK16") == 0) {
+ return 0x00;
+ } else if (strcmp(keyn, "FK17") == 0) {
+ return 0x00;
+ } else if (strcmp(keyn, "FK18") == 0) {
+ return 0x00;
+ } else if (strcmp(keyn, "FK19") == 0) {
+ return 0x00;
+ } else if (strcmp(keyn, "FK20") == 0) {
+ return 0x00;
+ } else if (strcmp(keyn, "FK21") == 0) {
+ return 0x00;
+ } else if (strcmp(keyn, "FK22") == 0) {
+ return 0x00;
+ } else if (strcmp(keyn, "FK23") == 0) {
+ return 0x00;
+ } else if (strcmp(keyn, "FK24") == 0) {
+ return 0x00;
+ } else if (strcmp(keyn, "FK25") == 0) { /* F25 */
+ return 0x00;
+ } else if (strcmp(keyn, "PRSC") == 0) {
+ return 0x00;
+ } else if (strcmp(keyn, "SCLK") == 0) {
+ return 0x46;
+ } else if (strcmp(keyn, "PAUS") == 0) {
+ return 0x45;
+ } else if (strcmp(keyn, "LWIN") == 0) {
+ return 0x15b;
+ } else if (strcmp(keyn, "RWIN") == 0) {
+ return 0x15c;
+ } else if (strcmp(keyn, "MENU") == 0) {
+ return 0x15d;
+ } else if (strcmp(keyn, "POWR") == 0) {
+ return 0x15e;
+ } else if (strcmp(keyn, "KATA") == 0) { /* Katakana */
+ return 0x70;
+ } else if (strcmp(keyn, "XFER") == 0) { /* Convert/Henkan */
+ return 0x79;
+ } else if (strcmp(keyn, "NFER") == 0) { /* Non Convert/Muhenkan */
+ return 0x7b;
+ } else {
+ return 0x00;
+ }
+#else
+ return 0x00;
+#endif
+}
/***********************************************************************
* X11DRV_send_keyboard_input
@@ -1594,6 +1871,9 @@ void X11DRV_InitKeyboard( Display *display )
{ 0, 0 }
};
int vkey_range;
+#ifdef HAVE_XKB
+ XkbDescPtr kb_desc;
+#endif
pthread_mutex_lock( &kbd_mutex );
XDisplayKeycodes(display, &min_keycode, &max_keycode);
@@ -1641,6 +1921,14 @@ void X11DRV_InitKeyboard( Display *display )
e2.type = KeyPress;
memset(keyc2vkey, 0, sizeof(keyc2vkey));
+#ifdef HAVE_XKB
+ kb_desc = XkbGetMap(display, 0, XkbUseCoreKbd);
+ if (use_xkb)
+ {
+ /* Allocate and fill the keycode-name map. */
+ XkbGetNames(display, XkbKeyNamesMask, kb_desc);
+ }
+#endif
for (keyc = min_keycode; keyc <= max_keycode; keyc++)
{
char buf[30];
@@ -1652,20 +1940,32 @@ void X11DRV_InitKeyboard( Display *display )
vkey = 0; scan = 0;
if (keysym) /* otherwise, keycode not used */
{
+#ifdef HAVE_XKB
+ if (use_xkb)
+ {
+ /* Returned key name may not be null-terminated, if it is exactly XkbKeyNameLength long, add a null to be sure. */
+ char keyn[XkbKeyNameLength+1];
+ memset(keyn, 0, XkbKeyNameLength+1);
+ memcpy(keyn, kb_desc->names->keys[keyc].name, XkbKeyNameLength);
+
+ /* Translate key name to a scan code. */
+ scan = scancode_from_key_name(keyn);
+ }
+#endif
if ((keysym >> 8) == 0xFF) /* non-character key */
{
vkey = nonchar_key_vkey[keysym & 0xff];
- scan = nonchar_key_scan[keysym & 0xff];
+ scan = scan ? scan : nonchar_key_scan[keysym & 0xff];
/* set extended bit when necessary */
if (scan & 0x100) vkey |= 0x100;
} else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */
vkey = xfree86_vendor_key_vkey[keysym & 0xff];
/* All vendor keys are extended with a scan code of 0 per testing on WinXP */
- scan = 0x100;
+ scan = scan ? scan : 0x100;
vkey |= 0x100;
} else if (keysym == 0x20) { /* Spacebar */
vkey = VK_SPACE;
- scan = 0x39;
+ scan = scan ? scan : 0x39;
} else if (have_chars) {
/* we seem to need to search the layout-dependent scancodes */
int maxlen=0,maxval=-1,ok;
@@ -1701,7 +2001,7 @@ void X11DRV_InitKeyboard( Display *display )
/* got it */
const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan;
const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey;
- scan = (*lscan)[maxval];
+ scan = scan ? scan : (*lscan)[maxval];
vkey = (*lvkey)[maxval];
}
}
@@ -1714,6 +2014,9 @@ void X11DRV_InitKeyboard( Display *display )
vkey_used[(vkey & 0xff)] = 1;
} /* for */
+#ifdef HAVE_XKB
+ XkbFreeClientMap(kb_desc, 0, TRUE);
+#endif
#define VKEY_IF_NOT_USED(vkey) (vkey_used[(vkey)] ? 0 : (vkey_used[(vkey)] = 1, (vkey)))
for (keyc = min_keycode; keyc <= max_keycode; keyc++)
{
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/182
More information about the wine-devel
mailing list