저는 부팅 시 자동으로 실행되고 문자 디스플레이와 일종의 버튼 배열을 통해 사용자와 상호 작용하는 프로그램을 개발할 임베디드 Linux 프로젝트를 진행하고 있습니다. 간단한 GPIO 버튼 배열을 사용하면 이러한 GPIO 라인에서 버튼을 찾는 프로그램을 쉽게 작성할 수 있습니다. 그러나 우리의 아이디어 중 하나는 USB 숫자 키패드 장치를 사용하여 사용자 입력을 대체하는 것입니다. 제가 이해한 바에 따르면 이러한 장치는 운영 체제에 USB 키보드로 표시됩니다. 이런 식으로 진행되는 경우 가상 터미널이나 VGA 모니터가 없다는 점을 염두에 두고 내 프로그램이 Linux의 이 USB 키보드에서 입력을 찾을 수 있는 방법이 있습니까? USB 키보드가 연결되면 '/dev'에 파일 설명자를 열 수 있는 엔터티가 있습니까?
답변1
/dev/input/
장치에는 이라는 파일이 있을 가능성이 높습니다 eventN
. 여기서 N은 마우스, 키보드, 잭, 전원 버튼 등과 같은 다양한 장치입니다.
ls -l /dev/input/by-{path,id}/
힌트를 주어야합니다.
또한보십시오:
cat /proc/bus/input/devices
여기서 Sysfs
value는 아래의 경로입니다 /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);
그런 다음 -bit가 설정되어 있는지 확인하십시오
EV_KEY
.그런 다음 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이면 숫자 잠금 표시등이 켜집니다. 비트 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
노드를 제공해야 합니다 .