Acceso a las teclas desde el dispositivo de entrada de Linux

Lo que estoy tratando de hacer

Entonces, he estado tratando de acceder a la entrada del teclado en Linux. Específicamente, necesito poder acceder a las pulsaciones de las teclas modificadorassin otras teclas siendo presionadas. Además, quiero poder hacer esto.sin un sistema X en ejecución.

Así que, en definitiva, mis requerimientos son estos:

Funciona en linuxNo necesita X11Puede recuperar la tecla modificadora presionandosin cualquier otra tecla presionadaEsto incluye las siguientes teclas:CambioControlarAltTodo lo que necesito es un simple0 = not pressed, 1 = currently pressed para avisarme si la tecla se mantiene presionada cuando se comprueba el tecladoConfiguración de mi computadora

Mi máquina normal de Linux está en un camión hacia mi nuevo apartamento; Entonces, solo tengo un Macbook Air para trabajar en este momento. Por lo tanto, estoy ejecutando Linux en una máquina virtual para probar esto.

Máquina Virtual en VirtualBox

SO: Linux Mint 16Entorno de escritorio: XFCE

Todo lo de abajo fue hecho en este ambiente. He intentado con X en ejecución y en uno de los otros ttys.

Mis pensamientos

Alteraré esto si alguien me puede corregir.

He leído bastante para darme cuenta de que las bibliotecas de nivel superior no proporcionan este tipo de funcionalidad. Las teclas modificadoras se utilizan con otras teclas para proporcionar un código de tecla alternativo. Acceder a las claves modificadoras a través de una biblioteca de alto nivel en Linux no es tan fácil. O, mejor dicho, no he encontrado una API de alto nivel para esto en Linux.

pensélibtermkey sería la respuesta, pero no parece admitir la tecla modificadora Shift mejor que la recuperación de pulsaciones de tecla normal. Tampoco estoy seguro de si funciona sin X.

Mientras trabajaba con libtermkey (antes de darme cuenta de que no había cambios en casos como Shift-Return), planeaba escribir un demonio que se ejecutaría para recopilar eventos de teclado. Ejecutar copias del programa daemon simplemente canalizaría las solicitudes de datos del teclado y recibiría los datos del teclado en respuesta. Podría usar esta configuración para tener algo siempre ejecutándose en segundo plano, en caso de que no pueda verificar los estados de los códigos clave en momentos específicos (se deben recibir los códigos clave a medida que ocurren).

A continuación están mis dos intentos de escribir un programa que puede leer desde el dispositivo de teclado Linux. También he incluido mi pequeño cheque para asegurarme de que tenía el dispositivo correcto.

Intento # 1

He intentado acceder al dispositivo del teclado directamente, pero tengo problemas. He intentado la sugerenciaaquí que está en otro hilo de desbordamiento de pila. Me dio una falla de segmentación; Así que, lo cambié de fopen para abrir:

// ...

int fd;
fd = open("/dev/input/by-path/platform-i8042-serio-0-event-kbd", O_RDONLY);

char key_map[KEY_MAX/8 + 1];

memset(key_map, 0, sizeof(key_map));
ioctl(fd, EVIOCGKEY(sizeof key_map), key_map);

// ...

Si bien no hubo falla de segmentación, no hubo ningún indicador de pulsación de tecla (no solo teclas modificadoras). He probado esto utilizando:

./foo && echo "TRUE" || echo "FALSE"

He usado eso para probar los códigos de retorno exitosos de los comandos bastante; Entonces, sé que está bien. También he enviado la clave (siempre 0) y la máscara (0100) para verificar. Simplemente no parece detectar nada.

Intento # 2

Desde aquí, pensé en probar un enfoque ligeramente diferente. Quería averiguar qué estaba haciendo mal. Siguiendoesta La página proporcionaba un fragmento que mostraba la impresión de códigos clave, lo incluí en un programa:

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <linux/input.h>

int main(int argc, char** argv) {
    uint8_t keys[128];
    int fd;

    fd = open("/dev/input/by-path/platform-i8042-serio-event-kbd", O_RDONLY);
    for (;;) {
        memset(keys, 0, 128);
        ioctl (fd, EVIOCGKEY(sizeof keys), keys);

        int i, j;
        for (i = 0; i < sizeof keys; i++)
            for (j = 0; j < 8; j++)
                if (keys[i] & (1 << j))
                    printf ("key code %d\n", (i*8) + j);
    }

    return 0;
}

Anteriormente, tenía el tamaño de 16 bytes en lugar de 128 bytes. Sinceramente, debería dedicar un poco más de tiempo a comprender ioctl y EVIOCGKEY. Solo sé que supuestamente asigna bits a teclas específicas para indicar prensas, o algo así (corrígeme si me equivoco, por favor!).

Al principio, tampoco tenía un bucle y simplemente presionaba varias teclas para ver si aparecía un código clave. No recibí nada; Entonces, pensé que un bucle podría hacer que el cheque fuera más fácil de probar en caso de que algo se perdiera

Cómo sé que el dispositivo de entrada es el correcto

Lo probé corriendocat en el dispositivo de entrada. Específicamente:

$ sudo cat /dev/input/by-path/platform-i8042-serio-0-event-kbd

El ASCII de basura se envió a mi terminal al presionar y liberar eventos que comienzan con la tecla de retorno (ingresar) cuando comencé la salida utilizando cat. También sé que esto parece funcionar bien con las teclas modificadoras como cambio, control, función e incluso la tecla de comando de Apple en mi Macbook que ejecuta una VM de Linux. La salida apareció cuando se presionó una tecla, comenzó a aparecer rápidamente desde las señales posteriores enviadas al mantener presionada la tecla, y generó más datos cuando se soltó una tecla.

Entonces, si bien mi enfoque puede no ser el correcto (estoy dispuesto a escucharalguna alternativa), el dispositivo parece proporcionar lo que necesito.

Además, sé que este dispositivo es solo un enlace que apunta a / dev / input / event2 desde la ejecución:

$ ls -l /dev/input/by-path/platform-i8042-serio-0-event-kbd

He probado los dos programas anteriores con / dev / input / event2 y no recibí datos. La ejecución de cat en / dev / input / event2 proporcionó la misma salida que con el enlace.

Respuestas a la pregunta(1)

Su respuesta a la pregunta