Ist es einem Daemon-Prozess (also einem Hintergrundprozess) möglich, nach Tastendrücken auf einer USB-Tastatur zu suchen?

Ist es einem Daemon-Prozess (also einem Hintergrundprozess) möglich, nach Tastendrücken auf einer USB-Tastatur zu suchen?

Ich arbeite an einem eingebetteten Linux-Projekt, bei dem ich ein Programm entwickeln werde, das beim Hochfahren automatisch ausgeführt wird und über eine Zeichenanzeige und eine Art Tastenfeld mit dem Benutzer interagiert. Wenn wir uns für ein einfaches GPIO-Tastenarray entscheiden, kann ich problemlos ein Programm schreiben, das nach Tastendrücken auf diesen GPIO-Leitungen sucht. Einer unserer Gedanken war jedoch, stattdessen ein USB-Ziffernblockgerät für die Benutzereingabe zu verwenden. Meines Wissens werden sich diese Geräte dem Betriebssystem als USB-Tastatur präsentieren. Wenn ich diesen Weg einschlage, gibt es dann eine Möglichkeit für mein Programm, von Linux aus nach Eingaben auf dieser USB-Tastatur zu suchen, wobei zu berücksichtigen ist, dass es kein virtuelles Terminal oder VGA-Display gibt? Wenn eine USB-Tastatur angeschlossen ist, wird dann eine Entität in „/dev“ angezeigt, für die ich einen Dateideskriptor öffnen kann?

Antwort1

Geräte erhalten höchstwahrscheinlich eine Datei mit /dev/input/dem Namen, eventNwobei N für die verschiedenen Geräte steht, wie Maus, Tastatur, Buchse, Netzschalter usw.

ls -l  /dev/input/by-{path,id}/

sollte dir einen Hinweis geben.

Siehe auch:

cat /proc/bus/input/devices

Wobei Sysfsder Wert der Pfad unter ist /sys.

Sie können testen, indem Sie z. B.

cat /dev/input/event2 # if 2 is kbd.

Verwenden Sie zur Implementierung ioctl und überprüfen Sie Geräte + Monitor.

BEARBEITEN 2:

OK. Ich erweitere diese Antwort basierend auf der /dev/input/eventNverwendeten Annahme.

Eine Möglichkeit könnte sein:

  1. Beim Start werden alle eventin gefundenen Dateien in einer Schleife ausgeführt /dev/input/. Verwenden Sie ioctl()diese Option, um Ereignisbits anzufordern:

    ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), &evbit);
    

    Überprüfen Sie dann, ob EV_KEYdas -Bit gesetzt ist.

  2. IFF festlegen und dann nach Schlüsseln suchen:

    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), &keybit);
    

    Wenn beispielsweise Zifferntasten interessant sind, dann prüfen Sie, ob die Bits für KEY_0- KEY9und KEY_KP0bis vorhanden sind KEY_KP9.

  3. IFF-Schlüssel gefunden, dann mit der Überwachung der Ereignisdatei im Thread beginnen.

  4. Zurück zu 1.

Auf diese Weise sollten Sie alle Geräte überwachen können, die die gewünschten Kriterien erfüllen. Sie können nicht nur prüfen, ob EV_KEYbeispielsweise beim Einschaltknopf dieses Bit gesetzt ist, sondern ob KEY_Ausw. offensichtlich nicht gesetzt ist.

Habe falsche Positivmeldungen für exotische Schlüssel gesehen, aber fürnormale Tastendas sollte genügen. Es schadet nicht direkt, z. B. Ereignisdateien für einen Netzschalter oder eine Buchse zu überwachen, aber diese geben keine fraglichen Ereignisse aus (auch bekannt als fehlerhafter Code).

Näheres dazu weiter unten.


BEARBEITEN 1:

In Bezug auf„Erklären Sie diese letzte Aussage …“. Übergehen inPaketüberflusslande hier … aber:

Ein schnelles und einfaches Beispiel in C. Sie müssen verschiedene Codes implementieren, um zu prüfen, ob Sie tatsächlich das richtige Gerät erhalten und Ereignistyp, Code und Wert übersetzen. Normalerweise Taste gedrückt, Taste los, Taste wiederholen, Tastencode usw.

Ich habe keine Zeit (und es ist zu viel hier), den Rest hinzuzufügen.

Schauen Sie sich linux/input.hProgramme wie dumpkeysKernelcode usw. an, um Codes zuzuordnen. Beispiel:dumpkeys -l

Jedenfalls:

Ausführen als zB:

# ./testprog /dev/input/event2

Code:

#include <stdio.h>

#include <string.h>     /* strerror() */
#include <errno.h>      /* errno */

#include <fcntl.h>      /* open() */
#include <unistd.h>     /* close() */
#include <sys/ioctl.h>  /* ioctl() */

#include <linux/input.h>    /* EVIOCGVERSION ++ */

#define EV_BUF_SIZE 16

