I'm writing a Perl script that reads data from the infamous /dev/input/event*
and I didn't find a way to translate the key codes generated by the kernel into ASCII.
我正在编写一个Perl脚本,它从臭名昭著的/dev/input/event*中读取数据,我没有找到将内核生成的关键代码转换为ASCII的方法。
I'm talking about the linux key codes in this table here and I can't seem to find something that would help me translate them without hardcoding an array into the script. Am I missing something?
我在这里讨论的是linux的关键代码,我似乎找不到可以帮助我翻译它们的东西,而不是把数组硬编码到脚本中。我遗漏了什么东西?
I'd like to skip the array part because it doesn't seem to be a good practice, so any idea? :)
我想跳过数组部分因为这看起来不是很好的练习,有什么想法吗?:)
3 个解决方案
#1
5
It's basically a map problem. You have to take a keycode and lookup its ASCII equivalent. What about the "array part" do you think is not a good practice?
这基本上是一个地图问题。您必须使用keycode并查找它的ASCII等效项。你认为“数组部分”不是一个好的实践吗?
I didn't see a module for this on CPAN, but that means that you have a chance to be the first to upload it. :)
我在CPAN上没有看到这个模块,但这意味着你有机会第一个上传它。:)
#2
9
Unfortunately, I don't program in Perl but here is a simple example written in C. Perhaps it might help you nevertheless.
不幸的是,我不使用Perl编程,但这里有一个简单的例子,也许它可以帮助您。
/*
* Based on keytable.c by Mauro Carvalho Chehab
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/input.h>
#include <string.h>
#include <linux/input.h>
#include <sys/ioctl.h>
#define KEY_RELEASE 0
#define KEY_PRESS 1
#define KEY_KEEPING_PRESSED 2
#include "parse.h"
void prtcode(int codes) {
struct parse_key *p;
for (p = keynames; p->name != NULL; p++) {
if (p->value == (unsigned) codes) {
printf("scancode %s (0x%02x)\n", p->name, codes);
return;
}
}
if (isprint(codes)) {
printf("scancode '%c' (0x%02x)\n", codes, codes);
} else {
printf("scancode 0x%02x\n", codes);
}
}
int main (int argc, char *argv[]) {
int i, fd;
struct input_event ev[64];
if (argc != 2) {
fprintf(stderr, "usage: %s event-device (/dev/input/eventX)\n", argv[0]);
return 1;
}
if ((fd = open(argv[1], O_RDONLY)) < 0) {
perror("Couldn't open input device");
return 1;
}
while (1) {
size_t rb = read(fd, ev, sizeof(ev));
if (rb < (int) sizeof(struct input_event)) {
perror("short read");
return 1;
}
for (i = 0; i < (int) (rb / sizeof(struct input_event)); i++) {
if (EV_KEY == ev[i].type) {
if ((ev[i].value == KEY_PRESS) || (ev[i].value == KEY_KEEPING_PRESSED)) {
prtcode(ev[i].code);
printf("type %d code %d value %d\n", ev[i].type, ev[i].code, ev[i].value);
printf("\n");
}
}
}
}
return 0;
}
For generating the parse.h, put this into your Makefile
:
生成的解析。h,把这个放进你的Makefile:
parse.h: /usr/include/linux/input.h
@echo generating parse.h
@echo -en "struct parse_key {\n\tchar *name;\n\tunsigned int value;\n} " >parse.h
@echo -en "keynames[] = {\n" >>parse.h
@more /usr/include/linux/input.h |perl -n \
-e 'if (m/^\#define\s+(KEY_[^\s]+)\s+(0x[\d\w]+|[\d]+)/) ' \
-e '{ printf "\t{\"%s\", %s},\n",$$1,$$2; }' \
-e 'if (m/^\#define\s+(BTN_[^\s]+)\s+(0x[\d\w]+|[\d]+)/) ' \
-e '{ printf "\t{\"%s\", %s},\n",$$1,$$2; }' \
>> parse.h
@echo -en "\t{ NULL, 0}\n};\n" >>parse.h
Then, use it like this:
然后,像这样使用:
./keytable /dev/input/by-path/platform-i8042-serio-0-event-kbd
#3
1
Example 1 only gives you back the same key code values that are already coming from the linux kernel. For example you get KEY_A 0x1e for an 'a' key press. What you want is (and what i want) is the ascii conversion so if 'a' is pressed I want to see 0x61 for lower case and 0x41 for upper case.
示例1只提供了与linux内核相同的键值。例如,你得到KEY_A 0x1e作为“a”键。你想要的是(我想要的)是ascii转换,所以如果按下“a”,我想看到小写的0x61,大写的0x41。
#1
5
It's basically a map problem. You have to take a keycode and lookup its ASCII equivalent. What about the "array part" do you think is not a good practice?
这基本上是一个地图问题。您必须使用keycode并查找它的ASCII等效项。你认为“数组部分”不是一个好的实践吗?
I didn't see a module for this on CPAN, but that means that you have a chance to be the first to upload it. :)
我在CPAN上没有看到这个模块,但这意味着你有机会第一个上传它。:)
#2
9
Unfortunately, I don't program in Perl but here is a simple example written in C. Perhaps it might help you nevertheless.
不幸的是,我不使用Perl编程,但这里有一个简单的例子,也许它可以帮助您。
/*
* Based on keytable.c by Mauro Carvalho Chehab
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/input.h>
#include <string.h>
#include <linux/input.h>
#include <sys/ioctl.h>
#define KEY_RELEASE 0
#define KEY_PRESS 1
#define KEY_KEEPING_PRESSED 2
#include "parse.h"
void prtcode(int codes) {
struct parse_key *p;
for (p = keynames; p->name != NULL; p++) {
if (p->value == (unsigned) codes) {
printf("scancode %s (0x%02x)\n", p->name, codes);
return;
}
}
if (isprint(codes)) {
printf("scancode '%c' (0x%02x)\n", codes, codes);
} else {
printf("scancode 0x%02x\n", codes);
}
}
int main (int argc, char *argv[]) {
int i, fd;
struct input_event ev[64];
if (argc != 2) {
fprintf(stderr, "usage: %s event-device (/dev/input/eventX)\n", argv[0]);
return 1;
}
if ((fd = open(argv[1], O_RDONLY)) < 0) {
perror("Couldn't open input device");
return 1;
}
while (1) {
size_t rb = read(fd, ev, sizeof(ev));
if (rb < (int) sizeof(struct input_event)) {
perror("short read");
return 1;
}
for (i = 0; i < (int) (rb / sizeof(struct input_event)); i++) {
if (EV_KEY == ev[i].type) {
if ((ev[i].value == KEY_PRESS) || (ev[i].value == KEY_KEEPING_PRESSED)) {
prtcode(ev[i].code);
printf("type %d code %d value %d\n", ev[i].type, ev[i].code, ev[i].value);
printf("\n");
}
}
}
}
return 0;
}
For generating the parse.h, put this into your Makefile
:
生成的解析。h,把这个放进你的Makefile:
parse.h: /usr/include/linux/input.h
@echo generating parse.h
@echo -en "struct parse_key {\n\tchar *name;\n\tunsigned int value;\n} " >parse.h
@echo -en "keynames[] = {\n" >>parse.h
@more /usr/include/linux/input.h |perl -n \
-e 'if (m/^\#define\s+(KEY_[^\s]+)\s+(0x[\d\w]+|[\d]+)/) ' \
-e '{ printf "\t{\"%s\", %s},\n",$$1,$$2; }' \
-e 'if (m/^\#define\s+(BTN_[^\s]+)\s+(0x[\d\w]+|[\d]+)/) ' \
-e '{ printf "\t{\"%s\", %s},\n",$$1,$$2; }' \
>> parse.h
@echo -en "\t{ NULL, 0}\n};\n" >>parse.h
Then, use it like this:
然后,像这样使用:
./keytable /dev/input/by-path/platform-i8042-serio-0-event-kbd
#3
1
Example 1 only gives you back the same key code values that are already coming from the linux kernel. For example you get KEY_A 0x1e for an 'a' key press. What you want is (and what i want) is the ascii conversion so if 'a' is pressed I want to see 0x61 for lower case and 0x41 for upper case.
示例1只提供了与linux内核相同的键值。例如,你得到KEY_A 0x1e作为“a”键。你想要的是(我想要的)是ascii转换,所以如果按下“a”,我想看到小写的0x61,大写的0x41。