Захват нажатий клавиш в GNU/Linux в C без X11

Если я работаю в приложении и нажимаю клавишу с клавиатуры, как я могу захватить этот ключ (или строку), включая имя исходного приложения, в C, в GNU/LINUX, в userland, без X11:)

Спасибо.

Ответ 1

Ну, без X11 эта проблема сложнее.
Для части нажатия клавиши вы можете использовать код, похожий на этот, но вы должны передать в качестве аргумента устройство, которое вы читаете (клавиатура, обычно /dev/input/event 0)

#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int fd;
    if(argc < 2) {
        printf("usage: %s <device>\n", argv[0]);
        return 1;
    }
    fd = open(argv[1], O_RDONLY);
    struct input_event ev;

    while (1)
    {
    read(fd, &ev, sizeof(struct input_event));

    if(ev.type == 1)
        printf("key %i state %i\n", ev.code, ev.value);

    }
}

Кредиты не идут ко мне, этот код взят из взлома Ventriloctrl, чтобы получить нажатия клавиш. http://public.callutheran.edu/~abarker/ventriloctrl-0.4.tar.gz

Надеюсь, что я немного помогу.

Ответ 2

Вы можете читать данные из одного из файлов в /dev/input. Какой из них зависит от вашей системы. Это может быть /dev/input/event 0 или/dev/input/by-path/platform-i8042-serio-0-event-kbd или что-то еще. Формат указан в заголовке ядра input.h.

struct input_event {
        struct timeval time;
        __u16 type;
        __u16 code;
        __s32 value;
};

Вы можете запустить

od -tx2 FILENAME

и введите что-то, чтобы увидеть, что произойдет.

Что касается определения того, какое приложение получило ключевое событие, я не уверен. Вы можете попробовать проверить, какой из них читается из основного tty.

Ответ 3

Одна возможность: найти и взглянуть на источник для sudosh ',' sudo shell '(или один из его замены, поскольку это не было изменено через некоторое время, Google - ваш друг).

Он взаимодействует с псевдо-tty и отслеживает все входные и выходные данные, также записывая информацию в файл.

ли, что достаточно точен для вас, возможно, более спорно; он будет записывать все нажатия клавиш для всех приложений. Я также не уверен, как он работает с X11 - если он работает с X11.

Ответ 4

Для довольно хорошего примера просмотрите showkey код.

В частности, здесь основной цикл. Все, что он делает - это получить терминал, скопировать его, перевести скопированный в необработанный режим и до тех пор, пока не будет указана последовательность клавиш "quit" или "interrupt", он просто распечатает, какой ключ был предоставлен терминалу.

/*
 * showkey.c -- display cooked key sequences
 *
 * Invoke this (no arguments needed) to see keycap-to-keystrokes mappings.
 *
 * by Eric S. Raymond <[email protected]>, 1 Nov 88
 * - fix for little-endian machines (version 1.1), 21 Oct 1996.
 * - cleanup and modern packaging (version 1.2), 1 Aug 2002.
 * - changed to use termios (version 1.3), 26 Aug 2002.
 * See the RPM spec file changelog for more recent stuff.
 */
#include <stdio.h>
#include <termios.h>
#include <signal.h>
#include <string.h>
#include <stdbool.h>
static int signalled;

// ...

main()
{
    struct termios  cooked, raw;
    unsigned char   c;
    unsigned int    i, timeouts;
    char intrchar[32], quitchar[32];

    for (i = SIGHUP; i <= SIGIO; i++)
    (void) signal(c, catcher);

    // Get the state of the tty 
    (void) tcgetattr(0, &cooked);
    // Make a copy we can mess with
    (void) memcpy(&raw, &cooked, sizeof(struct termios));
    // Turn off echoing, linebuffering, and special-character processing,
    // but not the SIGINT or SIGQUIT keys.
    raw.c_lflag &=~ (ICANON | ECHO);
    // Ship the raw control blts
    (void) tcsetattr(0, TCSANOW, &raw);

    (void) printf("Type any key to see the sequence it sends.\n");
    visualize(raw.c_cc[VINTR], intrchar);
    visualize(raw.c_cc[VQUIT], quitchar);
    (void) printf("Terminate with your shell interrupt %s or quit %s character.\n",
          intrchar, quitchar);
    signalled = 0;
    while (!signalled)
    {
    char cbuf[32];

    read(0, &c, 1);
    visualize(c, cbuf);
    (void)fputs(cbuf, stdout);
    (void) fflush(stdout);
    }

    (void) printf("\nBye...\n");
    // Restore the cooked state
    (void) tcsetattr(0, TCSANOW, &cooked);
}