Как я могу перевести ключевые коды Linux из / dev / input / event * в ASCII на Perl? - PullRequest
4 голосов
/ 30 марта 2010

Я пишу сценарий Perl, который читает данные из печально известного /dev/input/event*, и я не нашел способа перевести коды ключей, сгенерированные ядром, в ASCII.

Я говорю о кодах клавиш linux в этой таблице здесь , и я не могу найти что-то, что помогло бы мне перевести их без жесткого кодирования массива в сценарий. Я что-то пропустил?

Я бы хотел пропустить часть массива, потому что она не кажется хорошей практикой, так что, есть идеи? :)

Ответы [ 3 ]

9 голосов
/ 31 марта 2010

К сожалению, я не программирую на 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
5 голосов
/ 30 марта 2010

Это в основном проблема с картой. Вы должны взять код ключа и найти его эквивалент ASCII. Как насчет "части массива", как вы думаете, не очень хорошая практика?

Я не видел модуль для этого в CPAN, но это означает, что у вас есть шанс быть первым, кто загрузит его. :)

1 голос
/ 09 декабря 2011

Пример 1 возвращает только те же значения кода ключа, которые уже поступают из ядра Linux. Например, вы получаете KEY_A 0x1e за нажатие клавиши «а». То, что вы хотите (и то, что я хочу) - это преобразование ascii, поэтому, если нажата 'a', я хочу видеть 0x61 для нижнего регистра и 0x41 для верхнего регистра.

...