Apakah mungkin untuk proses daemon (yaitu latar belakang) untuk mencari penekanan tombol dari keyboard USB?

13

Saya sedang mengerjakan proyek Linux tertanam di mana saya akan mengembangkan sebuah program yang akan berjalan secara otomatis saat bootup dan berinteraksi dengan pengguna melalui tampilan karakter dan semacam tombol array. Jika kita menggunakan array tombol GPIO sederhana, saya dapat dengan mudah menulis program yang akan mencari penekanan tombol pada baris GPIO tersebut. Namun, salah satu pemikiran kami adalah menggunakan perangkat pad nomor USB sebagai gantinya untuk input pengguna. Pemahaman saya adalah bahwa perangkat-perangkat itu akan hadir sendiri ke OS sebagai keyboard USB. Jika melalui jalur ini, apakah ada cara bagi program saya untuk mencari input pada keyboard USB ini dari dalam Linux, mengingat bahwa tidak ada terminal virtual atau tampilan VGA. Ketika keyboard USB dicolokkan, apakah ada entitas di '/ dev' yang muncul sehingga saya dapat membuka deskriptor file?

KyleL
sumber

Jawaban:

24

Perangkat yang paling mungkin mendapatkan file dengan /dev/input/nama eventNN adalah berbagai perangkat seperti mouse, keyboard, jack, tombol daya dll.

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

harus memberi Anda petunjuk.

Lihat juga:

cat /proc/bus/input/devices

Di mana Sysfsnilai berada di bawah jalur /sys.

Anda dapat menguji dengan misalnya

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

Untuk menerapkan gunakan ioctl dan periksa perangkat + monitor.

EDIT 2:

BAIK. Saya memperluas jawaban ini berdasarkan asumsi /dev/input/eventNyang digunakan.

Salah satu caranya adalah:

  1. Pada loop startup semua eventfile ditemukan di /dev/input/. Gunakan ioctl()untuk meminta bit acara:

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

    kemudian periksa apakah EV_KEY-bit diatur.

  2. Set IFF lalu periksa kunci:

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

    Misalnya jika tombol angka menarik, lalu periksa apakah bit untuk KEY_0- KEY9dan KEY_KP0untuk KEY_KP9.

  3. Kunci IFF ditemukan kemudian mulai memantau file acara di utas.

  4. Kembali ke 1.

Dengan cara ini Anda harus memantau semua perangkat yang memenuhi kriteria yang diinginkan. Anda tidak bisa hanya memeriksa karena EV_KEYmisalnya tombol daya akan mengatur bit ini, tetapi jelas tidak akan KEY_Amengatur dll.

Telah melihat positif palsu untuk kunci eksotis, tetapi untuk kunci normal ini sudah cukup. Tidak ada kerusakan langsung dalam pemantauan misalnya file acara untuk tombol daya atau jack, tetapi Anda yang tidak akan memancarkan acara yang dipertanyakan (alias. Kode buruk).

Lebih detail di bawah ini.


EDIT 1:

Sehubungan dengan "Jelaskan pernyataan terakhir itu ..." . Pergi ke tanah stackoverflow di sini ... tapi:

Sampel cepat dan kotor di C. Anda harus menerapkan berbagai kode untuk memastikan bahwa Anda benar-benar mendapatkan perangkat yang benar, menerjemahkan jenis acara, kode, dan nilai. Biasanya key-down, key-up, key-repeat, key-code, dll.

Belum waktunya, (dan terlalu banyak di sini), untuk menambahkan sisanya.

Lihat linux/input.h, program-program seperti dumpkeys, kode kernel dll. Untuk memetakan kode. Misalnyadumpkeys -l

Bagaimanapun:

Jalankan sebagai contoh:

# ./testprog /dev/input/event2

Kode:

#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 (lanjutan):

Perhatikan bahwa jika Anda melihat /proc/bus/input/devicesAnda memiliki surat di awal setiap baris. Di sini Bberarti bit-map. Itu misalnya:

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

Masing-masing bit sesuai dengan properti perangkat. Yang dengan bit-map artinya, 1 mengindikasikan sebuah properti hadir, sebagaimana didefinisikan dalam 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

Lihat di /drivers/input/input.{h,c}pohon kode sumber kernel. Banyak kode bagus di sana. (Misalnya, properti perangkat dihasilkan oleh fungsi ini .)

Masing-masing peta properti ini dapat diperoleh dengan ioctl. Misalnya, jika Anda ingin memeriksa properti LED apa yang tersedia, katakan:

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

Lihatlah definisi struct input_devin input.huntuk bagaimana ledbitdidefinisikan.

Untuk memeriksa status LED katakan:

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

Jika bit 1 in ledbitadalah 1 maka num-lock menyala. Jika bit 2 adalah 1 maka caps lock menyala dll.

input.h memiliki berbagai definisi.


Catatan tentang pemantauan acara:

Kode semu untuk pemantauan bisa menjadi sesuatu yang mengarah ke:

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

Beberapa dokumen terkait:

  1. Documentation/input/input.txt, esp. perhatikan bagian 5.
  2. Documentation/input/event-codes.txt, deskripsi berbagai peristiwa, dll. Perhatikan apa yang disebutkan di bawah misalnya EV_SYNtentangSYN_DROPPED
  3. Documentation/input ... baca sisanya jika Anda mau.
Runium
sumber
2

Anda dapat melakukan ini dengan mudah dengan referensi /dev/input/by-id/usb-manufacturername_*serialnumber*. Ini muncul sebagai tautan simbolis yang dapat Anda gunakan readlink -euntuk menentukan perangkat blok terkait. Namun tautan-tautan ini dibuat oleh udevyang mungkin tidak ada di lingkungan tertanam Anda.

Atau .. Lihat dmesgsetelah menghubungkan perangkat USB. Seharusnya memberi Anda /devsimpul.

Jeight
sumber
1
Entri /dev/disk/by-id/yang dibuat oleh udev- pertanyaan adalah apakah ini tersedia dalam kasus partikel ini (platform tertanam).
peterph
@peterph: Anda benar. Jika tidak menggunakan udev saran pertama tidak akan berfungsi.
Jeight
@Gilles: Saya melihat Anda mengedit jawabannya dan mengubah path ke input daripada disk. Dalam hal ini saya percaya itu akan menjadi input / by-path dan bukan disk / by-id. Saya kira keduanya akan berhasil.
Jeight
1
Tidak by-idbenar Misalnya keyboard USB saya tersedia sebagai /dev/input/by-id/usb-_USB_Keyboard-event-kbddan /dev/input/by-path/pci-0000:00:1d.2-usb-0:2:1.0-event-kbd.
Gilles 'SANGAT berhenti menjadi jahat'
@Jeight: Setelah saya menemukan simpul perangkat yang benar, apakah Anda tahu bagaimana saya bisa mengakses penekanan tombol?
KyleL