Deviced added events for devices plugged in at game start

What is the behavior of controller device added events for devices that are already plugged in when the program starts? Is there documentation for this?

I would have expected that there wouldn’t be device added events, but it seems that there are. Here’s what I’ve seen. I’m using SDL 2.28.5.


I have a game controller that’s not in SDL’s database, but it is in SDL_GameControllerDB. In the tests below, I have my controller plugged in before starting the program.

#include "SDL.h"
#include "SDL_events.h"
#include "SDL_gamecontroller.h"
#include "SDL_joystick.h"

int main() {
	SDL_Event ev;

	SDL_Init(SDL_INIT_GAMECONTROLLER);

	printf("Detected %d joysticks.\n", SDL_NumJoysticks());

	SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt");

	while (SDL_PollEvent(&ev)) {
		switch (ev.type) {
			case SDL_JOYSTICKDEVICEADDED:
				printf("Adding device %02d. Is controller? %d\n",
					ev.jdevice.which,
					SDL_IsGameController(ev.jdevice.which)
				);
				break;
		}
	}

	return 0;
}

This prints:

Detected 1 joysticks.
Adding device 00. Is controller? 1

When I change the event handler to SDL_JOYSTICKDEVICEADDED, there is no event for the controller:

	while (SDL_PollEvent(&ev)) {
		switch (ev.type) {
-			case SDL_JOYDEVICEADDED:
+			case SDL_CONTROLLERDEVICEADDED:
				printf("Adding device %02d. Is controller? %d\n",
-					ev.jdevice.which,
-					SDL_IsGameController(ev.jdevice.which)
+					ev.cdevice.which,
+					SDL_IsGameController(ev.cdevice.which)
				);
				break;
		}

This prints:

Detected 1 joysticks.

When I loop forever, then unplug my controller and plug it in again, it is detected the second time.


Questions:

  • Can/should I rely on device added events for devices already plugged in?
  • When do the events get added to the queue? I guess during SDL_Init()?
  • Is there a way to make the devices recognized as GameControllers earlier?

I don’t remember if it was documented anywhere, but I used SDL2 and the joystick API in my engine. If I started the engine while my gamepad was already connected to the PC (or several), SDL would generate SDL_JOYDEVICEADDED events for each controller. Thanks to this, the engine could always correctly recognize the number of currently connected controllers. In my opinion, this is how SDL should behave.

However, I can’t help with the SDL Gamepad API — I’ve never used it and I don’t plan to use it, because I prefer my own implementation of the input mapper abstraction.

Yes, you should. But I don’t know why you are not receiving SDL_CONTROLLERDEVICEADDED events — I don’t know gamepad API. Try to initialize more SDL subsystems or even all of them to be sure that everything needed is initialized by the SDL (for tests only, later remove unnecessary subsystem initializations).

Probably there but It does not really matter. The only thing you should carry about is event processing somewhere in your main game loop, when you are processing the events.

When before? To find out if any joysticks or gamepads are connected when your game starts, you should process the event queue. If you want, you can do this before you start the main game loop. It all depends on your requirements and the architecture of your project.

Thanks. I ask because some guides online say that you don’t get events for devices already plugged in at start, like this one: Like It's Stolen... | Game Controller API in SDL2

I’m not sure if these are out of date or just flat out wrong, but since it’s not mentioned in the docs I wasn’t sure what the intended behavior is.

Well unfortunately in my case it does make a difference. :slightly_smiling_face: It seems like the events get added to the queue during Init(), and if I later make more devices recognized as game controllers, it’s too late to go back and change those events already in the queue.

Ok, that’s fine. I still have some questions about the Gamepad API though.

So it would be easy enough to say “Just move SDL_GameControllerAddMappingsFromFile() to before you do SDL_Init().” If that’s accurate, then I’d be happy to add that to the docs.

However, to reveal a bit more about my situation, I’m using rust-sdl, which seems to require initializing the GameController subsystem before it’s possible to update the GameController mappings. load_mappings() is a method of GameControllerSubsystem, and making the subsystem object requires initializing the subsystem. :slightly_frowning_face:

So maybe I should make a feature request to rust-sdl? Or is rust-sdl’s restriction reasonable?

This also affects LOVE games, where the subsystems all get initialized before your first line of code runs.

That is accurate. You can also set SDL_HINT_GAMECONTROLLERCONFIG_FILE before initialization, which might be a workaround in this case.

1 Like

Oh, that’s great, thanks!

I wrote some docs for this here. Please leave any suggestions or clarifications and I’ll do my best to address them. I’ll also backport this to SDL 2 after review.