удалить/переписать/генерировать события клавиатуры под Linux

Я хотел бы подключиться, перехватить и сгенерировать события клавиатуры (сделать/разбить) в Linux до того, как они будут доставлены в какое-либо приложение. Точнее, я хочу обнаруживать шаблоны в ключевом потоке событий и иметь возможность отбрасывать/вставлять события в поток в зависимости от обнаруженных шаблонов.

Я видел некоторые связанные вопросы по SO, но:

  • либо они имеют дело только с тем, как получить ключевые события (кейлоггеры и т. д.), а не с тем, как манипулировать их распространением (они только слушают, но не перехватывают/генерируют).
  • или они используют пассивные/активные захваты в X (подробнее об этом ниже).

Маленький DSL

Я объясню проблему ниже, но чтобы сделать ее немного более компактной и понятной, сначала небольшое определение DSL.

  • A_: сделать (нажать) клавишу A
  • A^: для прерывания (отпускания) клавиши A
  • A^->[C_,C^,U_,U^]: в A^ отправьте комбинацию make/break для C, а затем для U дальше по цепочке обработки (и, наконец, в приложение). Если -> нет, то ничего не отправляется (но внутреннее состояние может быть изменено для обнаружения последующих событий).
  • $X: выполнить произвольное действие. Это может быть отправка какой-либо настраиваемой последовательности событий клавиш (может быть, что-то вроде C-x C-s для emacs) или выполнение функции. Если бы я мог отправлять только ключевые события, этого было бы достаточно, так как я мог бы затем обработать их в оконном менеджере в зависимости от того, какое приложение активно.

описание проблемы

Итак, с этой нотацией вот шаблоны, которые я хочу обнаружить, и какие события я хочу передать по цепочке обработки.

  1. A_, A^->[A_,A^]: поясн. см. выше, обратите внимание, что отправка происходит A^.
  2. A_, B_, A^->[A_,A^], B^->[B_,B^]: в основном то же, что и 1. но перекрывающиеся события не меняют поток обработки.
  3. A_, B_, B^->[$X], A^: если произошло полное замыкание/размыкание ключа (B) при удерживании другого ключа (A), выполняется X (см. выше), а разрыв A отбрасывается.

(в принципе, это простой конечный автомат, реализованный для ключевых событий, который может генерировать (несколько) ключевых событий в качестве вывода).

Дополнительные замечания

  • Решение должно работать на скорости набора текста.
  • Потребители измененного потока ключевых событий работают под X в Linux (консоли, браузеры, редакторы и т. д.).
  • На обработку влияют только события клавиатуры (без мыши и т. д.)
  • Сопоставление может происходить по символам клавиш (немного проще) или по кодам клавиш (немного сложнее). В последнем случае мне просто нужно будет прочитать сопоставление, чтобы перевести код в keysym.
  • Если возможно, я бы предпочел решение, которое работает как с USB-клавиатурами, так и внутри виртуальной машины (могут быть проблемы при работе на уровне драйвера, другие уровни должны быть в порядке).
  • Я довольно открыто говорю о языке реализации.

Возможные решения и вопросы

Итак, основной вопрос заключается в том, как это реализовать.

Я реализовал решение в оконном менеджере, используя пассивные захваты (XGrabKey) и XSendEvent. К сожалению, в этом случае пассивные захваты не работают, так как они неправильно захватывают B^ во втором шаблоне выше. Причина в том, что преобразованный захват заканчивается на A^ и не продолжается до B^. Новый захват преобразуется в захват B, если он все еще удерживается, но только через ~1 секунду. В противном случае приложению отправляется обычный B^. Это можно проверить с помощью xev.

Я мог бы преобразовать свою реализацию, чтобы использовать активный захват (XGrabKeyboard), но я не уверен в эффекте на другие приложения, если оконный менеджер все время активно захватывает клавиатуру. Документация X описывает активные захваты как навязчивые и предназначенные для краткосрочного использования. Если у кого-то есть опыт с этим и нет серьезных недостатков с долгосрочными активными захватами, то я бы рассмотрел это как решение.

Я готов рассмотреть другие уровни обработки ключевых событий помимо оконных менеджеров (которые работают как X-клиенты). Драйверы клавиатуры или сопоставления возможны, если я могу решить с ними вышеуказанную проблему. Это также означает, что решение не обязательно должно быть отдельным приложением. Меня вполне устраивает драйвер или модуль ядра, делающий это за меня. Имейте в виду, однако, что я никогда не занимался программированием ядра или драйвера, поэтому я был бы признателен за хорошие ресурсы.

Спасибо за любые подсказки!


person Heron    schedule 23.09.2010    source источник
comment
Могу я спросить конечную цель этого? Это задание? Любимый проект? Профессиональная работа? Что-то другое?   -  person kazanaki    schedule 15.10.2010
comment
Вы нашли способ добиться этого?   -  person retracile    schedule 07.05.2012


Ответы (1)


Используйте XInput2, чтобы сделать устройство (клавиатуру) плавающим, затем отслеживайте события KeyPress и KeyRelease на устройстве, используя XTest для повторного создания событий KeyPress и KeyRelease.

person reiv    schedule 21.10.2010