How can I translate Linux keycodes from /dev/input/event* to ASCII in Perl?
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.
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?
I'd like to skip the array part because it doesn't seem to be a good practice, so an开发者_如何学运维y idea? :)
Unfortunately, I don't program in Perl but here is a simple example written in C. Perhaps it might help you nevertheless.
/*
* 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
:
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
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?
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. :)
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.
To read the barcodes from a barcode reader I missed a simple application to get the pure key strokes into a string. That's by far easier to do a complete keyboard translation as the barcodes usually contain mostly numbers and some few normal ascii characters.
So, perhaps, this simple python3 script may help as well others to get started. It requires python3-evdev
as library.
For sure, you may have to adapt the InputDevice
. This works for the Manhatten reader.
from evdev import InputDevice, categorize, ecodes
dev = InputDevice('/dev/input/by-id/usb-040b_6543-if01-event-kbd')
print(dev)
shiftPressed = False
ctrlPressed = False
string = ""
for event in dev.read_loop():
if event.type == ecodes.EV_KEY:
keyEvent = categorize(event)
# handle release of special keys
if keyEvent.keystate == 0:
if keyEvent.keycode=="KEY_LEFTSHIFT":
shiftPressed = False
continue
if keyEvent.keycode=="KEY_LEFTCTRL":
ctrlPressed = False
continue
# handle key presses
if keyEvent.keystate == 1:
if keyEvent.keycode=="KEY_LEFTSHIFT":
shiftPressed = True
continue
if keyEvent.keycode=="KEY_LEFTCTRL":
ctrlPressed = True
continue
if ctrlPressed:
continue
key = keyEvent.keycode[4:]
if key == "ENTER":
print(string)
string = ""
continue
dict2 = {"Z" : "Y", "Y": "Z"}
if key in dict2:
key = dict2[key]
if not (shiftPressed):
key = key.lower()
else:
dict = {"0" : "=",
"1" : "!",
"2" : "\"",
"3" : "§",
"4" : "$",
"5" : "%",
"6" : "&",
"7" : "/",
"8" : "(",
"9" : ")"}
if key in dict:
key = dict[key]
string+=key
精彩评论