#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. В сочетании с вышесказанным это должно предотвратить создание бесконечного числа процессов.