Miałem ten sam problem i właśnie znalazłem rozwiązanie. Zacznijmy od tego, co oczywiste.
Jeśli chcesz uzyskać określone klucze, takie jak "W" lub "4", bez względu na to, gdzie się znajdują, możesz po prostu przekonwertować kod klucza otrzymany z wydarzenia na KeySym. W tym przypadku "W" to XK_W
i XK_w
, a "4" to XK_4
(i XK_dollar
na większości klawiatur).
Czasami jednak potrzebne są klucze, takie jak "klucz o numerze jeden th". Aby to zrobić, potrzebujesz nazw kluczowych. W tym przypadku "W" to AD02
, a "4" to AE04
na klawiaturach QWERTY.
Załóżmy, że tworzysz grę, w której gracz musi użyć klawiszy WASD, aby się poruszać. Jeśli szukasz KeySymów, to będzie działało dobrze na klawiaturach QWERTY, ale ludzie używający innych układów klawiatury, takich jak AZERTY, QWERTZ i DVORAK będą mieli kłopoty. Więc w tym przypadku lepiej użyć nazw kluczowych.
Używanie nazw klawiszy jest w rzeczywistości dość łatwe, ale documentation jest bardzo brudny (ale nadal zalecam, aby go obejrzeć). Musiałem spojrzeć na kod źródłowy GLFW (konkretnie src/x11_init.c), ponieważ nie miałem pojęcia. Ta metoda wymaga Xkb, ale już go używasz, więc domyślam się, że to żaden problem.
Najpierw trzeba uzyskać mapę klawiatury i uzyskać symboliczne nazwy. Chcemy tylko kluczowych nazw, więc używamy XkbKeyNamesMask
.
#include <X11/XKBlib.h>
XkbDescPtr KbDesc = XkbGetMap(XDisplay, 0, XkbUseCoreKbd);
XkbGetNames(XDisplay, XkbKeyNamesMask, KbDesc);
Następnie w pętli zdarzeń można użyć tablicę KbDesc-> names->, aby uzyskać nazwę klucza dla konkretnego kodu dostępu:
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... */
}
/* ... */
}
/* ... */
}
I to wszystko. Wydaje się, że do tej pory działa całkiem dobrze. Chciałbym wspomnieć, że specjalne klucze mają bardzo różne nazwy kluczowe. Na przykład Lewy Shift to LFSH
, lewy przycisk kontrolny to LCTL
, spacja to SPCE
, a Escape to ESC
.
Mam nadzieję, że to pomaga.
Sam pomysł, że klucz ma stałą fizyczną lokalizację, zależy od konkretnej implementacji wprowadzania znaków. Ludzie mogą używać wirtualnych klawiatur, gdzie mogą dowolnie zmieniać kolejność klawiszy. Lub ręczne wprowadzanie lub rozpoznawanie głosu albo ... W żadnym z tych przypadków nie ma fizycznych lokalizacji związanych z klawiszami.Nawet jeśli istnieje fizyczna klawiatura ze skanerami, istnieje wiele niekompatybilnych modeli, zobacz inne pliki w '/ usr/share/X11/xkb/keycodes'. –
To ma sens. Powiedzmy, że ignorujemy wszelkie specjalne metody wprowadzania danych inne niż tradycyjne klawiatury. Jeśli któryś z plików z "/ usr/share/X11/xkb/keycodes" może być użyty do mapowania, czy istnieje sposób na wykrycie, który z nich jest używany przez urządzenie? – ComfyS
Możesz uzyskać fizyczną lokalizację kluczy, analizując geometrię klawiatury. Uruchom 'setxkbmap -print -verbose 10', a zobaczysz instrukcję include geometrii. Zbadaj pliki w X11/xkb/geometry (najprawdopodobniej jeden o nazwie "pc"). Zobaczysz także, które mapowanie jest w użyciu. Nie znam programowego odpowiednika "setxkbmap -print", ale zdecydowanie taki jest. Nie jestem pewien, co się stanie, jeśli użytkownik zmieni swoją klawiaturę za pomocą xmodmap, ale powiedziałbym, niech sobie z tym poradzą. –