Joystick Buttons won't get recognized

Hello,

I try to create a game with SDL2 and I am able to open my joystick and also get the axis movement etc, but I don’t get any button presses. I tried it with 4 different gamepads (XBOX 360 controller, OUYA controller, Competition Pro USB, Trust EasyPlay), and while all of them were recognized and all of them yielded a positive result for SDL_JoystickNumButtons, with none of them I could get any button press or release events.

I tried with Event Polling, and I also tried with SDL_JoystickGetButton.
Btw, I used Xubuntu 13.04, haven’t tried it under Windows yet.

Another question: I also tried to understand the GameController library, but I don’t get it. How is that supposed to be used? I have absolutely no idea how this library works, even though I have read the wiki page a few times.

Here’s a couple of basic Joystick examples (compiled by my brain,
which is somewhat tolerant of typos?) I’m going to assume you have
init both joysticks and gamecontrollers for this:

First, show current sticks (a verbose example?)

int i;
SDL_Joystick * joystick;

for (i = 0; i < SDL_NumJoysticks(); ++i) {
const char * name = SDL_JoystickNameForIndex(i);
printf(“Joystick index %d: %s\n”, i, name? name : “[no name]”);

   /* This much can be done without opening the controller */
   if (SDL_IsGameController(i)) {
       char *mapping = SDL_GameControllerMappingForGUID(
               SDL_JoystickGetDeviceGUID(i));
       printf("game controller: %s\n", mapping);
       SDL_free(mapping);
   } else {
       char guid[64];
       SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(i),
               guid, sizeof (guid));
       printf("           guid: %s\n", guid);
   }

   /* For anything else we have to open */
   joystick = SDL_JoystickOpen(i);
   if (joystick != NULL) {
       /* Not the same as a device index! */
       printf("    instance id: %d\n", SDL_JoystickInstanceID(joystick));
       printf("           axes: %d\n", SDL_JoystickNumAxes(joystick));
       printf("           hats: %d\n", SDL_JoystickNumHats(joystick));
       printf("        buttons: %d\n", SDL_JoystickNumButtons(joystick));

       /* I've _never_ seen this non-zero, if anyone has lemme know! */
       printf("     trackballs: %d\n", SDL_JoystickNumBalls(joystick));
       SDL_JoystickClose(joystick);
   }

}

You can use whatever mechanism you want to let the user pick the
joystick to open and use, of course. But there’s a new API in 2.0
involving the event loop you can use on everything except the Windows
MMJoystick driver which never did get updated for 2.0.1 and was not
nuked as Sam concluded it should be. :wink: This is regarded as a known
bug in 2.0.1, so on 2.0.2+ I can assure you it’s going to get fixed
one way or another because I’m going to be a PITA about it and fix it
myself if I have to. :wink: (Still working on the Windows build setup?)

For the purposes of example, I’m going to make some assumptions here
that you shouldn’t. Namely, I’m going to open the first Joystick SDL
gives us. So here’s a few globals:

int joystick_instance = -1;
SDL_Joystick * joystick = NULL;
SDL_bool quit = SDL_FALSE;

Then, assuming you have a typical init/loop/quit setup, do something
like this in the event processing of your loop:

SDL_Event event;

while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_JOYDEVICEADDED:
if (joystick == NULL) {
joystick = SDL_JoystickOpen(event.which);
joystick_instance = SDL_JoystickInstanceID(joystick);
/* You might want to query axes/buttons/etc here /
} /
else ignore it /
break;
case SDL_JOYDEVICEREMOVED:
/
Make sure we opened this joystick /
if (event.which == joystick_instance) {
/
We just lost our joystick /
joystick_instance = -1;
SDL_JoystickClose(joystick);
}
break;
case SDL_JOYAXISMOTION:
if (event.which == joystick_instance) {
printf(“axis %d value %d\n”, event.jaxis.axis,
event.jaxis.value);
} /
else it’s not a joystick we care about /
break;
case SDL_JOYHATMOTION:
if (event.which == joystick_instance) {
/
I’m not gonna parse SDL_HAT_CENTERED, etc here */
printf(“hat %d value 0x%02x\n”, event.jhat.hat,
event.jhat.value);
}
break;
case SDL_JOYBUTTONDOWN:
if (event.which == joystick_instance) {
printf(“button %d down\n”, event.jbutton.which,
event.jbutton.button);
}
break;
case SDL_JOYBUTTONUP:
if (event.which == joystick_instance) {
printf(“button %d up\n”, event.jbutton.which,
event.jbutton.button);
}
break;
case SDL_JOYBALLMOTION:
if (event.which == joystick_instance) {
printf(“ball %d motion: (%d, %d)\n”,
event.jball.ball, event.jball.xrel,
event.jball.yrel);
}
break;

       /* That's it for joystick-specific events */

       case SDL_QUIT:
           quit = SDL_TRUE;
           break;
       case SDL_KEYDOWN:
           switch (event.key.keysym.sym) {
               case SDLK_ESCAPE:
                   quit = SDL_TRUE;
                   break;

               /* Handle any other keys */

               default:
                   break;
           }
           break;
   }

}

if (quit) {
return false;
} else {
return true;
}

The GameController API works very similarly to the above, but is in
some ways simpler. Unfortunately, it’s in other ways it is slightly
more complicated. As you saw in the simple iterative dump, not all
joysticks are GameControllers. In fact, it’s possible that the XBox
360 controller is not a GameController, and that’s the thing upon
which the API is based! (So far as I can tell so far, Windows XP’s
driver for the thing does not use XInput, and the thing is crippled
in DirectInput mode because ? Microsoft.)

Anyway, IF you have a supported GameController, it’s very simple, as
this handy table illustrates. :wink:

