Подключиться к обработке событий в ключе Linux

Я хочу подключиться к обработке событий на клавиатуре Linux.

Нажатие кнопки CapsLock должно ввести какую-то командную строку.

Некоторые из команд, которые я хочу реализовать:

  • d/x: удалить текущую позицию курсора до символа x. (вдохновленный vi)
  • a: Перейти к началу строки, например pos1. (вдохновленный emacs).
  • k: Удалить до конца строки. (вдохновленный emacs).
  • ...

Команды должны работать в любом текстовом поле: браузер, почтовый клиент, терминал gnome,...

AFAIK низкоуровневый xmodmap не поможет мне здесь.

Возможно ли подобное?

Где мне нужно разместить крючок?

Текущей целевой платформой является Ubuntu >= 14.04

Справочная информация. Я хочу, чтобы мои пальцы указывали на F и J, и используйте компьютер, не глядя на клавиатуру. Работает для A-Z с нескольких лет, но клавиши, такие как Pos1/End, получить нелегко.

Пожалуйста, оставьте комментарий, если вы не понимаете часть этого вопроса. Спасибо.

Обновление

Этот вопрос касается только того, как подключиться к обработке ключевых событий. Другой материал (командная строка) - это другая тема. Как вы можете уловить, например, CapsLock x?

Update2 Я вижу, что нет простого и прямого решения. Если у вас нет ответа, но вы знаете, где я могу найти дополнительную помощь (например, спросить в списке рассылки FOO), пожалуйста, скажите мне.

Update3 Поскольку некоторые люди не понимают, что я хочу, я пытаюсь объяснить это: если я использую emacs или bash, я чувствую, что контролирую, если компьютер: он похож на полет, при этом очень мало движений, я могу сказать, что компьютер делай то, что я хочу. Редактирование текста в текстовом поле webbrowser, LibreOffice или использовании thunderbird заставляет это чувство уйти. Движения курсора громоздки, ему не хочется летать. Я хочу контролировать рабочий стол, а не только одно приложение, и держать указательные пальцы на клавишах F и J.

Ответ 1

UPDATE

Вместо того, чтобы сообщать X-серверу об игнорировании устройства, вы можете использовать EVIOCGRAB ioctl, который я добавил в программу ниже.

Вам нужно сделать следующее:

1.Убедитесь, что модуль CONFIG_UINPUT скомпилирован и загружен. Я считаю, Ubuntu уже имеет его. Если вы не видите устройство /dev/uinput, попробуйте запустить modprobe -v uinput, чтобы загрузить модуль.

2. Запустите следующую программу с правами root и укажите путь к клавиатурному устройству, например:

./process /dev/input/by-id/usb-Microsoft_Wired_Keyboard_600-event-kbd

Следующая программа создает поддельное устройство ввода под названием uinput-sample и пересылает все события с данного устройства ввода на него. Я адаптировал его из образца, приведенного в http://thiemonge.org/getting-started-with-uinput

Вы можете изменить его, чтобы делать то, что вы хотите сделать.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>

#define die(str, args...) do { \
        perror(str); \
        exit(EXIT_FAILURE); \
    } while(0)

int
main(int argc, char* argv[])
{
    int                    fdo, fdi;
    struct uinput_user_dev uidev;
    struct input_event     ev;
    int                    i;

    if(argc != 2) die("error: specify input device");

    fdo = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
    if(fdo < 0) die("error: open");

    fdi = open(argv[1], O_RDONLY);
    if(fdi < 0) die("error: open");

    if(ioctl(fdi, EVIOCGRAB, 1) < 0) die("error: ioctl");

    if(ioctl(fdo, UI_SET_EVBIT, EV_SYN) < 0) die("error: ioctl");
    if(ioctl(fdo, UI_SET_EVBIT, EV_KEY) < 0) die("error: ioctl");
    if(ioctl(fdo, UI_SET_EVBIT, EV_MSC) < 0) die("error: ioctl");

    for(i = 0; i < KEY_MAX; ++i)
        if(ioctl(fdo, UI_SET_KEYBIT, i) < 0) die("error: ioctl");

    memset(&uidev, 0, sizeof(uidev));
    snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");
    uidev.id.bustype = BUS_USB;
    uidev.id.vendor  = 0x1;
    uidev.id.product = 0x1;
    uidev.id.version = 1;

    if(write(fdo, &uidev, sizeof(uidev)) < 0) die("error: write");
    if(ioctl(fdo, UI_DEV_CREATE) < 0) die("error: ioctl");

    while(1)
    {
        if(read(fdi, &ev, sizeof(struct input_event)) < 0)
            die("error: read");

        ev.time.tv_sec = 0;
        ev.time.tv_usec = 0;

        if(write(fdo, &ev, sizeof(struct input_event)) < 0)
            die("error: write");
    }

    if(ioctl(fdo, UI_DEV_DESTROY) < 0) die("error: ioctl");

    close(fdi);
    close(fdo);

    return 0;
}

Ответ 2

Путь грубой силы - это сделать modyfy/rebuild xserver-xorg-input-evdev и заменить /usr/lib/xorg/modules/input/evdev_drv.so. Я бы начал с попытки изменить функцию EvdevQueueKbdEvent() в xf86-input-evdev-2.9.0/src/evdev.c. Не выглядит очень элегантным решением, но я думаю, вы получите гибкость в изменении очереди событий на клавиатуре.

Менее интрузивное решение может быть возможно с помощью XGRabKey() (некоторые подробности здесь) и/или XGrabKeyboard().

Некоторая информация, которая может быть полезной здесь (относительно расширения XTest).

Ответ 3

Еще один способ взглянуть на ваш вопрос: вам нужен специализированный оконный менеджер. Подробнее читайте EWMH. Прочтите перед обзором X11.

Или рассмотрите некоторые существующие X window manager. Их много. Я подозреваю, что ratpoison или xmonad (или возможно sawfish и т.д.) можно настроить для удовлетворения ваших потребностей. (Но я не очень хорошо знаю эти WM).

Подумайте дважды, прежде чем внедрять свой оконный менеджер с нуля. Это может означать годы работы! AFAIU, WM может перенаправлять, фильтровать, захватывать или синтезировать события клавиатуры или мыши.

Конечно, с wayland все будет по-другому.