(Today’s article is by Alan Uthoff, the CEO and Founder of Swordpoint Studios, LLC. He is a Senior Programmer with over 14 years of experience developing games and leading teams. Alan has extensive experience designing, creating, debugging, and evaluating the quality of software. He is the creator of the open-source controller library Freestick, which is used in commercial engines. His knowledge in controller development is hard-earned and will assuredly be of assistance in your development journey.)
Swordpoint Studios, LLC: https://www.swordpointstudios.com/
FreeStick: https://bitbucket.org/freestick/freestick/src/master/
In the Beginning
Game controllers have been with gamers since the dawn of games but have been a thorn in the side of developers for just as long. Controller support in-game can sometimes make or break a game when the gameplay does not lend itself to the keyboard and mouse.
Developers have had to deal with coding for custom controllers over custom ports requiring new code when porting the game to new systems. With the advent of Universal Serial Bus (USB) and Human Interface Device (HID), developers got a much-needed break where the Operating System (OS) would take over the job of talking to the controllers and free up the developer to only interface with the OS.
A Fractured World
However, there was still a fracture between how controllers were made and the Application Programming Interface (API) developers needed to interface with. Game Controllers are no more than a set of analog systems that report movement converted to a digital range of numbers. With analog sticks, for example, the range of values produced from the right to left movement can vary wildly from one manufacturer to another.
Let’s look at the D-pad, a set of buttons that denote up, down, left, or right. One may think that they would be separate buttons. Still, on some controllers with eight-way, they are a hat stick where instead of four individual elements with values from 0 to 1, they are expressed as one element with eight values representing down and one representing up.
Technical Note
The USB Implementers Forum, Inc publishes an HID usage table that defines codes called a usage page, and usage IDs that provide context for the HID elements. For example, on the usage page “Generic Desktop,” there is a D-pad-up code that states: “Indicates the top of a Direction Pad is pressed.” This hint should help sort out what the element does, however manufacturers don’t follow this very often, nor are they required to.
On the Software Side of Things
While all the operating systems (Mac, Windows, Linux, etc.) had HID APIs, some, like Windows, built API on top of HID making development on that OS easier, but had an unfortunate side effect; it required more code to be written when porting the game to other systems. Others left the support at the HID layer, which requires more knowledge of the lower level. These older APIs are Windows Direct Input, macOS: IOKit/IOHIDManager, and Linux Input.h. They required developers to have a custom map that lays out what controller element ranges map to different button presses, for example allowing the top right button to be identified as the right trigger.
Fast forward to today. Most OS have added new APIs built at a higher level that requires hardware manufacturers to create controllers according to a standard. This allows the API to use the standard to define the top right button as a trigger button in code no matter the hardware. These new APIs are Windows Direct X, macOS/iOS GameController/MFI, and Linux hidraw/hiddev, and Android InputDevice API.
While these APIs provide a way for developers to interface with the hardware more easily, it leaves much older controllers incompatible with the newer APIs. This has left the developers with a choice: use the newer APIs but only support newer controllers, support older API and lose support for some newer controllers, or try to support both.
It Better Be X
On the hardware side, many game controller manufacturers have opted to support the XInput style of the controller (Xbox 360), which has helped standardize the layout and button mapping. Still, when this started it left other OS out in the cold. For example, macOS relied on third-party drivers to support XInput controllers for many years, and only recently did Apple support newer XInput controllers (Xbox One and One S).
Most have chosen the first route leaving many gamers forced to spend money on new XInput controllers for better or worse. So what is a game developer to do when they want controller support and don’t want to spend hours dealing with different APIs in different languages and have to test all the supported controllers?
The Light at the End
Thankfully there are existing cross-platform libraries (lib) and engines that can assist developers with their game’s controller support. However, not all of the systems are created equally. Here are some things to keep in mind when choosing a lib/engine:
- Ensure the analog stick values are a float. Not all analog sticks use the same range of values, and the stick values must map to a standard range
- Eight-way controllers should report as buttons, not as a hat stick
- Bonus if they can support the older and newer APIs at the same time
At the End of the Wire
We have come a long way from having to code so close to the hardware to get controller support in games. With the advent of higher-level API and hardware standards, it is getting easier to work with game controllers and requiring less platform-specific code. However, until there is better unification across the platform’s APIs it is still best to work with a controller library or engine.
Here’s a list of a couple of cross-platform controller libraries and their pros and cons:
- Pros:
- Simple to use
- Supports older and new game controller APIs at the same time
- Platforms: macOS, Windows, iOS, and Android
- Analog stick values are mapped to a float for a common range
- Cons:
- Does not support force feedback on controllers or Linux
- Does not support touchpads on controllers
- Pros:
- Supports most controllers and platforms
- Simple API to use
- Has binding for many programming languages
- Supports force feedback and touchpads on controllers
- Cons:
- It does more than controllers and requires more of the lib to be included than just the controllers
- May not support more than one API at the same time
- Analog value range int values and may not map well to some controllers