如何在 Perl 中将 Linux 键码从 /dev/input/event* 转换为 ASCII?

发布于 2024-08-27 20:40:04 字数 314 浏览 9 评论 0原文

我正在编写一个 Perl 脚本,该脚本从臭名昭著的 /dev/input/event* 读取数据,但我没有找到一种方法将内核生成的关键代码转换为 ASCII。

我在这里谈论这个表中的linux关键代码似乎无法找到可以帮助我翻译它们而不将数组硬编码到脚本中的东西。我错过了什么吗?

我想跳过数组部分,因为这似乎不是一个好的做法,所以有什么想法吗? :)

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 any idea? :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

盛夏已如深秋| 2024-09-03 20:40:04

不幸的是,我不会用 Perl 编程,但这里有一个用 C 编写的简单示例。也许它仍然可以对您有所帮助。

/*
 * 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;
}

要生成 parse.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

然后,像这样使用它:

./keytable /dev/input/by-path/platform-i8042-serio-0-event-kbd

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
花间憩 2024-09-03 20:40:04

基本上是地图问题。您必须获取一个键码并查找其等效的 ASCII 码。您认为“数组部分”不是一个好的做法吗?

我在 CPAN 上没有看到此模块,但这意味着您有机会成为第一个上传它的人。 :)

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

梦途 2024-09-03 20:40:04

示例 1 仅返回来自 Linux 内核的相同密钥代码值。例如,按下“a”键时会得到 KEY_A 0x1e。你想要的是(也是我想要的)ascii 转换,所以如果按下“a”,我想看到小写字母 0x61 和大写字母 0x41。

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.

旧话新听 2024-09-03 20:40:04

为了从条形码阅读器读取条形码,我错过了一个将纯按键输入字符串的简单应用程序。到目前为止,进行完整的键盘翻译要容易得多,因为条形码通常主要包含数字和一些正常的 ASCII 字符。
因此,也许这个简单的 python3 脚本也可以帮助其他人入门。它需要 python3-evdev 作为库。
当然,您可能必须调整 InputDevice。这适用于曼哈顿读者。

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

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" : "
quot;,
                        "5" : "%",
                        "6" : "&",
                        "7" : "/",
                        "8" : "(",
                        "9" : ")"}
                if key in dict:
                    key = dict[key]
            string+=key
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文