Linux: Отмена ввода из /dev/ввода/события*

#c #linux #input #keyboard

Вопрос:

В программе, которую я разрабатывал, я хочу считывать удары клавиатуры независимо от того, на каком окне я сосредоточен (так что одна и та же программа будет работать, независимо от того, сосредоточен ли я на Firefox или играю ли в Minecraft, без необходимости менять фокус). До сих пор, используя linux/ввод.библиотека h и чтение из /dev/input/event5, похоже, работают довольно хорошо.

 fd = open(argv[1], O_RDONLY);
struct input_event ev;
int len = read(fd, amp;ev, sizeof(struct input_event));
 

Тем не менее, одна из функций, которую я хотел бы добавить, — это отмена этого ввода во время работы программы, чтобы мои нажатия клавиш не достигали Firefox, Minecraft или общей ОС. Есть ли хороший способ сделать это?

Комментарии:

1. Это проблема XY? Выведение из строя операционной системы-это довольно радикальное решение.

2. Может быть. Я немного поискал решение, которое позволяет мне записывать ввод с клавиатуры, не полагаясь на выделенное окно, чтобы быть в фокусе, и просто записывать необработанные события ввода, казалось, было проще всего. Я попробовал модуль pynput, но это приводило к случайному сбою среды моего рабочего стола всякий раз, когда он был установлен, поэтому я запускал свой собственный.

3. В идеале не весь ввод с клавиатуры будет отменен, а только ввод, который я считаю полезным для своей программы (в основном это клавиши с буквами/цифрами, пробел и клавиши ввода/esc, которые я использую для закрытия программы). Кроме того, программа будет запускаться только при запуске (на данный момент с помощью горячей клавиши автозапуска), поэтому операционная система отключается на минимальное время.

4. В Windows API я использовал SetWindowsHookEx() для просмотра событий клавиатуры, но не пытался вмешиваться в них. Ну, не там, я сгенерировал события, как будто они возникли с клавиатуры SendInput() , но они переходят к процессу, который имеет фокус (которым также можно управлять).

5. Однако, согласно rediculousanddirtyprogramming , SetWindowsHookEx можно использовать для этой цели, если вы действительно этого хотите. К сожалению, я нахожусь в Linux (хотя это может быть полезно, если я захочу перенести свое приложение в Windows).

Ответ №1:

Предупреждение: непроверено

  • откройте символьное устройство в режиме O_RDWR (чтение/запись)
  • захватите устройство: ioctl(fd, EVIOCGRAB, 1)
  • читать события
  • если вы хотите отправить событие:
    • ioctl устройства ungrab(fd, EVIOCGRAB, 0)
    • событие записи

Между удалением и записью могут произойти другие события, которые не будут отфильтрованы и отправлены всем подключенным дескрипторам файлов. Я не знаю, можно ли сначала написать, а потом снять граб (или вообще написать, проверьте возвращаемое значение write ).

Подсказка: Вы также можете изменить libevdev.

Комментарии:

1. На самом деле это работает довольно хорошо. Однако следует иметь в виду две вещи: 1. Необходимо приостановить программу на секунду перед захватом ( sleep(1); ). В противном случае, какое бы нажатие клавиши ни использовалось для запуска программы (т. Е. клавиша ввода в среде терминала), вызов «включения» никогда не будет отправлен в ОС, что приведет к бесконечному потоку повторяющихся нажатий. 2. Мы можем использовать код возврата вызова ioctl, чтобы гарантировать, что одновременно выполняется только один экземпляр программы, выходящий, если он ниже 0. В сочетании с вышесказанным это должно предотвратить создание бесконечного числа процессов.