%20m%C3%B6glich%2C%20nach%20Tastendr%C3%BCcken%20auf%20einer%20USB-Tastatur%20zu%20suchen%3F.png)
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, eventN
wobei 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 Sysfs
der 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/eventN
verwendeten Annahme.
Eine Möglichkeit könnte sein:
Beim Start werden alle
event
in gefundenen Dateien in einer Schleife ausgeführt/dev/input/
. Verwenden Sieioctl()
diese Option, um Ereignisbits anzufordern:ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), &evbit);
Überprüfen Sie dann, ob
EV_KEY
das -Bit gesetzt ist.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
-KEY9
undKEY_KP0
bis vorhanden sindKEY_KP9
.IFF-Schlüssel gefunden, dann mit der Überwachung der Ereignisdatei im Thread beginnen.
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_KEY
beispielsweise beim Einschaltknopf dieses Bit gesetzt ist, sondern ob KEY_A
usw. 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.h
Programme wie dumpkeys
Kernelcode 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/devices
Sie am Anfang jeder Zeile einen Buchstaben haben. Hier B
bedeutet 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 ledbit
es definiert ist.
Um den Status der LEDs zu überprüfen, sagen Sie:
ioctl(fd, EVIOCGLED(sizeof(ledbit)), &ledbit);
Wenn Bit 1 ledbit
1 ist, leuchtet die Num-Lock-Taste. Wenn Bit 2 1 ist, leuchtet die Feststelltaste usw.
input.h
hat 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:
Documentation/input/input.txt
, beachten Sie insbesondere Abschnitt 5.Documentation/input/event-codes.txt
, Beschreibung verschiedener Veranstaltungen usw. Beachten Sie, was unter anderem erwähnt wirdEV_SYN
überSYN_DROPPED
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 -e
um das zugehörige Blockgerät zu ermitteln. Diese Links werden jedoch von erstellt, udev
die in Ihrer eingebetteten Umgebung möglicherweise nicht vorhanden sind.
Oder... Schauen Sie dmesg
nach dem Anschließen des USB-Geräts nach. Der Knoten sollte angezeigt werden /dev
.