Как обрабатывать ввод с символьного устройства / геймпада непосредственно в системах Linux?
Я разрабатываю программу на C, которая использует USB SNES контроллер для входного сигнала на распределении основанном RPM. Есть ли библиотека, о которой кто-нибудь знает, что делает это проще взаимодействовать, или какой-то инструмент (joydev?), что позволяет правильно считывать входные данные с устройства? Мне не нужен весь игровой движок; он предназначен только для ввода с устройства персонажа.
если есть библиотека, которая уже делает это для меня, это было бы отлично (я могу просто посмотреть, что делает библиотека самостоятельно), и это может быть закрыто только ссылкой; в противном случае, если я должен сделать это сам, у меня есть несколько конкретных вопросов:
вопросы:
- есть ли уже существующая библиотека C, которая обрабатывает все мои взаимодействия USB-устройств с геймпадом для меня? Я с удовольствием изучу новую библиотеку. (Мой google-fu подвел меня здесь, я прошу прощения, если это слишком очевидно)
- каков подходящий способ, чтобы убедиться, что вы открываете правильный символ устройство каждый раз, когда событие* имя изменяется между сеансами/инициализацией?
- каков соответствующий метод обработки ввода с этих устройств из моего приложения? Просто определите, что каждое нажатие кнопки равнозначно значению и выполните действия на основе этого ввода, когда мы опрашиваем символьное устройство?
вкратце pseduo-C, что-то вроде этого?
struct gamepad {
int fd;
};
void get_input(struct gamepad *gamepad)
{
char *buf;
read(gamepad->fd, buf, 48);
switch(buf)
{
/* insert cases about handling differing buttons */
}
}
как устройство представляет собой:
Я могу ясно видеть устройство регистрируется правильно, насколько я вижу:
$ dmesg | tail
[198564.517068] usb 1-1: USB disconnect, device number 17
[198566.154324] usb 1-1: new low-speed USB device number 18 using xhci_hcd
[198566.323309] usb 1-1: New USB device found, idVendor=12bd, idProduct=d015
[198566.323312] usb 1-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[198566.323313] usb 1-1: Product: 2Axes 11Keys Game Pad
[198566.323792] usb 1-1: ep 0x81 - rounding interval to 64 microframes, ep desc says 80 microframes
[198566.328692] input: 2Axes 11Keys Game Pad as /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/input/input20
[198566.329036] hid-generic 0003:12BD:D015.0006: input,hidraw2: USB HID v1.10 Gamepad [2Axes 11Keys Game Pad] on usb-0000:00:14.0-1/input0
и если я читаю с устройства, я вижу, что он получает прерывание и ввод с устройства просто с помощью hexdump:
$ ls -lattr /dev/input/by-id/usb-12bd_2Axes_11Keys_Game_Pad-event-joystick
lrwxrwxrwx. 1 root root 10 Jan 20 15:56 /dev/input/by-id/usb-12bd_2Axes_11Keys_Game_Pad-event-joystick -> ../event17
когда я нажимаю клавишу (не отпуская), она работает так, как ожидалось, хотя я пока не могу расшифровать, что возвращается из буфера без контекста:
$ hexdump /dev/input/event17
0000000 f53a 569f 0000 0000 ac6c 000c 0000 0000
0000010 0003 0000 007f 0000 f53a 569f 0000 0000
0000020 ac6c 000c 0000 0000 0000 0000 0000 0000
при отпускании кнопки, вы получаете аналогичный выход:
0000030 f53c 569f 0000 0000 8be3 0007 0000 0000
0000040 0003 0001 007f 0000 f53c 569f 0000 0000
0000050 8be3 0007 0000 0000 0000 0000 0000 0000
это "вверх" кнопка нажата и отпущена выше.
исследования:
в попытке определить, как это делают другие библиотеки, я подумал о том, чтобы сделать strace pygame
в python и посмотреть, какие устройства он открывает, а также как он читает ввод, но я все еще учусь, как его использовать. Я также увидел какие-то смутные упоминания о joydev, но, опять же, не научились ими пользоваться. Я делаю это в настоящее время и опубликую результаты, если узнаю что-нибудь значение.
помимо этого, кнопка просмотра нажимает через ASCII и hexdump, я отмечаю, что у них есть аналогичный вход на основе кнопки, но, похоже, есть то, что я считаю, это количество прерываний для шины USB в конце выхода выше (0xf53a до 0xf53c). Это всегда кажется увеличивающимся, и, для моих целей, вероятно, может быть отброшено.
существует также возможность, что я просто не монтирую устройство правильно, потому что мне не хватает какого-то модуля или пакета (думаю, опять же, о joydev и что он должен делать). Я не часто работал с USB вообще, поэтому этот тип обработки устройств является новым для меня.
Поиск вокруг некоторое время, я не видел ничего, что показало именно то, что я искал, но я с удовольствием принимаю перенаправления на другие вопросы/темы для чтения.
спасибо заранее!
2 ответов
устройства ввода USB в Linux обычно обрабатываются драйвером HID (устройство человеческого интерфейса), которые, в свою очередь, преобразуются в устройства ввода.
вы можете прочитать их как необработанные USB-устройства, но это обычно не очень хорошая идея, потому что это очень низкоуровневый протокол.
вы можете прочитать /dev/input/*
устройств, если у вас есть соответствующие разрешения. Обычно они читаются только по корню. Если вы не хотите читать необработанные байты, есть некоторые библиотеки, такие как libinput, которые делают эту работу за вас.
но если ваша игра работает в XWindows (скорее всего), то вы должны управлять устройствами XInput. Вы можете сделать это с необработанными вызовами X, но вам, вероятно, лучше использовать некоторую библиотеку, такую как SDL. На самом деле SDL-это то, что pygame
использует под капотом, поэтому я бы сначала попробовать.
о том, как определить правильное устройство, каждое устройство ввода имеет имя, а некоторые даже серийный номер (вы видите те, как симлинк под /dev/input/by-id
обычно этого достаточно, чтобы идентифицировать устройство, а не входной номер.
если вы хотите прочитать сырые устройства ввода, поясню насчет о вашем hexdumps. Вы читаете input*
устройства, поэтому вы получаете значения типа struct input_event
(см. /usr/include/linux/input.h
):
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
в вашем первом дампе, например:
0000000 f53a 569f 0000 0000 ac6c 000c 0000 0000
0000010 0003 0000 007f 0000 f53a 569f 0000 0000
0000020 ac6c 000c 0000 0000 0000 0000 0000 0000
на самом деле их два input_event
s. Первый:
f53a 569f 0000 0000 ac6c 000c 0000 0000 0003 0000 007f 0000
первые 64 байта временная метка. Затем:0003 (EV_ABS)
означает движение абсолютной оси,0000 (ABS_X)
- индекс оси и 0000007f
положение этой оси. Абсолютные оси иногда используются для представления дросселей, джойстиков и тому подобного (иногда клавиатуры отправляются как джойстик вместо 4 кнопок), и вы получаете положение на первом чтении, чтобы знать, где находится элемент управления, даже если вы его не перемещаете.
второе событие-это:
f53a 569f 0000 0000 ac6c 000c 0000 0000 0000 0000 0000 0000
первые 64 байта-это метка времени (совпадает с выше. Тогда 0000 (EV_SYN)
означает событие синхронизации. С EV_SYN
, остальные поля не используются. EV_SYN
используется для группировки различных значений одного события, таких как горизонтальная и вертикальная оси мыши или джойстика.
ваш другой дамп похож, но для AXIS_Y
.
я предполагаю, что клавиатура рассматривается как цифровой джойстик, две оси ABS_X
и ABS_Y
, будучи 0x7F
средняя точка (диапазон от 0x00
to 0xFF
). Сообщения, которые вы получаете, - это просто средняя точка, то есть кнопка клавиатуры не нажата. Может быть, ваш hexdump
вывод в буфер?
Это устройство USB Hid, поэтому оно обрабатывается драйвером hid-см. В вашем отладочном выходе " USB HID v1.10 геймпад" Существуют различные учебные пособия и примеры того, как это сделать.
в качестве отправной точки вы можете установить джойстик поверх "apt-get install joystick" и посмотреть исходный код.
также libhidapi является хорошим выбором.