int main(int argc, char *argv[])
{
    int fd, sz;
    unsigned i;

    /* A few examples of information to gather */
    unsigned version;
    unsigned short id[4];                   /* or use struct input_id */
    char name[256] = "N/A";

    struct input_event ev[EV_BUF_SIZE]; /* Read up to N events ata time */

    if (argc < 2) {
        fprintf(stderr,
            "Usage: %s /dev/input/eventN\n"
            "Where X = input device number\n",
            argv[0]
        );
        return EINVAL;
    }

    if ((fd = open(argv[1], O_RDONLY)) < 0) {
        fprintf(stderr,
            "ERR %d:\n"
            "Unable to open `%s'\n"
            "%s\n",
            errno, argv[1], strerror(errno)
        );
    }
    /* Error check here as well. */
    ioctl(fd, EVIOCGVERSION, &version);
    ioctl(fd, EVIOCGID, id); 
    ioctl(fd, EVIOCGNAME(sizeof(name)), name);

    fprintf(stderr,
        "Name      : %s\n"
        "Version   : %d.%d.%d\n"
        "ID        : Bus=%04x Vendor=%04x Product=%04x Version=%04x\n"
        "----------\n"
        ,
        name,

        version >> 16,
        (version >> 8) & 0xff,
        version & 0xff,

        id[ID_BUS],
        id[ID_VENDOR],
        id[ID_PRODUCT],
        id[ID_VERSION]
    );

    /* Loop. Read event file and parse result. */
    for (;;) {
        sz = read(fd, ev, sizeof(struct input_event) * EV_BUF_SIZE);

        if (sz < (int) sizeof(struct input_event)) {
            fprintf(stderr,
                "ERR %d:\n"
                "Reading of `%s' failed\n"
                "%s\n",
                errno, argv[1], strerror(errno)
            );
            goto fine;
        }

        /* Implement code to translate type, code and value */
        for (i = 0; i < sz / sizeof(struct input_event); ++i) {
            fprintf(stderr,
                "%ld.%06ld: "
                "type=%02x "
                "code=%02x "
                "value=%02x\n",
                ev[i].time.tv_sec,
                ev[i].time.tv_usec,
                ev[i].type,
                ev[i].code,
                ev[i].value
            );
        }
    }

fine:
    close(fd);

    return errno;
}

EDIT 2 (Fortsetzung):

Beachten Sie, dass /proc/bus/input/devicesSie am Anfang jeder Zeile einen Buchstaben haben. Hier Bbedeutet Bitmap. Das ist zum Beispiel:

B: PROP=0
B: EV=120013
B: KEY=20000 200 20 0 0 0 0 500f 2100002 3803078 f900d401 feffffdf ffefffff ffffffff fffffffe
B: MSC=10
B: LED=7

Jedes dieser Bits entspricht einer Eigenschaft des Geräts. Bei der Bitmap bedeutet dies, dass 1 das Vorhandensein einer Eigenschaft anzeigt, wie in definiert linux/input.h:

B: PROP=0    => 0000 0000
B: EV=120013 => 0001 0010 0000 0000 0001 0011 (Event types sup. in this device.)
                   |   |               |   ||
                   |   |               |   |+-- EV_SYN (0x00)
                   |   |               |   +--- EV_KEY (0x01)
                   |   |               +------- EV_MSC (0x04)
                   |   +----------------------- EV_LED (0x11)
                   +--------------------------- EV_REP (0x14)
B: KEY=20... => OK, I'm not writing out this one as  it is a bit huge.

B: MSC=10    => 0001 0000
                   |
                   +------- MSC_SCAN
B: LED=7     => 0000 0111 , indicates what LED's are present
                      |||
                      ||+-- LED_NUML
                      |+--- LED_CAPSL
                      +---- LED_SCROLL

Schauen Sie sich /drivers/input/input.{h,c}den Kernel-Quellcode an. Dort gibt es jede Menge guten Code. (Die Geräteeigenschaften werden beispielsweise erzeugt durchdiese Funktion.)

Jede dieser Eigenschaftszuordnungen kann über erreicht werden ioctl. Wenn Sie beispielsweise prüfen möchten, welche LED-Eigenschaften verfügbar sind, geben Sie Folgendes ein:

ioctl(fd, EVIOCGBIT(EV_LED, sizeof(ledbit)), &ledbit);

Schauen Sie sich die Definition von struct input_dev„in“ an input.h, um zu erfahren, wie ledbites definiert ist.

Um den Status der LEDs zu überprüfen, sagen Sie:

ioctl(fd, EVIOCGLED(sizeof(ledbit)), &ledbit);

Wenn Bit 1 ledbit1 ist, leuchtet die Num-Lock-Taste. Wenn Bit 2 1 ist, leuchtet die Feststelltaste usw.

input.hhat die verschiedenen Definitionen.


Hinweise zur Ereignisüberwachung:

Pseudocode zur Überwachung könnte etwa in die Richtung gehen:

WHILE TRUE
    READ input_event
    IF event->type == EV_SYN THEN
        IF event->code == SYN_DROPPED THEN
            Discard all events including next EV_SYN
        ELSE
            This marks EOF current event.
        FI
    ELSE IF event->type == EV_KEY THEN
        SWITCH ev->value
            CASE 0: Key Release    (act accordingly)
            CASE 1: Key Press      (act accordingly)
            CASE 2: Key Autorepeat (act accordingly)
        END SWITCH
    FI
END WHILE

Einige zugehörige Dokumente:

  1. Documentation/input/input.txt, beachten Sie insbesondere Abschnitt 5.
  2. Documentation/input/event-codes.txt, Beschreibung verschiedener Veranstaltungen usw. Beachten Sie, was unter anderem erwähnt wird EV_SYNüberSYN_DROPPED
  3. Documentation/input... den Rest können Sie nachlesen, wenn Sie möchten.

Antwort2

Dies ist ganz einfach durch die Referenzierung möglich /dev/input/by-id/usb-manufacturername_*serialnumber*. Diese erscheinen als symbolische Links, die Sie dereferenzieren können, readlink -eum das zugehörige Blockgerät zu ermitteln. Diese Links werden jedoch von erstellt, udevdie in Ihrer eingebetteten Umgebung möglicherweise nicht vorhanden sind.

Oder... Schauen Sie dmesgnach dem Anschließen des USB-Geräts nach. Der Knoten sollte angezeigt werden /dev.

verwandte Informationen