2

I am trying to figure out how to properly handle game controller inputs in an SDL2 program. I have written a program which is able to handle inputs from my game controller on my Mac, but not on my Linux machine. However, the game controller does work with other programs on the Linux machine. My program uses a library called Simple2D, which wraps SDL2 to provide an easier interface.

I'm trying to determine if the problem is with the controller input handling or some missing dependency/configuration on the Linux side. I have not found any examples of using SDL2 to handle game controller inputs to determine if the code is working correctly.

Here is the code that Simple2D uses for handling game controller inputs. Do you see anything that could cause my controller to not work on my Linux machine?

https://github.com/simple2d/simple2d/blob/master/src/simple2d.c#L642-L689

  // Variables for controllers and joysticks
  SDL_GameController *controller = NULL;
  SDL_Joystick *joy = NULL;

  // Enumerate joysticks
  for (int i = 0; i < SDL_NumJoysticks(); ++i) {

    // Check to see if joystick supports SDL's game controller interface
    if (SDL_IsGameController(i)) {
      controller = SDL_GameControllerOpen(i);
      if (controller) {
        sprintf(S2D_msg, "Found a valid controller, named: %s\n",
                SDL_GameControllerName(controller));
        S2D_Log(S2D_msg, S2D_INFO);
        break;  // Break after first available controller
      } else {
        sprintf(S2D_msg, "Could not open game controller %i: %s\n", i, SDL_GetError());
        S2D_Log(S2D_msg, S2D_ERROR);
      }

    // Controller interface not supported, try to open as joystick
    } else {
      sprintf(S2D_msg, "Joystick %i is not supported by the game controller interface", i);
      S2D_Log(S2D_msg, S2D_WARN);
      joy = SDL_JoystickOpen(i);

      // Joystick is valid
      if (joy) {
        sprintf(S2D_msg,
          "Opened Joystick %i\n"
          "Name: %s\n"
          "Axes: %d\n"
          "Buttons: %d\n"
          "Balls: %d\n",
          i, SDL_JoystickName(joy), SDL_JoystickNumAxes(joy),
          SDL_JoystickNumButtons(joy), SDL_JoystickNumBalls(joy)
        );
        S2D_Log(S2D_msg, S2D_INFO);

      // Joystick not valid
      } else {
        sprintf(S2D_msg, "Could not open Joystick %i", i);
        S2D_Log(S2D_msg, S2D_ERROR);
      }

      break;  // Break after first available joystick
    }
  }

https://github.com/simple2d/simple2d/blob/master/src/simple2d.c#L782-L806

SDL_Event e;
while (SDL_PollEvent(&e)) {
  switch (e.type) {

    case SDL_JOYAXISMOTION:
      if (window->on_controller)
        window->on_controller(true, e.jaxis.axis, e.jaxis.value, false, 0);
      break;

    case SDL_JOYBUTTONDOWN:
      if (window->on_controller)
        window->on_controller(false, 0, 0, true, e.jbutton.button);
      break;

Update: Thanks to @genpfault, I found out that the SDL codebase comes with a test script. I am working on compiling and running this. After downloading the source code, on my Mac, I was able to successfully compile and run the test script like this:

$ cd SDL2-2.0.4/test
$ gcc testgamecontroller.c `sdl2-config --cflags --libs`
$ ./a.out

However, when I tried the same thing on my Linux machine, it failed to compile:

$ gcc testgamecontroller.c `sdl2-config --cflags --libs`
In file included from /usr/include/SDL2/SDL.h:69:0,
                 from testgamecontroller.c:19:
testgamecontroller.c: In function 'main':
testgamecontroller.c:296:132: warning: comparison between pointer and integer
                 SDL_assert(SDL_GameControllerFromInstanceID(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamecontroller))) == gamecontroller);
                                                                                                                                    ^
/usr/include/SDL2/SDL_assert.h:143:19: note: in definition of macro 'SDL_enabled_assert'
         while ( !(condition) ) { \
                   ^
testgamecontroller.c:296:17: note: in expansion of macro 'SDL_assert'
                 SDL_assert(SDL_GameControllerFromInstanceID(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamecontroller))) == gamecontroller);
                 ^
testgamecontroller.c:325:144: warning: comparison between pointer and integer
                             SDL_assert(SDL_GameControllerFromInstanceID(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamecontroller))) == gamecontroller);
                                                                                                                                                ^
/usr/include/SDL2/SDL_assert.h:143:19: note: in definition of macro 'SDL_enabled_assert'
         while ( !(condition) ) { \
                   ^
testgamecontroller.c:325:29: note: in expansion of macro 'SDL_assert'
                             SDL_assert(SDL_GameControllerFromInstanceID(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamecontroller))) == gamecontroller);
                             ^
