How can I translate Linux keycodes from /dev/input/event* to ASCII in Perl?

后端 未结 4 663
梦谈多话
梦谈多话 2020-12-15 14:06

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

相关标签:
4条回答
  • 2020-12-15 14:14

    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
    
    0 讨论(0)
  • 2020-12-15 14:29

    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. :)

    0 讨论(0)
  • 2020-12-15 14:32

    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.

    0 讨论(0)
  • 2020-12-15 14:36

    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
    
    0 讨论(0)
提交回复
热议问题