Android GamePad vs. Desktop (Assertions)

I have a small open source Quake 1 project with multi-touch support for Android developed with SDL 2.0.8 QuakeDroid.

It has gamepad support added in a beta-build Gamepad Beta Support. The basis of the gamepad support was derived from the Quake 1 port SDL2 port Quakespasm.

The usage of the SDL2 functions in Android is quite different than the SDL2 functions on the desktop platforms.

Functions like SDL_IsGameController simply don’t work, I found that I needed to substitute the SDL_Joystick functions for SDL_GameController functions and that I had to use the joystick events for buttons instead of being able to check the state of the buttons at any time.

That being said, the gamepad support for Android in SDL2 is great.

Although I have 3 mysteries which I have not solved.

  1. Connecting or disconnecting a bluetooth game controller resets the application. Connecting or disconnecting a bluetooth keyboard does not do this.

  2. On rare instances that appear to be related to sleeping the phone — but I have found no exact pattern, I get an “Assertion Failed” messagebox asking for “Abort Retry” that occurs in SDL_video.c. Is there a way to get it to just do “abort”? The docs on SDL_Assertion seem to indicate this should not happen in a release build, but I just switched from ant to gradle for SDL2 2.0.8 and have not 100% validated all the gradle build settings.

  3. Does SDL 2.0.8 support a landscape mode for Android? A cursory search suggests this not supported at this time.

Hi Baker, a brief reply, since no one else has chipped in yet:

GameController functions only work with USB joysticks that have mapping information, like the XBOX360. I purchased a bunch of cheap controllers from China and none of them are mapped. So yes, the best thing to do is open with the SDL_Joystick functions. I set up a handler that uses both controllers and joysticks depending on if they’re mapped and did my own mapping for plain joysticks. I believe the idea behind this is for Steam, which has a comprehensive database of mappings and users can submit their own mapping for custom controllers and Steam supply the mapping if your game is run from that markeplace. This doesn’t really work in practice because none of my controllers are mapped there, either.

My game runs in landscape on Android - I’m not currently sure how to change it - It doesn’t rotate to portrait. But I do know all of that is configurable.

Last time I tried a Bluetooth game controller (PS2) was 2.0.4 and it worked fine.

Hi Alchemist, thanks!

I see, different intentions/controller type targets. The native Android controllers work fine several beta testers have said with just the Joystick functions.

Perhaps fitting with your description, those that have tried using console or desktop game controllers on Android haven’t been able to get them to work completely or with mixed results.

Based on the information you supplied, maybe those will even work if I use the GameController functions for the PC or console game controllers. Or at least the popular ones that seem to be built-in for SDL2 in the source code like XBox ones.

re:Landscape “But I do know all of that is configurable.”

I haven’t tried to do native Landscape too hard yet, but at least I now know it should be possible.

If you just use the joystick functions you won’t necessarily know the layout of the controller (is this axis a thumbstick? a trigger? who knows?)

I made a change so most controllers should work correctly with the game controller API on Android.

Can you try it out and let me know how it works for you?



Back when I was using SDL 2.0.4 I found joystick buttons were giving different values (sometimes very odd / random ones) under Android compared to Windows, which might be the problem. Often the button index will be +20 on Android, so I hacked a fix that would just -20 if button value was >20, but it didn’t fix everything because it wasn’t consistent across all the different controllers. There was no pattern to the oddness. Now I have it all working in SDL 2.0.8 I haven’t tested, but I’m guessing it’s the same. I’ll also try slokuen’s solution when I get time (what change you make, slokuen?).

Actually, here are my notes on the button indexes:

Gamecube PC:
A = 1
B = 2
X = 0
Y = 3
Start = 9
UDLR = 12, 14, 15, 13
L-shoulder = 4
R-shoulder = 5
Z = 7

Gamecube Android:
L-shoulder = 24
R-shoulder = 25
UDLR = 32, 34, 35, 33
Start = 29
buttons = 20-23
Z = 27

impact PC:
buttons = 0 - 3

impact Android:
buttons = 0 - 2 & 17 ?!

Vinyson CP:
L-shoulder = 4 & 6
R-shoulder = 5 & 7
buttons = 0 - 3
L-stick = 10
R-stick = 11
Start = 8 & 9

Vinyson Android:
L-shoulder = 24 & 26
R-shoulder = 25 & 27
L-stick = 30
R-stick = 31
buttons = 20 - 23
Start = 28 & 29

UDLR 11, 12, 13, 14
L-shoulder = 9
R-shoulder = 10

XBOX Android: n/a

Sega PC:
L-shoulder = 4
R-shoulder = 5
buttons = 0 - 3

Sega Android:
buttons = 20 - 23
L-shoulder = 24
R-shoulder = 25

When using the joystick interface it’s also safe 95% of the time to assume that axis 0 is X and axis 1 is Y; any axis beyond that are pretty random across controller designs. I think it’s better to make this assumption rather than not support unmapped controllers at all. Best solution is to use SDL’s controller mapping, and then backup with an assumed mapping for plain joysticks.

Back to portrait / landscape. It’s really easy. Look at AndroidManifest.xml:


It’s that easy.

I’ll try it out.

Just a note: I have an Xbox One S Controller (wireless, white) and it pairs with Android easy. Current SDL 2.0.8 returns SDL_IsGameController(index) false for this controller and it also has no name. With the SDL2 joystick functions, the controller works except 2 buttons (LTRIGGER, RTRIGGER) which I made some slight changes in my code to cause them to work.

Anyway, I’ll try out the zip you provided and see how it goes and provide feedback.

For reference, Eric_Wasylishen is whose code I was adapting, I know he has interacted here for years.


I tried SDL 2.0.8-11953.

My wireless Xbox One S Controller responds to SDL_IsGameController (index) as false, which as I understand it means it is unrecognized for the SDL2 GameController functions.

My initialization of the game controller code looks like this:

if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) == -1) {
	Con_WarningLinef ("could not initialize SDL Game Controller");
	return false;

{  int n; for (n = 0; n < SDL_NumJoysticks(); n++) {
	const char *joyname = SDL_JoystickNameForIndex (n);
	if (SDL_IsGameController(n) ) {
		alert ("%s is a game controller", joyname);
	else {
		alert ("%s is not a game controller", joyname);
	/* proceed to use use SDL2 joystick functions*/

I only have on console controller (the Xbox One S controller) and I have 1 Android controller (EVO VR gamepad). Both do work ok with the SDL2 joystick code.

(I do get a name [SDL_JoystickNameForIndex] for the Xbox One S Controller, “Broadcom Bluetooth HID” – it just doesn’t match what I see in Android->Settings->Bluetooth where it shows as "Xbox Wireless Controller.)