Get scancode, not keycode on Linux using X11

I am trying to listen for keyboard input (using the X11 event loop) and get scancodes. These scancodes should refer to the physical location of the key, and not to the characteristic type. The problem is that all I can get is KeySyms and KeyCodes, which display differently for different languages ​​(e.g. QWERTY vs QWERTZ).

My current solution is to read the file "/ usr / share / X11 / xkb / keycodes / evdev". It contains mappings of key locations with key codes. Using this, I can simply translate any keycode back to scancode. I guess this is not a stable way to do something. I don't know anything about Linux at all. That is why I thought that asking here might be a good idea.

Can we assume that these evdev mappings are used by most user machines? If not, where else can you find the key mappings that are actually used? Or is there a better solution for all this?

+5
source share
1 answer

I had the same problem and just found a solution. Let's start with the obvious.

If you want to receive certain keys, such as "W" or "4", no matter where they are, you can simply convert the key code that you receive from the event into KeySym. In this case, β€œW” is XK_W and XK_W , and β€œ4” is XK_4 (and XK_dollar on most keyboards).

However, sometimes you want to get keys, such as "key n th of the string m th ". This requires key names. In this case, β€œW” is AD02 , and β€œ4” is AE04 on QWERTY keyboards.

Let's say you make a game in which a player needs to use the WASD keys to move. If you're looking for KeySyms, it works great on QWERTY keyboards, but people using other keyboard layouts like AZERTY, QWERTZ and DVORAK will have problems. Therefore, in this case, it is better to use key names.

Using key names is actually quite simple, but the documentation is very dirty (but I still recommend that you take a look at it). I had to take a look at the GLFW source code (specifically src / x11_init.c ) because I was clueless. This method requires Xkb, but you have already used it, so I think there are no problems.

First you need to get a keyboard map and get symbolic names. We only need key names, so we use XkbKeyNamesMask .

 #include <X11/XKBlib.h> XkbDescPtr KbDesc = XkbGetMap(XDisplay, 0, XkbUseCoreKbd); XkbGetNames(XDisplay, XkbKeyNamesMask, KbDesc); 

Then, in the event loop, you can use the KbDesc-> names-> key array to get the key name for a specific keyboard code:

 XEvent Event; XNextEvent(XDisplay, &Event); switch (Event.type) { case KeyPress: /* I'm not sure this 'if' is necessary, but better safe than sorry */ if ((Event.xkey.keycode >= KbDesc->min_key_code) && (Event.xkey.keycode <= KbDesc->max_key_code)) { /* Copy key name into Name */ char Name[XkbKeyNameLength + 1]; memcmp(Name, KbDesc->names->keys[Event.xkey.keycode].name, XkbKeyNameLength); Name[XkbKeyNameLength] = '\0'; /* Null terminator */ if (strcmp(Name, "AD02") == 0) /* Is it W (for QWERTY and QWERTZ) / Z (for AZERTY) / comma (for DVORAK) /  (for Russian) etc... ? */ { /* Do something... */ } else if (strcmp(Name, "AE04") == 0) /* Is it 4 (for most keyboards) / whatever in its place? */ { /* Do something... */ } /* ... */ } /* ... */ } 

What is it. Everything seems to be fine so far. I would like to mention that special keys have very different key names. For example, Left Shift is LFSH , Left Control is LCTL , LCTL is space SPCE and Escape is ESC .

Hope this helps.

+3
source

All Articles