[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