%20%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EA%B0%80%20USB%20%ED%82%A4%EB%B3%B4%EB%93%9C%EC%97%90%EC%84%9C%20%ED%82%A4%20%EB%88%84%EB%A5%B4%EA%B8%B0%EB%A5%BC%20%EC%B0%BE%EB%8A%94%20%EA%B2%83%EC%9D%B4%20%EA%B0%80%EB%8A%A5%ED%95%A9%EB%8B%88%EA%B9%8C%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:
좋아요. 나는 /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
설정되어 있지는 않습니다.
이국적인 키에 대한 오탐(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_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
.