Linux 입력 장치에서 키 액세스
내가 하려는 일
그래서 저는 리눅스에서 키보드 입력에 접근하려고 노력해왔습니다.특히 다른 키를 누르지 않고 수식어 키 누르기에 액세스할 수 있어야 합니다.또한 X 시스템을 실행하지 않고도 이 작업을 수행할 수 있기를 원합니다.
간단히 말해서, 제 요구 사항은 다음과 같습니다.
- Linux에서 작동합니다.
- X11이 필요하지 않음
- 다른 키를 누르지 않고 수식자 키 누르기를 검색할 수 있습니다.
- 여기에는 다음 키가 포함됩니다.
- 시프트
- 통제
- 알트
- 간한것있됩니다면으만단▁a됩▁i다니▁all▁simple▁is▁need면만 있으면 됩니다.
0 = not pressed
,1 = currently pressed
키보드를 선택했을 때 키가 눌려 있는지 여부를 알려주는 것
- 여기에는 다음 키가 포함됩니다.
내 컴퓨터 설정
제 일반적인 리눅스 기계는 트럭에 실려 새 아파트로 향합니다. 그래서 지금은 맥북 에어만 가지고 있습니다.따라서 이를 테스트하기 위해 VM에서 Linux를 실행하고 있습니다.
VirtualBox의 가상 시스템
- OS: 리눅스 민트 16
- 데스크톱 환경: XFCE
아래의 모든 작업은 이 환경에서 수행되었습니다.저는 X가 달리는 것과 다른 타이 중 하나에서 둘 다 시도했습니다.
나의 생각
누군가 나를 고쳐줄 수 있다면 나는 이것을 바꿀 것입니다.
저는 높은 수준의 도서관이 이런 기능을 제공하지 않는다는 것을 깨닫기 위해 상당한 독서를 했습니다.수정자 키는 대체 키 코드를 제공하기 위해 다른 키와 함께 사용됩니다.리눅스에서 고급 라이브러리를 통해 수식어 키 자체에 액세스하는 것은 쉽지 않습니다.또는 리눅스에서 이에 대한 고급 API를 찾지 못했습니다.
저는 libtermkey가 정답일 줄 알았는데 Shift 수정자 키를 일반 키 입력 검색보다 더 잘 지원하지 않는 것 같습니다.X 없이도 작동하는지도 잘 모르겠습니다.
libtermkey로 작업하는 동안(Shift-Return과 같은 경우에는 변경되지 않는다는 것을 깨닫기 전에) 키보드 이벤트를 수집하기 위해 실행되는 데몬을 작성할 계획이었습니다.데몬 프로그램의 복사본을 실행하면 키보드 데이터에 대한 요청을 파이프로 처리하고 응답으로 키보드 데이터를 수신할 수 있습니다.특정 시간에 키 코드 상태를 확인할 수 없는 경우(키 코드를 수신해야 할 경우) 이 설정을 사용하여 항상 백그라운드에서 실행할 수 있습니다.
다음은 Linux 키보드 장치에서 읽을 수 있는 프로그램을 작성하기 위한 두 가지 시도입니다.올바른 장치가 있는지 확인하기 위해 소액 수표도 동봉했습니다.
시도 #1
키보드 장치에 직접 액세스하려고 했지만 문제가 발생했습니다.다른 스택 오버플로 스레드에 있는 제안을 시도해 보았습니다.분할 오류가 발생했기 때문에 열림에서 열림으로 변경했습니다.
// ...
int fd;
fd = open("/dev/input/by-path/platform-i8042-serio-0-event-kbd", O_RDONLY);
char key_map[KEY_MAX/8 + 1];
memset(key_map, 0, sizeof(key_map));
ioctl(fd, EVIOCGKEY(sizeof key_map), key_map);
// ...
분할 오류가 없는 동안에는 키 누름 표시기(수정자 키뿐만 아니라)가 없었습니다.다음을 사용하여 테스트했습니다.
./foo && echo "TRUE" || echo "FALSE"
명령어의 성공적인 반환 코드를 테스트하기 위해 이 기능을 사용한 적이 꽤 많았기 때문에 문제가 없다는 것을 알고 있습니다.확인할 키(항상 0)와 마스크(0100)도 출력했습니다.아무것도 감지하지 못하는 것 같습니다.
시도 #2
여기서부터, 저는 약간 다른 접근법을 시도해 보겠다고 생각했습니다.저는 제가 무엇을 잘못하고 있는지 알고 싶었습니다.이 페이지에서 키 코드를 출력하는 것을 보여주는 스니펫을 제공한 후 프로그램에 포함시켰습니다.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <linux/input.h>
int main(int argc, char** argv) {
uint8_t keys[128];
int fd;
fd = open("/dev/input/by-path/platform-i8042-serio-event-kbd", O_RDONLY);
for (;;) {
memset(keys, 0, 128);
ioctl (fd, EVIOCGKEY(sizeof keys), keys);
int i, j;
for (i = 0; i < sizeof keys; i++)
for (j = 0; j < 8; j++)
if (keys[i] & (1 << j))
printf ("key code %d\n", (i*8) + j);
}
return 0;
}
이전에는 128바이트가 아닌 16바이트로 크기를 잡았습니다.솔직히 ioctl과 EVIOCKEY를 이해하는 데 조금 더 많은 시간을 보내야겠습니다.저는 단지 그것이 특정 키에 비트를 매핑하여 프레스 또는 그와 유사한 것을 표시한다는 것을 알고 있습니다(제가 틀렸다면 수정해주세요!).
또한 처음에는 루프가 없었고 키 코드가 나타나는지 확인하기 위해 다양한 키를 누르곤 했습니다.저는 아무것도 받지 못했습니다. 그래서, 루프를 통해 무언가를 놓친 경우 검사를 더 쉽게 테스트할 수 있을 것이라고 생각했습니다.
입력 장치가 올바른 장치인지 확인하는 방법
나는 그것을 실행함으로써 테스트했습니다.cat
입력 장치에 있습니다.구체적으로:
$ sudo cat /dev/input/by-path/platform-i8042-serio-0-event-kbd
Cat을 사용하여 출력을 시작했을 때 반환(입력) 키로 시작하는 키 누르기 및 릴리스 이벤트에서 가비지 ASCII가 내 단말기로 전송되었습니다.Linux VM을 실행하는 Macbook에서 Shift, Control, Function 및 Apple의 명령 키와 같은 수식어 키에서도 이 작업이 잘 작동하는 것으로 보입니다.키를 누를 때 출력이 나타나고, 키를 누른 상태에서 전송되는 후속 신호에서 빠르게 나타나기 시작했으며, 키를 놓으면 더 많은 데이터가 출력됩니다.
따라서 제 접근 방식이 올바른 접근 방식이 아닐 수도 있지만(어떤 대안이든 기꺼이 듣겠습니다), 이 장치는 제가 필요로 하는 것을 제공하는 것 같습니다.
또한 이 장치는 실행 중인 /dev/input/event2를 가리키는 링크일 뿐입니다.
$ ls -l /dev/input/by-path/platform-i8042-serio-0-event-kbd
위의 두 프로그램 모두 /dev/input/event2로 시도해 보았지만 데이터를 받지 못했습니다./dev/input/event2에서 실행 중인 cat은 링크와 동일한 출력을 제공했습니다.
입력 장치를 엽니다.
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <string.h>
#include <stdio.h>
static const char *const evval[3] = {
"RELEASED",
"PRESSED ",
"REPEATED"
};
int main(void)
{
const char *dev = "/dev/input/by-path/platform-i8042-serio-0-event-kbd";
struct input_event ev;
ssize_t n;
int fd;
fd = open(dev, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Cannot open %s: %s.\n", dev, strerror(errno));
return EXIT_FAILURE;
}
장치에서 키보드 이벤트를 읽습니다.
while (1) {
n = read(fd, &ev, sizeof ev);
if (n == (ssize_t)-1) {
if (errno == EINTR)
continue;
else
break;
} else
if (n != sizeof ev) {
errno = EIO;
break;
}
위의 스니펫은 오류가 발생하거나 사용자 공간이 부분적인 이벤트 구조만 수신하는 경우 루프에서 발생합니다(이는 발생하지 않아야 하지만 일부 미래/버기 커널에서는 발생할 수 있음).).보다 강력한 읽기 루프를 사용하는 것이 좋습니다. 저는 개인적으로 마지막 루프를 교체하는 것이 만족스럽습니다.break
와 함께continue
부분 이벤트 구조가 무시되도록 합니다.
그런 다음 검사할 수 있습니다.ev
이벤트 구조를 사용하여 발생한 내용을 확인하고 프로그램을 종료합니다.
if (ev.type == EV_KEY && ev.value >= 0 && ev.value <= 2)
printf("%s 0x%04x (%d)\n", evval[ev.value], (int)ev.code, (int)ev.code);
}
fflush(stdout);
fprintf(stderr, "%s.\n", strerror(errno));
return EXIT_FAILURE;
}
키 프레스를 위해,
ev.time
이벤트 시간(struct timeval
type)ev.type
:EV_KEY
ev.code
:KEY_*
키 식별자; 의 전체 목록 참조/usr/include/linux/input.h
ev.value
:0
키가 해제된 경우1
키를 누르면,2
키를 자동으로 반복하는 경우
설명서/입력/입력을 참조하십시오.자세한 내용은 Linux 커널 소스에서 txt를 참조하십시오.
의 명명된 상수/usr/include/linux/input.h
커널 사용자 공간 인터페이스이기 때문에 매우 안정적이며 커널 개발자들은 호환성을 유지하기 위해 매우 노력합니다.(즉, 때때로 새로운 코드가 있을 것으로 예상할 수 있지만 기존 코드는 거의 변경되지 않습니다.)
언급URL : https://stackoverflow.com/questions/20943322/accessing-keys-from-linux-input-device
'itsource' 카테고리의 다른 글
각도 캐스트 선택 값을 int로 (0) | 2023.07.26 |
---|---|
시스템 호출 대 함수 호출 (0) | 2023.07.26 |
MS가 파워셸을 만들어 해결한 문제는? (0) | 2023.07.26 |
고온 및 저온 관측 가능: '열온' 및 '냉온' 연산자가 있습니까? (0) | 2023.07.26 |
장고에서 OR 쿼리 필터를 동적으로 구성하는 방법은 무엇입니까? (0) | 2023.07.21 |