2016-07-24 14 views
5

Próbuję odsłuchać dane wejściowe z klawiatury (przy użyciu pętli zdarzeń X11) i uzyskać kody błędów. Scancody te powinny odnosić się do fizycznej lokalizacji klucza, a nie postaci, którą wpisuje. Problem w tym, że wszystko, co mogę uzyskać, to KeySyms i KeyCodes, które są mapowane inaczej dla różnych języków (na przykład QWERTY vs QWERTZ).Uzyskaj kod scancode zamiast kodu klucza w systemie Linux przy użyciu X11

Moje obecne rozwiązanie polega na odczytaniu pliku "/ usr/share/X11/xkb/keycodes/evdev". Zawiera odwzorowania kluczowych lokalizacji na kluczowe kody. Używając tego mogę po prostu przetłumaczyć dowolny kod z powrotem na kod. Domyślam się, że nie jest to stabilny sposób robienia rzeczy. W ogóle nie znam się na Linuksie. Dlatego pomyślałem, że spytanie tutaj może być dobrym pomysłem.

Czy można bezpiecznie założyć, że te odwzorowania evdev są używane przez większość komputerów użytkowników? Jeśli nie, to gdzie mogę znaleźć kluczowe odwzorowania, które są aktualnie używane? Czy istnieje lepsze rozwiązanie tego wszystkiego?

+1

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'. –

+0

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

+0

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ą. –

Odpowiedz

3

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.

Powiązane problemy