%20%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E3%81%8C%20USB%20%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E3%81%8B%E3%82%89%E3%81%AE%E3%82%AD%E3%83%BC%E6%8A%BC%E4%B8%8B%E3%82%92%E6%8E%A2%E3%81%99%E3%81%93%E3%81%A8%E3%81%AF%E5%8F%AF%E8%83%BD%E3%81%A7%E3%81%99%E3%81%8B%3F.png)
私は組み込み Linux プロジェクトに取り組んでおり、起動時に自動的に実行され、文字ディスプレイと何らかのボタン アレイを介してユーザーと対話するプログラムを開発する予定です。単純な GPIO ボタン アレイを使用する場合は、それらの GPIO ラインでキー押下を検出するプログラムを簡単に作成できます。ただし、ユーザー入力には USB テンキー デバイスを使用するというアイデアもありました。私の理解では、これらのデバイスは OS に対して USB キーボードとして表示されます。この方法を採用する場合、仮想端末や VGA ディスプレイがないことを念頭に置き、Linux 内からこの USB キーボードの入力を検出するプログラムはありますか。USB キーボードが接続されると、ファイル記述子を開くことができるエンティティが '/dev' 内に表示されますか。
答え1
/dev/input/
デバイスは、ほとんどの場合、 という名前のファイルを取得します。eventN
ここで、N は、マウス、キーボード、ジャック、電源ボタンなどのさまざまなデバイスです。
ls -l /dev/input/by-{path,id}/
ヒントになるはずです。
こちらもご覧ください:
cat /proc/bus/input/devices
ここで、Sysfs
値は の下のパスです/sys
。
例えば次のようにテストすることができます
cat /dev/input/event2 # if 2 is kbd.
実装するには、ioctl を使用してデバイスとモニターをチェックします。
編集2:
OK。 が使用されているという仮定に基づいて、この回答を拡張します/dev/input/eventN
。
一つの方法としては、次のことが考えられます。
起動時に、
event
で見つかったすべてのファイルをループします/dev/input/
。ioctl()
イベント ビットを要求するために使用します。ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), &evbit);
次に、
EV_KEY
-bit が設定されているかどうかを確認します。IFF を設定してからキーをチェックします。
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), &keybit);
たとえば、数字キーが興味深い場合は、
KEY_0
-KEY9
およびKEY_KP0
toのビットがあるかどうかを確認しますKEY_KP9
。IFF キーが見つかったら、スレッド内のイベント ファイルの監視を開始します。
1に戻ります。
この方法では、必要な基準を満たすすべてのデバイスを監視できます。EV_KEY
たとえば、電源ボタンにはこのビットが設定されていますが、明らかに、KEY_A
その他は設定されていないため、確認することはできません。
珍しいキーの誤検出は見たことがあるが、通常のキーこれで十分でしょう。たとえば、電源ボタンやジャックのイベント ファイルを監視することで直接的な害はありませんが、問題のイベント (つまり、不良コード) は発生しません。
詳細は下記をご覧ください。
編集1:
に関してで「最後の文を説明してください…」. 行くスタックオーバーフローここに着陸します…しかし:
C で書かれた簡単なサンプルです。実際に正しいデバイスを取得し、イベント タイプ、コード、値を変換することを確認するために、さまざまなコードを実装する必要があります。通常は、キーダウン、キーアップ、キーリピート、キーコードなどです。
残りを追加するには時間がありません (そしてここでは多すぎます)。
linux/input.h
マッピングコードについては、、などのプログラムdumpkeys
、カーネルコードなどを参照してください。例:dumpkeys -l
とにかく:
次のように実行します:
# ./testprog /dev/input/event2
コード:
#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;
}
編集2(続き):
ご覧のとおり、/proc/bus/input/devices
各行の先頭に文字があります。ここではB
ビットマップを意味します。たとえば次のようになります。
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
これらの各ビットはデバイスのプロパティに対応します。ビットマップでは、1 は で定義されているプロパティが存在することを示します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
カーネルソースツリーを見てください/drivers/input/input.{h,c}
。そこには良いコードがたくさんあります。(例えば、デバイスのプロパティはこの機能。
これらの各プロパティ マップは、 によって取得できますioctl
。たとえば、使用可能な LED プロパティを確認する場合は、次のようにします。
ioctl(fd, EVIOCGBIT(EV_LED, sizeof(ledbit)), &ledbit);
どのように定義されているかについては、 struct input_dev
inの定義を参照してください。input.h
ledbit
LED のステータスを確認するには、次のように言います。
ioctl(fd, EVIOCGLED(sizeof(ledbit)), &ledbit);
ビット 1 がledbit
1 の場合、Num Lock が点灯します。ビット 2 が 1 の場合、Caps Lock が点灯します。
input.h
さまざまな定義があります。
イベント監視に関する注意事項:
監視用の疑似コードは次のようなものになります。
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
関連文書:
Documentation/input/input.txt
特にセクション 5 に注意してください。Documentation/input/event-codes.txt
EV_SYN
、様々なイベントの説明など。例えば、以下に記載されている内容に注意してください。SYN_DROPPED
Documentation/input
... 残りは必要に応じて読んでください。
答え2
を参照することで、これを簡単に行うことができます/dev/input/by-id/usb-manufacturername_*serialnumber*
。これらは、readlink -e
関連するブロック デバイスを決定するために使用して逆参照できるシンボリック リンクとして表示されます。ただし、これらのリンクは によって作成されるudev
ため、組み込み環境に存在しない可能性があります。
または、dmesg
USB デバイスを接続した後で を見てください。/dev
ノードが表示されるはずです。