How to Translate X11 Keycode Back to Scancode or Hid Usage Id Reliably

Get scancode rather than keycode on Linux using X11

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

If you want to get specific keys such as "W" or "4", no matter where they're located, you can just convert the keycode you receive from the event into a 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 "the nth key of the mth row". You need key names to do that. In this case "W" is AD02 and "4" is AE04 on QWERTY keyboards.

Let's say you are making a game in which the player needs to use the WASD keys to move. If you look for KeySyms it's going to work fine on QWERTY keyboards, but people using other keyboard layouts such as AZERTY, QWERTZ and DVORAK will have trouble. So in this case it's better to use key names.

Using key names is actually pretty easy, but the documentation is very messy (but I still recommend you take a look at it). I had to take a look at GLFW's source code (specifically src/x11_init.c) because I was clueless. This method requires Xkb, but you were already using it so I guess that's no problem.

First you need to get the keyboard map and obtain symbolic names. We only want key names so we use XkbKeyNamesMask.

#include <X11/XKBlib.h>

XkbDescPtr KbDesc = XkbGetMap(XDisplay, 0, XkbUseCoreKbd);
XkbGetNames(XDisplay, XkbKeyNamesMask, KbDesc);

Then, at the event loop you can use the KbDesc->names->keys array to get the key name for a specific keycode:

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];
memcpy(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's in its place? */
{
/* Do something... */
}
/* ... */
}

/* ... */
}

And that's it. It seems to work pretty well so far. I'd like to mention that special keys have very different key names. For example, Left Shift is LFSH, Left Control is LCTL, Space is SPCE and Escape is ESC.

I hope it helps.

OS X Cocoa - Translate Virtual Scan Code to and from Char

I'm not sure there is, sadly. CGEvent and NSEvent (which aren't toll-free bridged, but NSEvent can convert back and forth) are the standard containers for events including key presses and as a result can convert from device-dependent scan codes to unicode string sequences but there seems to be no way to go in the other direction — from a unicode character to the required sequence of device-dependent key presses.

There's a brief comment underneath CGEventCreateKeyboardEvent that:

All keystrokes needed to generate a character must be entered,
including modifier keys. For example, to produce a 'Z', the SHIFT key
must be down, the 'z' key must go down, and then the SHIFT and 'z' key
must be released:

But the sequence shown then has hardcoded and unexplained constants for the shift and z keys.

How to translate hardware ascii to hardware scan code in win32

Seems the most direct method would be to use MapVirtualKey or MapVirtualKeyEx which translates from VK-codes to Scan codes.

The character to VK scan code can be gotten using VkKeyScan (extracting the low byte which contains the VK Code according to MS documentation). So to get the scan code of 'X':

 UINT VKCode=LOBYTE(VkKeyScan('X'));
UINT ScanCode=MapVirtualKey(VKCode,0);

How can I get the keyboard scan code in java?

As MadProgrammer said: You have to use JNA or JNI. You can also have a look at those projects:

  • jintellitype (Windows only)

JIntellitype is a Java API for interacting with Microsoft Intellitype
commands as well as registering for Global Hotkeys in your Java
application. The API is a Java JNI library that uses a C++ DLL to do
all the communication with Windows.

There are similar projects Linux and Mac OS X.


  • JNativeHook (Windows, Linux and Mac OS?)

JNativeHook is a library to provide global keyboard and mouse
listeners for Java. This will allow you to listen for global shortcuts
or mouse motion that would otherwise be impossible using pure Java. To
accomplish this task, JNativeHook leverages platform dependent native
code through Java's native interface to create low level system wide
hooks and deliver those events to your application.


  • Java – Global (low level) Keyboard / Mouse Hook (Windows only)

Windows only, capable of Win 7 / 8 (32 and 64 bit)


  • JNA Keyboard Hook in Windows

How to debug USB HID scancode-keycode translation in Linux

Found the problem. After looking through the code for usbhid I realized that it was what was assigning the available event codes discovered by evtest. To do this, it reads through the HID descriptor. As it turned out I had used a generic HID descriptor and the Logical Maximum and Usage Maximum were cutting off the higher numbered HID codes. I used https://github.com/DIGImend/hidrd to get an editable version of my binary descriptor and then changed the Usage Maximum and Logical Maximum to the highest HID code I use. Reconverted it to binary format, uploaded and started the keyboard. Now evtest recognizes all keys.

Here is my original spec:

Usage Page (Desktop),               ; Generic desktop controls (01h)
Usage (Keyboard), ; Keyboard (06h, application collection)
Collection (Application),
Usage Page (Keyboard), ; Keyboard/keypad (07h)
Usage Minimum (KB Leftcontrol), ; Keyboard left control (E0h, dynamic value)
Usage Maximum (KB Right GUI), ; Keyboard right GUI (E7h, dynamic value)
Logical Minimum (0),
Logical Maximum (1),
Report Size (1),
Report Count (8),
Input (Variable),
Report Count (1),
Report Size (8),
Input (Constant, Variable),
Report Count (5),
Report Size (1),
Usage Page (LED), ; LEDs (08h)
Usage Minimum (01h),
Usage Maximum (05h),
Output (Variable),
Report Count (1),
Report Size (3),
Output (Constant, Variable),
Report Count (6),
Report Size (8),
Logical Minimum (0),
Logical Maximum (101),
Usage Page (Keyboard), ; Keyboard/keypad (07h)
Usage Minimum (None), ; No event (00h, selector)
Usage Maximum (KB Application), ; Keyboard Application (65h, selector)
Input,
End Collection

And my updated spec:

Usage Page (Desktop),               ; Generic desktop controls (01h)
Usage (Keyboard), ; Keyboard (06h, application collection)
Collection (Application),
Usage Page (Keyboard), ; Keyboard/keypad (07h)
Usage Minimum (KB Leftcontrol), ; Keyboard left control (E0h, dynamic value)
Usage Maximum (KB Right GUI), ; Keyboard right GUI (E7h, dynamic value)
Logical Minimum (0),
Logical Maximum (1),
Report Size (1),
Report Count (8),
Input (Variable),
Report Count (1),
Report Size (8),
Input (Constant, Variable),
Report Count (5),
Report Size (1),
Usage Page (LED), ; LEDs (08h)
Usage Minimum (01h),
Usage Maximum (05h),
Output (Variable),
Report Count (1),
Report Size (3),
Output (Constant, Variable),
Report Count (6),
Report Size (8),
Logical Minimum (0),
Logical Maximum (115),
Usage Page (Keyboard), ; Keyboard/keypad (07h)
Usage Minimum (None), ; No event (00h, selector)
Usage Maximum (KB F24), ; Keyboard F24 (73h, selector)
Input,
End Collection


Related Topics



Leave a reply



Submit