デーモン(つまりバックグラウンド)プロセスはUSBキーボードでキーストロークを見つけることができますか?

デーモン(つまりバックグラウンド)プロセスはUSBキーボードでキーストロークを見つけることができますか?

私は起動時に自動的に実行され、文字表示と一種のボタン配列を介してユーザーと対話するプログラムを開発する組み込みLinuxプロジェクトを進めています。単純なGPIOボタン配列を使用すると、これらのGPIOライン上のボタンを見つけるプログラムを簡単に作成できます。しかし、私たちのアイデアの1つは、USBナンバーキーパッドデバイスを使用してユーザー入力を置き換えることです。私が理解したように、これらのデバイスはオペレーティングシステムにUSBキーボードとして表示されます。このように進んでいる場合は、仮想端末やVGAモニタがないことを念頭に置いて、私のプログラムがLinuxのこのUSBキーボードで入力を見つける方法はありますか? USBキーボードが接続されたら、「/dev」にファイル記述子を開くことができるエンティティはありますか?

ベストアンサー1

/dev/input/デバイスにというファイルがある可能性が高いですeventN。ここで、Nはマウス、キーボード、ジャック、電源ボタンなどのさまざまなデバイスです。

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

ヒントを与える必要があります。

また見なさい:

cat /proc/bus/input/devices

ここでSysfsvalue は以下のパスです/sys

たとえば、これをテストできます。

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

ioctlを使用するには、デバイス+モニターを確認してください。

編集2:

わかりました、私は/dev/input/eventN使用された仮定に基づいてこの答えを拡張します。

1つのアプローチは次のとおりです。

  1. 起動時にevent見つかったすべてのファイルを繰り返します/dev/input/ioctl()イベントビットを要求するために使用されます。

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

    次に、-bitが設定されていることを確認してくださいEV_KEY

  2. その後、IFF設定はキーを確認します。

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

    たとえば、数字キーが面白い場合はKEY_0-KEY9KEY_KP0to ビットがあることを確認してくださいKEY_KP9

  3. IFFキーを見つけて、スレッドでイベントファイルの監視を開始します。

  4. 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_devinの定義を参照してください。input.hledbit

LEDの状態を確認するには:

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

ビット 1 がledbit1 の場合、数値ロックインジケータが点灯します。ビット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

いくつかの関連文書:

  1. Documentation/input/input.txt、特に。セクション5を参照してください。
  2. Documentation/input/event-codes.txt、各種イベントの説明など下記のEV_SYN内容を参考にしてください。SYN_DROPPED
  3. Documentation/input...ご希望の場合は、残りの部分もお読みください。

おすすめ記事