데몬(즉, 백그라운드) 프로세스가 USB 키보드에서 키 누르기를 찾는 것이 가능합니까?

데몬(즉, 백그라운드) 프로세스가 USB 키보드에서 키 누르기를 찾는 것이 가능합니까?

저는 부팅 시 자동으로 실행되고 문자 디스플레이와 일종의 버튼 배열을 통해 사용자와 상호 작용하는 프로그램을 개발할 임베디드 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:

좋아요. 나는 /dev/input/eventN사용된다는 가정을 바탕으로 이 답변을 확장하고 있습니다.

한 가지 방법은 다음과 같습니다.

  1. 시작 루프 event에서 /dev/input/. ioctl()이벤트 비트를 요청하는 데 사용합니다 .

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

    그런 다음 EV_KEY-bit가 설정되어 있는지 확인하십시오.

  2. IFF를 설정한 후 키를 확인합니다.

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

    예를 들어 숫자 키가 흥미로운 경우 KEY_0- KEY9KEY_KP0to 에 대한 비트가 있는지 확인하십시오 KEY_KP9.

  3. IFF 키가 발견되면 스레드에서 이벤트 파일 모니터링을 시작합니다.

  4. 1로 돌아갑니다.

이렇게 하면 원하는 기준을 충족하는 모든 장치를 모니터링할 수 있습니다. EV_KEY예를 들어 전원 버튼에 이 비트가 설정되어 있는지 확인할 수는 없지만 분명히 KEY_A설정되어 있지는 않습니다.

이국적인 키에 대한 오탐(false positive)이 확인되었지만일반 키이것으로 충분합니다. 전원 버튼이나 잭에 대한 이벤트 파일 등을 모니터링하는 데 직접적인 피해는 없지만 문제의 이벤트(즉, 잘못된 코드)를 내보내지는 않습니다.

아래에서 더 자세히 알아보세요.


편집 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이면 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

일부 관련 문서:

  1. Documentation/input/input.txt, 특히. 섹션 5를 참고하세요.
  2. Documentation/input/event-codes.txt, 다양한 이벤트에 대한 설명 등 아래에 언급된 내용을 기록해 두세요 EV_SYN.SYN_DROPPED
  3. Documentation/input...원한다면 나머지 내용도 읽어보세요.

답변2

를 참조하면 쉽게 할 수 있습니다 /dev/input/by-id/usb-manufacturername_*serialnumber*. 이는 readlink -e연관된 블록 장치를 결정하는 데 사용하여 역참조할 수 있는 기호 링크로 나타납니다. 그러나 이러한 링크는 udev내장된 환경에 존재하지 않을 수도 있는 생성됩니다.

dmesg아니면.. USB 장치를 연결한 후 를 보세요 . 노드 를 제공해야 합니다 /dev.

관련 정보