Sign in to follow this  

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

Recommended Posts

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;
			}
		}
	}
}

 

Share this post


Link to post
Share on other sites

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?

Share this post


Link to post
Share on other sites

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.

Edited by Ansou

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Forum Statistics

    • Total Topics
      628686
    • Total Posts
      2984236
  • Similar Content

    • By alex1997
      Hey, I've a minor problem that prevents me from moving forward with development and looking to find a way that could solve it. Overall, I'm having a sf::VertexArray object and looking to reander a shader inside its area. The problem is that the shader takes the window as canvas and only becomes visible in the object range which is not what I'm looking for.. 
      Here's a stackoverflow links that shows the expected behaviour image. Any tips or help is really appreciated. I would have accepted that answer, but currently it does not work with #version 330 ...
    • By Grumn Gaming
      I have a simple openGL engine using SDL working. I'm not using any SDL_Image stuff, its all just openGL. I've made 2d tilemap levels with a .txt file before by reading in the characters and using a switch statement to assign them to various textures and using their position in the file to render them. This method works fine and produces no graphical glitches.
      Then I made a .tmx map in Tiled and used TmxParser to read the file into my program, and I'm able to render the map properly to the screen, but when I move up and down these black lines start to appear between the tiles.
      The map loads in fine at first, its only once I start moving the camera around that it happens, and its only when the camera moves up or down.
      I made a video to show exactly what I'm seeing, I see a lot of these type of issues when searching google but nothing that matches whats happening to me.
      https://www.youtube.com/watch?v=bm6DcJgCUKA
      I'm not even sure if this is a problem with the code or what it could be so I don't know of any code to include.
      This problem also happened to me when I was using Unity and importing a Tiled map with Tiled2Unity. In unity there were long horizontal line glitches on the tilemap, and now its happening to me again in c++, is this something to do with Tiled?
      Has anyone encountered this before or know a solution?
      Any help would be greatly appreciated, I feel stuck on this issue.
       
    • By CodeBro1
      I can't get SDL to make any rectangles on my Mac. The program I wrote worked completely fine on a Windows computer, but whenever I call the SDL_FillRect function on my Mac, nothing appears on the screen. I suspect this may be caused by a compilation issue. I'm using SDL through Frameworks. Inserted below is my terminal command and my code:
      g++ example.cpp -I/Library/Frameworks/SDL2.framework/Headers -F/Library/Frameworks -framework SDL2 #include <SDL2/SDL.h> #include <iostream> #include <stdio.h> const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; const int PLAYER_WIDTH = 20; const int PLAYER_HEIGHT = 20; SDL_Window* w = NULL; SDL_Surface* s = NULL; SDL_Renderer* r = NULL; SDL_Rect BG = {0,0,SCREEN_WIDTH,SCREEN_HEIGHT};   bool init() {     if (SDL_Init(SDL_INIT_VIDEO) < 0) {         printf("Couldn't initialize. error: %s\n", SDL_GetError() );         return false;     } else {         w = SDL_CreateWindow("test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);         if(w == NULL) {             printf("Couldn't make window. error:%s\n", SDL_GetError() );             return false;         } else {             s = SDL_GetWindowSurface(w);             r = SDL_CreateRenderer(w,-1,SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);             SDL_SetRenderDrawColor(r,0,0,0,0);             return true;         }     } } void close() {     SDL_FreeSurface(s);     SDL_DestroyWindow(w);     SDL_DestroyRenderer(r);     SDL_Quit(); } class Player {     private:         int x;         int y;         int xvel;         int yvel;         int acceleration;         SDL_Rect collider;     public:         bool landed;         Player() {             x = 0;             y = SCREEN_HEIGHT - PLAYER_HEIGHT;             xvel = 0;             yvel = 0;             acceleration = -1;             collider.x = x;             collider.y = y;             collider.w = PLAYER_WIDTH;             collider.h = PLAYER_HEIGHT;                         landed = true;         }         int getx() {             return x;         }         int gety() {             return y;         }         void setx(int num) {             x = num;         }         void sety(int num) {             y = num;         }         void setyvel(int num) {             yvel += num;         }         void setxvel(int num) {             xvel += num;         }         void move() {             x += xvel;             if( (y + PLAYER_HEIGHT) > SCREEN_HEIGHT) {                                  y = SCREEN_HEIGHT - PLAYER_HEIGHT;                 yvel = 0;                 landed = true;             } else {                 if(landed != true) { //so sorry for the bad code, this was the only idea i had to debug "bouncing" of the player                     y += yvel;                     yvel = yvel - acceleration;                 }                              }                          collider.x = x;             collider.y = y;         }         void render() {             SDL_SetRenderDrawColor(r,255,255,255,255);             SDL_RenderFillRect(r,&collider);             SDL_SetRenderDrawColor(r,0,0,0,255);         } }; int main(int argc, char *argv[]) { bool quit = false; SDL_Event e; //event for event polling Player p; int count = 0;     if(init() == false) {         printf("Init failed: %s\n", SDL_GetError());     } else {         while(quit == false ) {             while( SDL_PollEvent(&e) != 0) {                 if(e.type == SDL_QUIT) {                     quit = true;                 }                                  if(e.type == SDL_KEYDOWN) {                     switch(e.key.keysym.sym) {                         case SDLK_LEFT: if(e.key.repeat == 0) { p.setxvel(-10); }                         break;                         case SDLK_RIGHT: if(e.key.repeat == 0) { p.setxvel(10); }                         break;                         case SDLK_UP:                         if(count < 5) {                             p.setyvel(-3);                             ++count;                             }                             p.landed = false;                                                  break;                     }                 }                                  if(e.type == SDL_KEYUP && e.key.repeat == 0) {                     switch(e.key.keysym.sym) {                         case SDLK_LEFT: p.setxvel(10);                         break;                         case SDLK_RIGHT: p.setxvel(-10);                         break;                         case SDLK_UP: count = 0;                         break;                     }                 }                              }             SDL_RenderClear(r);             SDL_RenderFillRect(r,&BG);             p.move();             p.render();                          SDL_RenderPresent(r);         }     }     close(); Please help me to get it working, I have no idea what's going on. I have SDL 2.0.7 and my Mac is OS X 10.10.3.
    • By CodeBro1
      SDL isn't drawing any rectangles to the window in a Mac OS X environment, and I have no idea why. I've tried in both a Windows and an Ubuntu environment, and the rectangles are being drawn in those environments. I'm using SDL by using frameworks. This is what I write into the terminal:

      g++ example.cpp -I/Library/Frameworks/SDL2.framework/Headers -F/Library/Frameworks -framework SDL2
      This is the actual code of the program:

      #include <SDL2/SDL.h> #include <iostream> #include <stdio.h> const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; const int PLAYER_WIDTH = 20; const int PLAYER_HEIGHT = 20; SDL_Window* w = NULL; SDL_Surface* s = NULL; SDL_Renderer* r = NULL; SDL_Rect BG = {0,0,SCREEN_WIDTH,SCREEN_HEIGHT};   bool init() {     if (SDL_Init(SDL_INIT_VIDEO) < 0) {         printf("Couldn't initialize. error: %s\n", SDL_GetError() );         return false;     } else {         w = SDL_CreateWindow("test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);         if(w == NULL) {             printf("Couldn't make window. error:%s\n", SDL_GetError() );             return false;         } else {             s = SDL_GetWindowSurface(w);             r = SDL_CreateRenderer(w,-1,SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);             SDL_SetRenderDrawColor(r,0,0,0,0);             return true;         }     } } void close() {     SDL_FreeSurface(s);     SDL_DestroyWindow(w);     SDL_DestroyRenderer(r);     SDL_Quit(); } class Player {     private:         int x;         int y;         int xvel;         int yvel;         int acceleration;         SDL_Rect collider;     public:         bool landed;         Player() {             x = 0;             y = SCREEN_HEIGHT - PLAYER_HEIGHT;             xvel = 0;             yvel = 0;             acceleration = -1;             collider.x = x;             collider.y = y;             collider.w = PLAYER_WIDTH;             collider.h = PLAYER_HEIGHT;                         landed = true;         }         int getx() {             return x;         }         int gety() {             return y;         }         void setx(int num) {             x = num;         }         void sety(int num) {             y = num;         }         void setyvel(int num) {             yvel += num;         }         void setxvel(int num) {             xvel += num;         }         void move() {             x += xvel;             if( (y + PLAYER_HEIGHT) > SCREEN_HEIGHT) {                                  y = SCREEN_HEIGHT - PLAYER_HEIGHT;                 yvel = 0;                 landed = true;             } else {                 if(landed != true) { //so sorry for the bad code, this was the only idea i had to debug "bouncing" of the player                     y += yvel;                     yvel = yvel - acceleration;                 }                              }                          collider.x = x;             collider.y = y;         }         void render() {             SDL_SetRenderDrawColor(r,255,255,255,255);             SDL_RenderFillRect(r,&collider);             SDL_SetRenderDrawColor(r,0,0,0,255);         } }; int main(int argc, char *argv[]) { bool quit = false; SDL_Event e; //event for event polling Player p; int count = 0;     if(init() == false) {         printf("Init failed: %s\n", SDL_GetError());     } else {         while(quit == false ) {             while( SDL_PollEvent(&e) != 0) {                 if(e.type == SDL_QUIT) {                     quit = true;                 }                                  if(e.type == SDL_KEYDOWN) {                     switch(e.key.keysym.sym) {                         case SDLK_LEFT: if(e.key.repeat == 0) { p.setxvel(-10); }                         break;                         case SDLK_RIGHT: if(e.key.repeat == 0) { p.setxvel(10); }                         break;                         case SDLK_UP:                         if(count < 5) {                             p.setyvel(-3);                             ++count;                             }                             p.landed = false;                                                  break;                     }                 }                                  if(e.type == SDL_KEYUP && e.key.repeat == 0) {                     switch(e.key.keysym.sym) {                         case SDLK_LEFT: p.setxvel(10);                         break;                         case SDLK_RIGHT: p.setxvel(-10);                         break;                         case SDLK_UP: count = 0;                         break;                     }                 }                              }             SDL_RenderClear(r);             SDL_RenderFillRect(r,&BG);             p.move();             p.render();                          SDL_RenderPresent(r);         }     }     close();
      Please help me to get it working, I have no idea what's going on. I have SDL 2.0.7 and my Mac is OS X 10.10.3.
    • By glportal
      GlPortal is a free and open source first person 3D teleportation based puzzle game and platformer. But we have already integrated a physics engine and are planning for some physics based puzzles.
      We want to improve our Visual Studio support. Check out this project:
      https://github.com/kungfooman/glportal-vs
      You can chat with us on gitter https://gitter.im/GlPortal/glPortal
  • Popular Now