The SDL Game Controller API supports two shoulder triggers in addition to the two shoulder buttons. They are considered axes, not buttons.
On some controllers, like Nintendo Switch or bitdo, the shoulder triggers are implemented as digital buttons, not analog axes. In the game controller config, this is reflected by a mapping to :b10 or some such instead of :a6 for example.
What is a portable way to read such buttons? Should I check for an axis value not equal to 0? It seems to work that way, but wouldn’t an actual analog trigger cause erroneous readings then? Is there a runtime function to check whether the current platform uses true analog triggers, or uses digital ones?
Hi,
I know this post is rather old and SDL3 is on its way, but I just stumbled across the same issue and found out a possible workaround:
SDL_ControllerButtonEvents are not raised for the triggers (even if they are buttons, not axes)
SDL_JoyButtonEvents are in fact raised for the left and right trigger buttons, but the mapping is missing (SDL_GameControllerGetBindForButton returns a SDL_CONTROLLER_BINDTYPE_NONE)
In order to get the correct mapping, use cSDL.SDL_GameControllerGetBindForAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT). This will return a button binding with the respective joystick button number.
This requires some manual mapping, but seems to work around the problem.
I don’t know the reasoning behind why the “Trigger” buttons are mapped as axis instead of a button, there probably are some important controllers out there with variability in how far they are pressed or something.
In SDL2 you can detect a trigger event under a controller axis event. If I remember correctly, you can use event.caxis.axis to tell which axis in this list the event originated from.
In SDL3 the controller API is now named gamepad. The triggers are still axis/axes, and it can be detected in SDL_EVENT_GAMEPAD_AXIS_MOTION under event.gaxis.axis and here’s the list of possible values.
I check the value of the trigger axis on axis events and set a bool variable to communicate whether it is in a pressed or released state. I have a few different cheap controllers for testing and find the button mappings make controller/gamepad API simpler to work with than the joystick API.
Good controllers, like those for Xbox and PlayStation, have triggers that are more like analog sticks — you can change their position gradually. To be able to know how “deep” the trigger is pressed, the trigger must be represented as axis with a large range of possible values. And in most (or even all) cases, the range is 15-bit — positive for one trigger and negative for second trigger.
Some simpler and/or cheaper controllers have triggers that behave like buttons (e.g. 8bitdo SN30 Pro), so there are only two possible states — released (value 0) or pressed (value +/-32767).