"SDL2 Game Controller API Revisited"

Posted by Ryan C. Scott on Sat 03 December 2016

Further time with the API has led me to some realizations regarding the game controller API. It's just as useful as I had initially thought, but geared towards solving a slightly different problem than I had assumed. Largely because I wasn't paying enough attention.

Once More Unto the Breach

Alright kids, you get all buckled up, because this is, obviously, going to be super exciting to read about. It may change you. Probably will. Prolly never be the same in fact.

Expect:

  1. Thrills
  2. Excitements
  3. Trade Secrets
  4. Something to Distract You From This, The Most Terrible of Years

Mappings

Initially it seemed to me that the mapping functionality provided by SDL_GameControllerAddMapping* was meant to be used by games\/applications to provide player remapping of inputs.
The mapping format takes a controller GUID (which is unique to the controller type/manufacturer and not to the controller itself) and a list of raw inputs that map to conceptual buttons that are more or less the ubiquitous Xbox360 layout.

Here's a few entries from the mapping "Database" that you can find on GitHub

# Windows - DINPUT
8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,
341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,

The mapping format allows for specifying thresholds on axes, etc. A proper description can be found in the SDL2 documentation You may also have noticed that the platform is called out here. You can safely provide mapping for all platforms in a single file and SDL2 will ignore any irrelevant data for the current platform.

And the code to load this file, or multiple files for that matter, is:

SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );

I think it was the ability to map an axis to a button that initially made me think it was a layer for doing application specific input mapping. I've come to realize that the intended purpose of that interface is to expand the ability to support a lot of different hardware cleanly.
That is, normalizing all controller input into a handful of symbolically named inputs that an application can handle.

At this point you will be receiving controller input events with these logical buttons/axes:

SDL_CONTROLLER_AXIS_LEFTX
SDL_CONTROLLER_AXIS_LEFTY
SDL_CONTROLLER_AXIS_RIGHTX
SDL_CONTROLLER_AXIS_RIGHTY
SDL_CONTROLLER_AXIS_TRIGGERLEFT
SDL_CONTROLLER_AXIS_TRIGGERRIGHT

SDL_CONTROLLER_BUTTON_A
SDL_CONTROLLER_BUTTON_B
SDL_CONTROLLER_BUTTON_X
SDL_CONTROLLER_BUTTON_Y
SDL_CONTROLLER_BUTTON_BACK
SDL_CONTROLLER_BUTTON_GUIDE
SDL_CONTROLLER_BUTTON_START
SDL_CONTROLLER_BUTTON_LEFTSTICK
SDL_CONTROLLER_BUTTON_RIGHTSTICK
SDL_CONTROLLER_BUTTON_LEFTSHOULDER
SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
SDL_CONTROLLER_BUTTON_DPAD_UP
SDL_CONTROLLER_BUTTON_DPAD_DOWN
SDL_CONTROLLER_BUTTON_DPAD_LEFT
SDL_CONTROLLER_BUTTON_DPAD_RIGHT

You'll need to create your own layer mapping these controller inputs into application specific meanings, including providing any input remapping based on player preferences.

What This Means In Usage

The short version is that you should grab the database of mappings from GitHub and load that as a part of your application startup.

In the startup of my engine I load from the bundled copy of that file, and then from a location in the user's application data.

My thinking being that a user could, in a pinch, provide their own mappings to support other controllers. A utility for creating mapping strings can be found here

Steam Integration

There's a one-line note in the SDL2 documentation regarding running from within Steam. From what I've deduced Steam will set environment variables for applications that it runs that SDL2 will internally read use during it's own startup. In this way the controller mapping may be handed to your application from Steam itself and much of what we're talking about here will be fairly irrelevant. My guess is that this feature is to handle the Steam Controller (which I am completely in love with btw).

What Might Be Nice Eventually

I would love for the input handling code that SDL2 has for maintaining these mappings and doing the button<->axis conversions to be exposed in a way that it could be used for doing the application/user specified mapping of input. Player controller code has an amazing capacity for being quirky, incomplete, and filled with magic values that were shoved in to make things feel good. Recreating similar mechanisms is doable, but it seems like a doubling of effort may be occurring somewhere.

In Conclusion

I feel weak from the aforementioned excitement and thrills, to say nothing of the Trade Secrets/other stuff.