/tmp/ccipRq1s.o: In function `main':
testgamecontroller.c:(.text+0x8ea): undefined reference to `SDL_GameControllerFromInstanceID'
testgamecontroller.c:(.text+0xa0e): undefined reference to `SDL_GameControllerFromInstanceID'
collect2: error: ld returned 1 exit status

So then I tried to run ./configure && make instead:

$ ./configure 
checking build system type... armv7l-unknown-linux-gnueabihf
checking host system type... armv7l-unknown-linux-gnueabihf
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for an ANSI C-conforming const... yes
checking for pkg-config... /usr/bin/pkg-config
checking pkg-config is at least version 0.9.0... yes
checking for SDL... yes
checking how to run the C preprocessor... gcc -E
checking for X... libraries , headers 
checking for OpenGL support... yes
checking for OpenGL ES support... no
checking for OpenGL ES2 support... yes
checking for TTF_Init in -lSDL2_ttf... yes
configure: creating ./config.status
config.status: creating Makefile

$ make
gcc -o checkkeys checkkeys.c -g -O2 -D_REENTRANT -I/usr/include/SDL2  -DHAVE_OPENGLES2 -DHAVE_OPENGL -DHAVE_SDL_TTF -g -lSDL2_test -lSDL2 
gcc -o loopwave loopwave.c -g -O2 -D_REENTRANT -I/usr/include/SDL2  -DHAVE_OPENGLES2 -DHAVE_OPENGL -DHAVE_SDL_TTF -g -lSDL2_test -lSDL2 
gcc -o loopwavequeue loopwavequeue.c -g -O2 -D_REENTRANT -I/usr/include/SDL2  -DHAVE_OPENGLES2 -DHAVE_OPENGL -DHAVE_SDL_TTF -g -lSDL2_test -lSDL2 
/tmp/ccdYXqs4.o: In function `loop':
/home/chip/stash/SDL2-2.0.4/test/loopwavequeue.c:63: undefined reference to `SDL_GetQueuedAudioSize'
/home/chip/stash/SDL2-2.0.4/test/loopwavequeue.c:66: undefined reference to `SDL_QueueAudio'
collect2: error: ld returned 1 exit status
Makefile:78: recipe for target 'loopwavequeue' failed
make: *** [loopwavequeue] Error 1

I'm not sure why it is failing to compile and how to move past these errors.

Update: Thanks again to @genpfault, installing the latest version of SDL (2.0.4) from source, instead of using version 2.0.2 that was available as a package, fixed my compiling issues.

Now when I run the controller test script, on my Linux machine, I see this:

2016-06-29 12:59:05.588 a.out[64297:8754739] INFO: There are 0 game controller(s) attached (0 joystick(s))

However, when I run it on my Mac I see this:

2016-06-29 12:59:25.688 a.out[64303:8755040] INFO: Joystick 0: USB,2-axis 8-button gamepad   (guid 83050000000000006020000000000000)
2016-06-29 12:59:25.690 a.out[64303:8755040] INFO: There are 0 game controller(s) attached (1 joystick(s))

What could be different about the Linux environment? Again, the same controller works in other programs on this same Linux machine.

Update: I found that the device is detected:

$ cat /proc/bus/input/devices
...

I: Bus=0003 Vendor=0583 Product=2060 Version=0110
N: Name="USB,2-axis 8-button gamepad  "
P: Phys=usb-1c14400.usb-1/input0
S: Sysfs=/devices/platform/soc@01c00000/1c14400.usb/usb2/2-1/2-1:1.0/0003:0583:2060.0003/input/input5
U: Uniq=
H: Handlers=js0 event2 
B: PROP=0
B: EV=1b
B: KEY=ff 0 0 0 0 0 0 0 0 0
B: ABS=3
B: MSC=10

However, I'm not sure why SDL is not detecting it.

