2016-07-24 2 views
5

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

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

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

+1

Сама идея о том, что ключ имеет фиксированное физическое местоположение, зависит от конкретной реализации ввода символов. Люди могут использовать виртуальные клавиатуры, где они могут сами менять сами ключи. Или рукописный ввод или распознавание голоса или ... В любом из этих случаев нет физических мест, связанных с ключами.Даже если есть физическая клавиатура со сканнодами, существует много несовместимых моделей, см. Другие файлы в '/ usr/share/X11/xkb/keycodes'. –

+0

Это имеет смысл. Предположим, мы игнорируем любые специальные методы ввода, отличные от традиционных клавиатур. Если какой-либо из файлов в «/ usr/share/X11/xkb/keycodes» можно использовать для сопоставления, существует ли способ определить, какой из них используется устройством? – ComfyS

+0

Вы можете получить физическое расположение клавиш, исследуя геометрию клавиатуры. Запустите 'setxkbmap -print -verbose 10', и вы увидите инструкцию geometry include. Изучите файлы в X11/xkb/geometry (скорее всего, один из них называется «pc»). Вы также увидите, какое отображение используется. Я не знаю программный эквивалент 'setxkbmap -print', но определенно один. Я не уверен, что произойдет, если пользователь переделает свою клавиатуру с помощью xmodmap, но я бы сказал, пусть они справятся с этим. –

ответ

3

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

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

Однако, иногда вы хотите, чтобы получить ключи, такие как «п я ключа м я ряда». Для этого нужны ключевые имена. В этом случае «W» - AD02, а «4» - AE04 на клавиатурах QWERTY.

Предположим, вы делаете игру, в которой игроку необходимо использовать клавиши WASD для перемещения. Если вы ищете KeySyms, он отлично работает на клавиатурах QWERTY, но люди, использующие другие раскладки клавиатуры, такие как AZERTY, QWERTZ и DVORAK, будут иметь проблемы. Поэтому в этом случае лучше использовать имена ключей.

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

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

#include <X11/XKBlib.h> 

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

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

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

    /* ... */ 
} 

И это все. Кажется, пока все хорошо. Я хотел бы упомянуть, что специальные клавиши имеют очень разные ключевые имена. Например, Left Shift - LFSH, Left Control - LCTL, Space is SPCE и Escape is ESC.

Надеюсь, это поможет.

Смежные вопросы