How to handle character / gamepad input directly on Linux systems?

I am developing a C program that uses a USB SNES controller to input into an RPM distribution. Is there a library that knows about this that facilitates interaction with it, or some tool (joydev?) That allows you to correctly read data from the device? I don't need a whole game engine; it is only for input character device.

If there is a library that is already doing this for me, it will be fine (I can just see what the library does on its own), and this can only be closed by reference; otherwise, if I have to do it myself, I have a few specific questions:

Questions:

  • Is there an existing C library that handles all my interactions with USB devices for the gamepad for me? I will be happy to study the new library. (My google-fu failed me here, I apologize if this is too obvious)
  • How can you open the proper character device every time since the event name changes between sessions / initialization?
  • What is the appropriate method to handle the input of these devices from my application? Just determine what each button presses by value and performs actions based on this input when we are polling a character device?

In short pseduo-C, something like this?

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 */ } } 

How the device presents itself:

I can clearly see how the device registers correctly, as far as I can see:

 $ 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 

And if I read from the device, I see that it receives an interrupt and input from the device just uses 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 

When I press the key (do not release), it works as expected, although I can not decrypt what is returned from the buffer without context:

 $ 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 

When you release the button, you get a similar output:

 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 

This is the up button, pressed and released above.

Study:

In an attempt to determine how other libraries do this, I thought about making strace pygame in python and see which devices it opens, as well as how it reads input, but I'm still learning how to use It. I also saw some vague references to joy, but, again, did not learn to use them. I am doing this now and will post the results if I learn anything of value.

Also, by pressing the browse button using ASCII and hexdump, I note that they have a similar button-based input, but it seems like I think the number of interrupts for the USB bus at the end of the output is higher (0xf53a to 0xf53c). It is always increasing as well, and for my purposes it may possibly be dropped.

There is also the possibility that I simply do not install the device correctly because I am missing a module or package (again, think about joydev and what it should do). I did not work often with USB at all, so this type of device handling is new to me.

In search of some time I did not see anything that showed exactly what I was looking for, but I gladly accept redirecting to other questions / topics for reading.

Thank you in advance!

+6
source share
2 answers

Linux USB input devices are typically handled by the HID (Human Interface Device) driver, which in turn translates to input devices.

You can read them as raw USB devices, but this is usually not a good idea, because it is a protocol with a very low level.

You can read devices /dev/input/* if you have the appropriate permissions. Usually they are read only by root. If you don't want to read raw bytes, there are some libraries, such as libinput , that do the job for you.

But if your game runs on XWindows (most likely), you should manage your XInput devices. You can do this using raw X-calls, but you are probably better off using some library like SDL . Actually SDL is what pygame uses under the hood, so I would try this first.

On how to determine the correct device, each input device has a name, and some even have a serial number (you see them as a symbolic link in the /dev/input/by-id section /dev/input/by-id Usually this is enough to identify the device, not the input number.

If you want to read raw input devices, let me explain the battle about your hexagons. You read input* devices, so you get values โ€‹โ€‹of type struct input_event (see /usr/include/linux/input.h ):

 struct input_event { struct timeval time; __u16 type; __u16 code; __s32 value; }; 

In your first dump, for example:

 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 

Actually there are two input_event s. The first one is:

 f53a 569f 0000 0000 ac6c 000c 0000 0000 0003 0000 007f 0000 

The first 64 bytes are a timestamp. Then 0003 (EV_ABS) means the movement of the absolute axis, 0000 (ABS_X) is the index of the axis, and 0000007f is the position of this axis. Absolute axes are sometimes used to represent chokes, joysticks, etc. (Sometimes the keyboard is sent as a joystick instead of 4 buttons), and you first get a position to know where the control is, even if you don't move it.

Second event:

 f53a 569f 0000 0000 ac6c 000c 0000 0000 0000 0000 0000 0000 

The first 64 bytes is the timestamp (same as above). Then 0000 (EV_SYN) means a synchronization event. With EV_SYN remaining fields are not used. EV_SYN used to group different values โ€‹โ€‹of one event, such as the horizontal and vertical axis of the mouse or joystick.

Your other dump is similar, but for AXIS_Y .

I assume that the keyboard is treated like a digital joystick, two axes ABS_X and ABS_Y , being 0x7F midpoint (from 0x00 to 0xFF ). The messages you receive are just the midpoint that is not pressed. Maybe your hexdump buffer is buffering?

+3
source

This is a USB Hid device, therefore it is handled by a hidden driver - see in its debug output "USB HID v1.10 Gamepad" There are various manuals and examples on how to do this.

As a starting point, you can install the joystick on top of "apt-get install joystick" and see the source code.

Also libhidapi is a good choice.

+1
source

All Articles