Получить scancode вместо keycode на Linux с помощью X11



Я пытаюсь прослушать ввод с клавиатуры (используя цикл событий X11) и получить сканкоды. Эти сканкоды должны ссылаться на физическое расположение ключа, а не на символ, который он вводит. Проблема в том, что все, что я могу получить, - это KeySyms и KeyCodes, которые отображаются по-разному для разных языков (например, QWERTY vs QWERTZ).



Мое текущее решение-прочитать файл" /usr/share/X11/xkb/keycodes/evdev". Он содержит сопоставления ключевых местоположений с ключевыми кодами. Используя это я могу просто перевести любой ключ обратно в скан. Я думаю, что это не стабильный способ делать вещи, хотя. Я вообще мало что знаю о Linux. Вот почему я подумал, что спросить Здесь может быть хорошей идеей.



Можно ли с уверенностью предположить, что эти отображения evdev используются большинством машин пользователя? Если нет, то где еще я могу найти ключевые сопоставления, которые на самом деле используются? Или есть лучшее решение для всего этого?

663   1  

1 ответ:

У меня была та же проблема, и я только что нашел решение. Давайте начнем с очевидного первого.

Если вы хотите получить определенные ключи, такие как" W "или" 4", независимо от того, где они расположены, вы можете просто преобразовать код ключа, полученный от события, в KeySym. В этом случае "W" - это XK_W и XK_w, а" 4 " - это XK_4XK_dollar на большинстве клавиатур).

Однако иногда вы хотите получить ключи, такие как"NTh ключ mth строки". Вам нужны ключевые имена, чтобы сделать тот. В этом случае "W" - это AD02, а" 4 " - AE04 на клавиатурах QWERTY. Предположим, вы создаете игру, в которой игрок должен использовать клавиши WASD для перемещения. Если вы ищете KeySyms, он будет отлично работать на клавиатурах QWERTY, но у людей, использующих другие раскладки клавиатуры, такие как AZERTY, QWERTZ и DVORAK, возникнут проблемы. Поэтому в этом случае лучше использовать имена ключей.

Использовать имена ключей на самом деле довольно легко, но документация очень грязная (но я все еще рекомендую вам взглянуть на него). Мне пришлось взглянуть на исходный кодGLFW (в частности, src/x11_init.c ), потому что я был невежествен. Этот метод требует Xkb, но вы уже использовали его, так что я думаю, что это не проблема.

Сначала вам нужно получить карту клавиатуры и получить символические имена. Нам нужны только имена ключей, поэтому мы используем XkbKeyNamesMask.

#include <X11/XKBlib.h>

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

Затем в цикле событий вы можете использовать массив KbDesc->names->keys, чтобы получить имя ключа для конкретного код ключа:

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... */
        }
        /* ... */
    }

    /* ... */
}

И это все. Похоже, пока что это работает довольно хорошо. Я хотел бы отметить, что специальные ключи имеют очень разные имена ключей. Например, сдвиг влево - это LFSH, Управление влево-это LCTL, пространство-это SPCE, а побег-это ESC.

Я надеюсь, что это помогает.

Comments

    Ничего не найдено.