🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

SDL2 - Unexpected Behavior When Hot Swapping Gamepads If One Or More Is Asleep

Started by
3 comments, last by Ansou 6 years, 9 months ago

I created a small test application where I handle the SDL_CONTROLLERDEVICEADDED and SDL_CONTROLLERDEVICEREMOVED events, and output information about the controller being added/removed, based on the information in this blog.

I have two controllers connected to my PC, an Xbox 360 controller and a Logitech controller. What I found is that if they are both active and awake it produces the expected output, but if either one or both of them are asleep, it outputs the wrong name under certain conditions. I don't want to be overly verbose and go over every configuration I tested, but one example is if I start the application with both controllers in sleep mode, it fires the SDL_CONTROLLERDEVICEADDED for the Logitech controller but not the Xbox controller at application startup (The event for the Xbox control only happens when it is awakened), and then when I unplug/plug in the Logitech controller's USB receiver, it shows the device name as "X360" every time, until I wake them both up, at which point it outputs the correct name again.

Perhaps I'm worrying too much about this, as most people probably don't mix and match controllers and likely only use one, but I just found it curious. I'm wondering if it might be a bug in SDL2, or if maybe there is some insight someone might have related to xbox controllers and how they behave in sleep mode.

 

Here is the relevant code if anyone's interested:


struct SdlGamepad
{
	SDL_GameController*	controller;
	SDL_Joystick*		joystick;
	SDL_JoystickID		joystickId;
	std::string		deviceName;
	int			deviceId;
};



std::map<SDL_JoystickID, SdlGamepad> joystickIdToGamepadMap;

SDL_Event event;

bool hasQuit = false;

while (hasQuit == false)
{
	while (SDL_PollEvent(&event))
	{
		switch (event.type)
		{
			case SDL_CONTROLLERDEVICEADDED:
			{
				std::cout << "Controller device added." << std::endl;

				if (SDL_IsGameController(event.cdevice.which))
				{
					SdlGamepad gamepad;

					gamepad.controller = SDL_GameControllerOpen(event.cdevice.which);
					gamepad.joystick = SDL_GameControllerGetJoystick(gamepad.controller);
					gamepad.joystickId = SDL_JoystickInstanceID(gamepad.joystick);

					std::string deviceName = SDL_GameControllerName(gamepad.controller);

					gamepad.deviceName = deviceName;
					gamepad.deviceId = event.cdevice.which;

					joystickIdToGamepadMap[gamepad.joystickId] = gamepad;

					std::cout 
						<< "Controller device name = " << gamepad.deviceName << std::endl
						<< "Controller device ID = " << gamepad.deviceId << std::endl
						<< "Joystick device ID = " << gamepad.joystickId << std::endl << std::endl;

				}

				break;
			}
			case SDL_CONTROLLERDEVICEREMOVED:
			{
				std::cout << "Controller device removed." << std::endl;

				SdlGamepad gamepad = joystickIdToGamepadMap[event.cdevice.which];

				std::cout
					<< "Controller device name = " << gamepad.deviceName << std::endl
					<< "Controller device ID = " << gamepad.deviceId << std::endl
					<< "Joystick device ID = " << gamepad.joystickId << std::endl << std::endl;
  
				SDL_GameControllerClose(gamepad.controller);

				joystickIdToGamepadMap.erase(event.cdevice.which);
  
				break;
			}
			case SDL_QUIT:
			{
				hasQuit = true;
				break;
			}
		}
	}
}

 

Advertisement

It seems to be a known misunderstanding of SDL API. Your joystickIdToGamepadMap is written and read with incoherent indices from different event types.

See https://discourse.libsdl.org/t/controllerdeviceremoved-which-increments-on-each-unplug/21019/2

 

 

Omae Wa Mou Shindeiru

Perhaps I'm misunderstanding. I'm using the joystick ID as the map key, obtained as the above link says, by calling SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(myController)), albeit factored out into multiple lines. Is that not correct?

Your code looks right. The code that is relevant for this particular can be condensed to:


SDL_Event event;
while (SDL_PollEvent(&event))
{
  switch (event.type)
  {
    case SDL_CONTROLLERDEVICEADDED:
    {
      std::cout << "Controller device added." << std::endl;
      if (SDL_IsGameController(event.cdevice.which))
      {
        auto controller = SDL_GameControllerOpen(event.cdevice.which);
        std::cout << "Controller device name = " << SDL_GameControllerName(gamepad.controller) << std::endl;
      }
      break;
    }
  }
}

This should still reproduce the same problem. If it does, I suggest that you report this as a bug in SDL.

This topic is closed to new replies.

Advertisement