Register
handmade.network»Forums»Modern Way To Read Gamepad Input With C On Linux
2 posts
Modern Way To Read Gamepad Input With C On Linux
9 months, 2 weeks ago Edited by JimAitken on Feb. 4, 2019, 8:52 p.m. Reason: Initial post
I am interested in reading gamepad input, specifically a gamepad with the layout of a wired xbox 360 controller, with C on a linux machine. I understand that this can be done in a variety of ways, however I was wondering what is the modern method of accomplishing this. As I understand it, evdev is the 'future' while the Joystick API is legacy. Using libudev I am able to find attached gamepads and detect when they are connected and disconnected:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// skipping setup code ....
char const* val = udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
if (val != NULL && strcmp(val, "1") == 0) {
  char const* devfs_path = udev_device_get_devnode(udev_device);
}
// .....
struct udev_device* device = udev_monitor_recieve_device(udev_monitor); 
char const* action = udev_device_get_action(device);
if (strcmp(action, "add") == 0) {
  // .....
}
if (strcmp(action, "remove") == 0) {
  // .....
}
The crux of my question lies in the best way to read button presses and axis movement. Currently, I am unsure whether to use
1
struct js_event
or
1
struct input_event
. In truth, I was hoping to be able to do this with the same check for connected and removed gamepads with libudev. If this is not possible, which is the most forward-thinking approach? Thanks
Mārtiņš Možeiko
1983 posts / 1 project
Modern Way To Read Gamepad Input With C On Linux
9 months, 2 weeks ago
I personally in this kind of situations go to libSDL or glfw source code to check what they do.

Both of them are using input_event struct.
David Butler
81 posts / 1 project

I love pretty much anything technical, whether it be programming, networking, hacking or electronics.

Modern Way To Read Gamepad Input With C On Linux
9 months, 2 weeks ago Edited by David Butler on Feb. 5, 2019, 12:22 a.m.
According to the documentation:

Newer clients are encouraged to switch to the generic event (evdev) interface.

IE. not the "joydev" interface.


Code:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>

int main () {
    auto gamepad = open("/dev/input/by-id/usb-045e_0291-event-joystick", 
                        O_RDONLY|O_NONBLOCK);
    assert(gamepad != -1);
    int gamepad_debug_event_count = 0;
    int gamepad_button_A_down = 0;
    int gamepad_button_B_down = 0;
    int gamepad_stick_left_x = 0;
    int gamepad_stick_left_y = 0;
    for (;;) {
        struct input_event events[8]; // 8 events per frame is pretty extreme, more like 1 or 2, sometimes as high as 4
        auto r1 = read(gamepad, events, sizeof events);
        if (r1 != -1) {
            int new_event_count = r1/sizeof(struct input_event);
            for (int evi=0; evi<new_event_count; evi++) {
                auto& ev = events[evi];
                switch (ev.type) {
                    case EV_ABS: {
                        switch (ev.code) {
                            case ABS_X: { gamepad_stick_left_x = ev.value; } break;
                            case ABS_Y: { gamepad_stick_left_y = ev.value; } break;
                        }
                    } break;
                    case EV_KEY: {
                        switch (ev.code) {
                            case BTN_A: { gamepad_button_A_down = ev.value; } break;
                            case BTN_B: { gamepad_button_B_down = ev.value; } break;
                            
                        }
                    } break;
                }
                gamepad_debug_event_count ++;
            }
        }
        
        assert(r1 != -1 || errno == EWOULDBLOCK || errno == EAGAIN);
        
        printf("Pos %d Left stick:%d,%d  A:%d B:%d \r", 
               gamepad_debug_event_count,
               gamepad_stick_left_x,
               gamepad_stick_left_y,
               gamepad_button_A_down,
               gamepad_button_B_down
               );
        
    }
    usleep(20*1000);
    
}




404 Signature not found
2 posts
Modern Way To Read Gamepad Input With C On Linux
9 months, 2 weeks ago
Thank you Martins, SDL source is indeed very informative. At times however, I find it a bit difficult to grasp the fundamentals from it as it supports so many use cases.
Thank you too David for your code snippet. I found linux input community docs to be very helpful in discerning the particular button mappings I was after.
I will indeed go ahead using linux_input.

To implement the same behaviour in macosx, I have far less intuition than I do for linux. I have found that there is Game Controller framework, however this only seems to support a very small subset of gamepads that Apple likes, making it impractical for me to test. Alternatively, it seems I can use HID Manager, however looking at SDL source it seems a lot of work to implement. Do you know if HID Manager is the way to go to support the widest array of popular controllers?
Thanks again.