Bir daemon (yani arka plan) işleminin bir USB klavyeden tuşa basarak arama yapması mümkün müdür?


13

Ben önyükleme otomatik olarak çalışacak ve bir karakter ekranı ve düğme dizisi bir çeşit aracılığıyla kullanıcı ile etkileşimde olacak bir program geliştiriyor olacak gömülü bir Linux projesi üzerinde çalışıyorum. Basit bir GPIO düğme dizisi ile gidersek, bu GPIO hatlarında tuşlara basılacak programı kolayca yazabilirim. Ancak, düşüncelerimizden biri kullanıcı girişi yerine bir USB sayısal tuş takımı kullanmaktı. Anladığım kadarıyla, bu cihazlar kendilerini bir USB klavye olarak işletim sistemine sunacaklar. Bu yoldan aşağı inerseniz, programımın bu USB klavyede Linux içinden giriş aramasının bir yolu var mı, sanal terminal veya VGA ekran olmadığını unutmayın. Bir USB klavye takıldığında, '/ dev' dosyasında dosya tanımlayıcısını açabileceğim görünen bir varlık var mı?

Yanıtlar:


24

Cihazlar büyük olasılıkla /dev/input/adlandırılmış bir dosya alır, eventNburada N fare, klavye, jak, güç düğmeleri vb.

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

size bir ipucu vermeli.

Ayrıca bakınız:

cat /proc/bus/input/devices

Nerede Sysfsdeğer yolu altındadır /sys.

Örneğin ile test edebilirsiniz

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

Uygulamak için ioctl kullanın ve cihazları + monitörü kontrol edin.

DÜZENLEME 2:

TAMAM. /dev/input/eventNKullanılan cevaba dayanarak bu cevabı genişletiyorum .

Bunun bir yolu olabilir:

  1. Başlangıç ​​döngüsünde bulunan tüm eventdosyalar /dev/input/. ioctl()Etkinlik bitleri istemek için kullanın :

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

    sonra EV_KEY-bit'in ayarlanıp ayarlanmadığını kontrol edin .

  2. IFF ayarlandıktan sonra anahtarları kontrol edin:

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

    Örneğin sayı tuşları ilginçse, bitlerin KEY_0- KEY9ve KEY_KP0için olup olmadığını kontrol edin KEY_KP9.

  3. Daha sonra bulunan IFF anahtarları olay dosyasını iş parçacığında izlemeye başlar.

  4. 1'e geri dön.

Bu şekilde, istenen kriterleri karşılayan tüm cihazları izlemelisiniz. Sadece EV_KEYgüç düğmesi bu biti ayarlayacağından kontrol edemezsiniz , ama açıkçası KEY_Avb.

Egzotik anahtarlar için yanlış pozitifler gördünüz, ancak normal anahtarlar için bu yeterli olmalıdır. İzlemede doğrudan bir zarar yoktur, örneğin güç düğmesi veya jak için olay dosyası, ancak söz konusu olayları (yani kötü kod) yaymazsınız.

Aşağıda daha ayrıntılı olarak.


DÜZENLEME 1:

Gelince "o son açıklama açıklayın ..." . Stackoverflow diyarında buraya gidiyoruz … ama:

C'de hızlı ve kirli bir örnek. Doğru cihazı aldığınızdan, olay türünü, kodu ve değeri çevirdiğinizden emin olmak için çeşitli kodlar uygulamanız gerekir. Genellikle tuş açma, tuş açma, tuş tekrarı, anahtar kodu vb.

Gerisini eklemek için zamanınız yok (ve burada çok fazla).

Check out linux/input.hprogramları gibi, dumpkeysharitalama kodları için vb çekirdek kodlarını. Örneğindumpkeys -l

Her neyse:

Örnek olarak çalıştırın:

# ./testprog /dev/input/event2

Kod:

#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;
}

DÜZENLEME 2 (devam):

Eğer bakarsanız, /proc/bus/input/devicesher satırın başında bir harf olduğunu unutmayın . İşte Bbit haritası. Örneğin:

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

Bu bitlerin her biri cihazın bir özelliğine karşılık gelir. Hangi bit eşleme aracıyla, 1, tanımlandığı gibi bir özelliğin mevcut olduğunu gösterir 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}Çekirdek kaynak ağacına bir göz atın . Orada çok iyi kod. (Örneğin, cihaz özellikleri bu işlev tarafından üretilir .)

Bu mülk haritalarının her birine tarafından ulaşılabilir ioctl. Örneğin, hangi LED özelliklerinin kullanılabilir olduğunu kontrol etmek istiyorsanız şunları söyleyin:

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

Nasıl tanımlandığına ilişkin olarak struct input_devin tanımına bakın .input.hledbit

LED'lerin durumunu kontrol etmek için şunları söyleyin:

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

Bit 1 girişi 1 ise ledbitnum-lock yanar. Bit 2 1 ise büyük harf kilidi yanar vb.

input.h çeşitli tanımları vardır.


Etkinlik izleme söz konusu olduğunda notlar:

İzleme için sözde kod şu yönde bir şey olabilir:

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

İlgili bazı belgeler:

  1. Documentation/input/input.txt, esp. not bölüm 5.
  2. Documentation/input/event-codes.txtÇeşitli olayların açıklaması vb örn altındaki açıklamalara göre dikkate alın EV_SYNhakkındaSYN_DROPPED
  3. Documentation/input ... isterseniz diğerlerini okuyun.

2

Bunu referans alarak kolayca yapabilirsiniz /dev/input/by-id/usb-manufacturername_*serialnumber*. Bunlar readlink -e, ilişkili blok aygıtını belirlemek için kullanmaktan vazgeçebileceğiniz sembolik bağlantılar olarak görünür . Ancak bu bağlantılar, udevyerleşik ortamınızda bulunmayabilecek şekilde oluşturulur .

Veya .. dmesgUSB aygıtını bağladıktan sonra bakın . Size /devdüğümü vermelidir .


1
İçindeki girişler imho /dev/disk/by-id/tarafından oluşturulur udev- soru bu parçalı durumda (gömülü platform) kullanılabilir olup olmadığıdır.
peterph

@peterph: Haklısın. Udev kullanılmazsa ilk öneri çalışmaz.
Jeight

@Gilles: Cevabı düzenlediğinizi ve disk yerine giriş yolunu değiştirdiğinizi görüyorum. Bu durumda girdi / by-path olacağını düşünüyorum, disk / by-id değil. İkisinin de işe yarayacağından şüpheleniyorum.
Jeight

1
Hayır, by-iddoğru. Örneğin benim USB klavye olarak mevcuttur /dev/input/by-id/usb-_USB_Keyboard-event-kbdve /dev/input/by-path/pci-0000:00:1d.2-usb-0:2:1.0-event-kbd.
Gilles 'SO- kötü olmayı kes

@Jeight: Doğru aygıt düğümünü bulduğumda, tuşlara nasıl erişebileceğimi biliyor musunuz?
KyleL
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.