Dostęp do kluczy z urządzenia wejściowego Linux

Co próbuję zrobić

Próbowałem uzyskać dostęp do klawiatury w systemie Linux. W szczególności muszę mieć dostęp do naciśnięć klawiszy modyfikującychbez inne naciśnięte klawisze. Ponadto chcę to zrobićbez działa system X.

Krótko mówiąc, moje wymagania są następujące:

Działa na LinuksieNie potrzebuje X11Może pobrać naciśnięcie klawisza modyfikatorabez pozostałe naciśnięte klawiszeObejmuje to następujące klucze:PrzesunięcieKontrolaAltPotrzebuję tylko prostego0 = not pressed, 1 = currently pressed aby poinformować mnie, czy klawisz jest przytrzymywany, gdy klawiatura jest zaznaczonaMoja konfiguracja komputera

Mój normalny komputer z Linuksem jest na ciężarówce w kierunku mojego nowego mieszkania; więc mam teraz tylko Macbook Air. Dlatego używam Linuksa w maszynie wirtualnej, aby to przetestować.

Maszyna wirtualna w VirtualBox

OS: Linux Mint 16Środowisko pulpitu: XFCE

Wszystko poniżej zostało zrobione w tym środowisku. Próbowałem zarówno z X-em, jak i jednym z pozostałych ttys.

Moje myśli

Zmienię to, jeśli ktoś może mnie poprawić.

Zrobiłem sporo czytania, aby zdać sobie sprawę, że biblioteki wyższego poziomu nie zapewniają takiej funkcjonalności. Klawisze modyfikujące są używane z innymi klawiszami, aby dostarczyć alternatywny kod klucza. Dostęp do samych klawiszy modyfikujących przez bibliotekę wysokiego poziomu w systemie Linux nie jest tak łatwy. Albo raczej nie znalazłem w tym celu wysokiego poziomu interfejsu API w systemie Linux.

myślałemlibtermkey byłaby odpowiedzią, ale wydaje się, że nie obsługuje ona klawisza modyfikującego Shift w sposób lepszy niż normalne pobieranie klawiszy. Nie jestem też pewien, czy działa bez X.

Podczas pracy z libtermkey (zanim zdałem sobie sprawę, że nie zmienia się w przypadkach takich jak Shift-Return), planowałem napisać demona, który uruchamiałby się w celu zbierania zdarzeń klawiatury. Uruchomione kopie programu demona po prostu przesyłają żądania danych klawiatury i w odpowiedzi odbierają dane klawiatury. Mógłbym użyć tej konfiguracji, aby coś zawsze działało w tle, na wypadek, gdyby nie mogłem sprawdzić statusów kluczy kodu w określonych godzinach (muszą być otrzymane kody kluczy, gdy się zdarzają).

Poniżej przedstawiam moje dwie próby napisania programu, który może czytać z urządzenia z klawiaturą Linux. Dołączyłem również mój mały czek, aby upewnić się, że mam odpowiednie urządzenie.

Próba # 1

Próbowałem uzyskać dostęp do urządzenia klawiatury bezpośrednio, ale napotykam problemy. Próbowałem tej sugestiitutaj to jest w innym wątku przepełnienia stosu. Dało mi to błąd segmentacji; więc zmieniłem go z fopen na otwarty:

// ...

int fd;
fd = open("/dev/input/by-path/platform-i8042-serio-0-event-kbd", O_RDONLY);

char key_map[KEY_MAX/8 + 1];

memset(key_map, 0, sizeof(key_map));
ioctl(fd, EVIOCGKEY(sizeof key_map), key_map);

// ...

Chociaż nie było błędu segmentacji, nie było żadnego wskaźnika naciśnięcia klawisza (nie tylko klawiszy modyfikujących). Przetestowałem to za pomocą:

./foo && echo "TRUE" || echo "FALSE"

Użyłem tego do testowania udanych kodów powrotu z poleceń dość często; więc wiem, że w porządku. Wypisałem również klucz (zawsze 0) i maskę (0100), aby sprawdzić. Po prostu nic nie wykrywa.

Próba # 2

Stąd pomyślałem, że spróbuję nieco innego podejścia. Chciałem dowiedzieć się, co robię źle. Następującyto strona zawierająca fragment kodu pokazujący drukowanie kluczowych kodów, włączyłem to do programu:

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <linux/input.h>

int main(int argc, char** argv) {
    uint8_t keys[128];
    int fd;

    fd = open("/dev/input/by-path/platform-i8042-serio-event-kbd", O_RDONLY);
    for (;;) {
        memset(keys, 0, 128);
        ioctl (fd, EVIOCGKEY(sizeof keys), keys);

        int i, j;
        for (i = 0; i < sizeof keys; i++)
            for (j = 0; j < 8; j++)
                if (keys[i] & (1 << j))
                    printf ("key code %d\n", (i*8) + j);
    }

    return 0;
}

Wcześniej miałem rozmiar 16 bajtów zamiast 128 bajtów. Powinienem szczerze poświęcić trochę więcej czasu na zrozumienie ioctl i EVIOCGKEY. Po prostu wiem, że przypuszczalnie mapuje bity na określone klawisze, aby wskazać naciśnięcia lub coś w tym stylu (popraw mnie, jeśli się mylę, proszę!).

Początkowo nie miałem też pętli i po prostu przytrzymałem różne klawisze, aby sprawdzić, czy pojawił się kod klucza. Nic nie otrzymałem; więc pomyślałem, że pętla może sprawić, że sprawdzenie będzie łatwiejsze do sprawdzenia na wypadek, gdyby coś przeoczyło.

Skąd wiem, że urządzenie wejściowe jest właściwe

Przetestowałem to, uruchamiająccat na urządzeniu wejściowym. Konkretnie:

$ sudo cat /dev/input/by-path/platform-i8042-serio-0-event-kbd

Garbage ASCII został wysłany do mojego terminala za pomocą naciśnięcia klawisza i zwolnienia, zaczynając od klawisza powrotu (enter), gdy zacząłem wydawać za pomocą cat. Wiem też, że to działa dobrze z klawiszami modyfikującymi, takimi jak shift, control, function, a nawet klawisz komend Apple na moim Macbooku z systemem Linux VM. Wyjście pojawiło się po naciśnięciu klawisza, zaczęło szybko pojawiać się z kolejnych sygnałów wysyłanych przez przytrzymanie klawisza i wysyłało więcej danych po zwolnieniu klawisza.

Tak więc, chociaż moje podejście może nie być właściwe (jestem gotów usłyszećkażdy alternatywnie) urządzenie wydaje się zapewniać to, czego potrzebuję.

Ponadto wiem, że to urządzenie jest tylko linkiem wskazującym na uruchamianie / dev / input / event2:

$ ls -l /dev/input/by-path/platform-i8042-serio-0-event-kbd

Wypróbowałem oba powyższe programy z / dev / input / event2 i nie otrzymałem żadnych danych. Uruchomienie cat na / dev / input / event2 zapewniło to samo wyjście, co w przypadku łącza.

questionAnswers(1)

yourAnswerToTheQuestion