Andrew
  • 227,796
  • 193
  • 515
  • 708
  • By "not handle inputs" do you mean that it flat out disregards all events, or does it register some events? Nothing in your code jumps out as being wrong. I wish I had a joystick to test your code with and be of more help. Lazy Foo' Productions has a simple [SDL2 Gamepads and Joysticks tutorial](http://lazyfoo.net/tutorials/SDL/19_gamepads_and_joysticks/index.php), I never worked through it but I did work through their other tutorials and they were helpful. – Jonny Henly Jun 28 '16 at 22:36
  • I mean, it works as expected on my Mac. When I press the buttons/arrows, my code recognizes it. When it runs on my Linux machine, it does not even fire an event (as far as I can tell). However, other events like keyboard button presses work fine. – Andrew Jun 28 '16 at 23:41
  • By the way, here is the controller that I am using: http://amzn.to/29mr0nF – Andrew Jun 28 '16 at 23:45
  • Have you tried simple debugging with `printf` statements inside of the polling while loop, to see if an event is fired, and inside `case SDL_JOYAXISMOTION` and `case SDL_JOYBUTTONDOWN`, to see if the event is recognized? – Jonny Henly Jun 28 '16 at 23:52
  • 1
    "I have not found any examples of using SDL2 to handle game controller inputs to determine if the code is working correctly."...[What about the one included with SDL?](https://hg.libsdl.org/SDL/file/4844b48eb17b/test/testgamecontroller.c) – genpfault Jun 29 '16 at 14:46
  • @genpfault Yeah, I came across that one, but I thought that is was for an older version of SDL (not v2). Maybe I didn't compile it correctly. Do you know how to compile that example? – Andrew Jun 29 '16 at 14:49
  • 1
    @Andrew: The 'ole `cd test && ./configure && make` Autotools dance works for me. As does a `gcc testgamecontroller.c \`sdl2-config --cflags --libs\``. – genpfault Jun 29 '16 at 14:57
  • @genpfault oh I didn't realize that was part of the SDL codebase. I thought it was just some random script. I'll try cloning the codebase, compiling, and running that script. – Andrew Jun 29 '16 at 15:00
  • @genpfault Thanks! Unfortunately, I ran into errors compiling on Linux. I have added an update with the backtrace. Can you look and see what I might be doing wrong? – Andrew Jun 29 '16 at 20:19
  • 1
    @Andrew: Are you using the SDL2 that your distro shipped or the version from the source tarball? My distro was shipping 2.0.2 instead of the 2.0.4 in the latest tarball and I got similar errors until I built & installed 2.0.4. – genpfault Jun 29 '16 at 20:39
  • @genpfault Yes, that was it. I was using a 2.0.2 package. I installed from source and that fixed the compiling problem. Thanks! Now when I run the controller test script, it correctly detects the controller on my Mac but not on Linux. What could be the problem? – Andrew Jun 29 '16 at 21:40
  • 1
    @Andrew: Can [`testjoystick.c`](https://hg.libsdl.org/SDL/file/4844b48eb17b/test/testjoystick.c) see the pad on Linux? If so then the gamepad database might be missing an entry for your pad. Should be [possible to generate one in that case](https://hg.libsdl.org/SDL/file/4844b48eb17b/test/controllermap.c). – genpfault Jun 29 '16 at 22:00
  • @genpfault I ran `testjoystick.c` as well as `controllermap.c` and they both report `There are 0 joysticks available`. Again, on my Mac, it detected as `Joystick 0: USB,2-axis 8-button gamepad`...any other ideas? – Andrew Jun 29 '16 at 23:10
  • In fact, the `guid` matches the one listed [on this line of a controller db file](https://github.com/gabomdq/SDL_GameControllerDB/blob/master/gamecontrollerdb.txt#L54) – Andrew Jun 29 '16 at 23:13
  • 1
    @Andrew: Double-check your `configure` output for SDL2, it might not have found the joystick IO library(s). If you're on a Debian or Debian-derivative you can pull those in via `apt-get build-dep libsdl2-dev` & rebuild SDL2. – genpfault Jun 30 '16 at 13:22
  • @genpfault I don't see anything about a joystick IO library. I do see that `enabled modules` includes `joystick`. Is that what you were referring to? – Andrew Jun 30 '16 at 14:22
  • [Here's](http://pastebin.com/8EULANWP) the final part of my `configure` output. I *think* the `xinput2`, `linuxev`, and `Using libudev : YES` are the important bits re: joysticks. – genpfault Jun 30 '16 at 14:35
  • @genpfault hmmm...mine is identical with the exception of a few less audio drivers and does not list anything for Assembly Math, but I don't think those are related to this issue. – Andrew Jun 30 '16 at 15:21
  • @Andrew: Well crud. I'm kinda at the end of my troubleshooting decision tree, sorry we couldn't get it figured out :( – genpfault Jun 30 '16 at 15:57
  • @genpfault No worries. You've been a great help getting me to this point! Thanks! – Andrew Jun 30 '16 at 17:04
  • @Andrew: do you run CentOS 5 ? Does your joystick work with SDL1 games ? There is no SDL2 support for joysticks on old Linux systems which don't have the Event API. see https://forums.libsdl.org/viewtopic.php?t=9772&sid=d8a674f72ddc6f35b4675a39e664d274 – Joseph Paul Jul 01 '16 at 13:56
  • 1
    @JosephPaul Thanks. Actually I figured out my issue. The controller does use the Event API, however, my issue was that the user did not have permission to read those files. Adding the user to the `input` group solved the problem. – Andrew Jul 01 '16 at 17:15
  • Better, to have an answer. – user.dz Oct 18 '19 at 11:14

0 Answers0