You Can’t Just: Query if a controller is for Xbox or PlayStation


I’m currently on a bit of holiday leave from my full-time web dev gig and I wanted to spend some time improving the gamepad support in my newly released puzzle game, Give Up The Dupe.

I wanted to detect if a user is using a fairly modern Xbox or PlayStation controller and then make the in-game instructions be more precise for those controllers. It’s a much smoother experience for the end-user if a game says “Press A to Jump” rather than saying “Press Button0 to Jump” or “Press [JUMP ACTION] to Jump”.

After some initial investigation, the first thing I thought to do was call one of these functions to get the gamepad name:

  • Game Maker: gamepad_get_description(0)
  • Ebiten: ebiten.GamepadName(0)
  • GLFW: glfwGetJoystickName(0)
  • SDL2: SDL_GameControllerNameForIndex(0)
  • Browsers: navigator.getGamepads()[0].id

You might think that we would be able to at least fuzzily determine what controller we are using with these functions but unfortunately it’s not that simple. As you can see with the examples below, you’re at the mercy of your driver, engine or browser when it comes to getting a name for your gamepad.

For example, my unofficial Xbox One Controller gave me these string values:

  • Windows/GLFWv3.2: “Xbox 360 Controller”
  • Windows/GLFWv3.3: “Xbox Controller”
  • Windows/Game Maker: “XInput STANDARD GAMEPAD”
  • Windows/Chrome: “Xbox 360 Controller (XInput STANDARD GAMEPAD)”
  • Windows/Firefox: “xinput”

My official PlayStation 4 controller gave me these values:

  • Windows/GLFW: “Wireless Controller”
  • Windows/Game Maker: “Sony DualShock 4”
  • Windows/Chrome: “Wireless Controller (STANDARD GAMEPAD Vendor: 054c Product: 09cc)”
  • Windows/Firefox: “054c-09cc-Wireless Controller”

Detecting the controller type via this string is probably not going to end up not being very reliable for PlayStation controller cases, especially in browsers.

Oh well. At least the controller layout of a modern Xbox and PlayStation controller is identical, so I should be able to map some reasonably good default controls. ie. “A” to Jump on a Xbox controller, “X” to Jump on a PlayStation controller.

If you use Game Maker or SDL2, you get a nice abstraction that allows you to achieve this easily, but unfortunately for us, we’re using a low-level gamepad API. This means that each gamepad could have up to 32 buttons and the “A” button on an Xbox controller could be mapped between 0 and 31, the same goes for a PlayStation controllers “X” button. There is no guarantee these two controllers will use the same button slot.

In reality, you’ll find that most or all Xbox controllers will map the “A” button to “Button 0” on a gamepad and all other buttons generally map to the same slots across various Xbox controllers. Unfortunately, a PlayStation controller will map the “X” button to the following button slots:

  • PlayStation 4 controller: “Button 1” on Windows, “Button 0” for iOS.
  • PlayStation 3 controller: “Button 0” or “Button 1” on Windows
  • PlayStation 1 or 2 controller: “Button 2” on Windows

This means that we can make a good default user-experience for players that use an Xbox controller but we cannot make any assumptions about PlayStation controllers that will “just work”. It’ll take some more dev. effort to provide first-class support for those.

So, assuming we are willing to do the work, what can we do? Well, thankfully there is an open-source controller mapping database that we can leverage! In-fact its the same data utilized by SDL2’s higher-level gamepad API. This means we don’t need to buy a bunch of different controllers and test them, other people have donated their time and effort to give us more mappings than we could have ever reasonably achieved by ourselves. Yay community!

So we have a large set of controller mappings thats regularly updated. How can we use this? Well, on most platforms there is a function that gives us the controllers GUID, which looks something like this for my respective controllers.

  • Xbox One Controller: 78696e70757401000000000000000000
  • PlayStation 4 Controller: 030000004c050000cc09000000000000

The above values were taken from glfw 3.3 for Go. I also tested calling Game Maker Studio 2’s equivalent function gamepad_get_guid(id). My Xbox One Controller returned an empty string and the PlayStation 4 Controller returned the same GUID as above.

Anyway moving on. We can utilize these GUID values by searching through the aforementioned controller mapping database. In my searches, I discovered that:

  • The Xbox One Controller does not have a mapping that matches my GUID (and with engines like Game Maker, I just get an empty string!)
  • The PlayStation 4 Controller does have a mapping that matches my GUID

With these facts in mind, if we really want to support PlayStation controller mapping by default, we can load this open-source file of game controller data, use that to determine button defaults and infer the controllers shape, which would allow us to display more accurate controls on screen for PlayStation controller users.

So… at a high-level, To get both Xbox and PlayStation controllers supported, I think we want a solution that does something like:

  • Lookup GUID in this community-sourced gamepad mapping list. You probably want to make this file embeddable into your code so it easy to update later down the line. Infact, its worth noting that SDL2 already embeds this exact code into its high-level gamepad drivers.
  • Check the name associated with the GUID in the text file to determine if its a Xbox or PlayStation controller.
  • Fallback to using a function like glfwGetJoystickName or gamepad_get_description and checking if the name contains words like “Xbox”. We will need this logic if we want Xbox controllers to be detected as we may not even get a GUID for certain controllers or on certain platforms.
  • If we are unable to detect the controllers shape, then fallback to standard gamepad mode and just display buttons as “[JUMP ACTION]” or “Button0”.

Please keep in mind I’ve not implemented and shipped something like this yet, so I’m not sure if there are problems with this method that I’m not foreseeing. In anycase, attempting to do this small quality of life change ended up being a much bigger rabbithole than I expected, so I thought it was important to share what I discovered during this exploration.

Get Give up the Dupe

Buy Now$3.00 AUD or more

Leave a comment

Log in with itch.io to leave a comment.