Joystick API GameController API--------------------------------------------------------------------
SDL_Joystick * SDL_GameController *

SDL_NumJoysticks SDL_NumJoysticks w/ SDL_IsGameController
SDL_JoystickOpen SDL_GameControllerOpen
SDL_JoystickClose SDL_GameControllerClose
SDL_JoystickInstanceID ? Obnoxiously missing at present!
SDL_JoystickGetAxis SDL_GameControllerGetAxis
SDL_JoystickGetButton SDL_GameControllerGetButton
SDL_JoystickGetHat N/A, DPad is 4 buttons
SDL_JoystickGetBall N/A, not supported

SDL_JOYDEVICEADDED SDL_CONTROLLERDEVICEADDED
SDL_JOYDEVICEREMOVED SDL_CONTROLLERDEVICEREMOVED

  •                       SDL_CONTROLLERDEVICEREMAPPED (ignore it)
    

SDL_JOYAXISMOTION SDL_CONTROLLERAXISMOTION
SDL_JOYBUTTONDOWN SDL_CONTROLLERBUTTONDOWN
SDL_JOYBUTTONUP SDL_CONTROLLERBUTTONUP
SDL_JOYHATMOTION -
SDL_JOYBALLMOTION -

There is no SDL_GameControllerInstanceID (which is a lot to type), so
use SDL_JoystickInstanceID with SDL_GameControllerGetJoystick. See
what I mean about obnoxiously missing? :slight_smile:

So? As you can see, GameController is just a thin emulation layer on
top of the existing Joystick system. It could have (and you might
argue should have) been implemented as an extension library. The
reason why is the same reason why Microsoft is trying to force march
everyone to XInput: Standardization.

If you have a supported GameController, you can generally expect that
axis 0 and 1 are the left analog stick, axis 2 and 3 are the right
analog stick, and axis 4 and 5 are the left and right triggers. (The
triggers may be digital?returning 0 or 0x7fff.) You know that your
first four buttons are A, B, X, and Y (or as close a physical
approximation as the controller allows). You don’t need to provide
users with a control mapping screen?or at least, you can actually
assume sensible defaults!

Buttons may be missing (Guide often isn’t present for example), but
you can assign a function to them and be reasonably assured that
you’re going to get something sane. For a SNES emulator, you’d swap
A for B and X for Y, use the DPad, map LB/RB to L/R, Back to Select,
Start is, well, Start, and make Guide pause the emulator and pop up a
menu. You could possibly do something creative with the sticks and
triggers to handle save states, rewinding, etc, if you wanted.

If you do NOT have a supported device, you’ll need to add a mapping
yourself. We haven’t really discussed what to do with "partial"
mappings yet as a policy matter, but you can map anything vaguely
similar into a GameController. You might lose advanced functions
like motion controls and whatnot. SDL_GameControllerAddMapping and
SDL_HINT_GAMECONTROLLERCONFIG for you to add mappings SDL doesn’t
know about.

I’m going to propose some functions for handling controllers with
fewer buttons (fighter pads/sticks, retro controllers, etc) following
the XInput model at least?but XInput prior to Windows 7 will always
report that you have a full and complete XBox 360 controller, even if
you don’t. On any other platform, including Windows non-XInput, SDL
knows exactly what’s mapped and what’s not.

Joseph

On Thu, Oct 24, 2013 at 08:56:45AM +0000, zeha wrote:

Hello,

I try to create a game with SDL2 and I am able to open my joystick and also get the axis movement etc, but I don’t get any button presses. I tried it with 4 different gamepads (XBOX 360 controller, OUYA controller, Competition Pro USB, Trust EasyPlay), and while all of them were recognized and all of them yielded a positive result for SDL_JoystickNumButtons, with none of them I could get any button press or release events.

I tried with Event Polling, and I also tried with SDL_JoystickGetButton.
Btw, I used Xubuntu 13.04, haven’t tried it under Windows yet.

Another question: I also tried to understand the GameController library, but I don’t get it. How is that supposed to be used? I have absolutely no idea how this library works, even though I have read the wiki page a few times.

Okay thanks for your long reply :slight_smile: I will try that code tonight, but I fear that it’s basically the same as what I have also tried and it won’t work either. But I will let you know :slight_smile:

As for the GameController API: I haven’t realized that there are functions called SDL_GameControllerGetAxis and SDL_GameControllerGetButton, because I was just looking through the Wiki and they are not mentioned there. I think the Wiki is quite incomplete then?

Yeah, if you see some lazy albino around here, tell him to get moving
on that. And no excuses about having to go in for the 11 tubes of
blood he had to have drawn today, the drug study people’s concerns
that prompted it, the GF who said she was beginning to forget what he
looked like, or that whole desire to do that thing called sleep. :wink:

Nah, seriously, I’m working on it?I just need about 6 more hours in a
day at present.

(I’m also trying to get a working Windows mingw-w64/msys build setup,
figuring out if Windows XP can actually do XInput with an XBox 360
controller and how, upgrading the Mac to Mavericks, rewriting
testgamecontroller, rewriting testjoystick, and planning a tool that
will let an end-user map a GameController from an arbitrary joystick
without Steam? And that’s in addition to the real job, for which I
am not currently actually earning an income, but won’t be unless I
get some stuff done! Kind of a full plate?)

JosephOn Fri, Oct 25, 2013 at 08:57:16AM +0000, zeha wrote:

Okay thanks for your long reply :slight_smile: I will try that code tonight, but I fear that it’s basically the same as what I have also tried and it won’t work either. But I will let you know :slight_smile:

As for the GameController API: I haven’t realized that there are functions called SDL_GameControllerGetAxis and SDL_GameControllerGetButton, because I was just looking through the Wiki and they are not mentioned there. I think the Wiki is quite incomplete then?