I’m currently trying to use SDL’s GameController subsystem to detect removing and attaching controllers, but have come up against a wall. The program won’t fire an event when attaching and removing while running, but if it’s plugged in before the loop starts, then it fires the CONTROLLERATTACHED event. I can see that when I plug in the controller, extra dlls are loaded (particularly deviceaccess.dll), so I was worried that it was just me. So here’s a list of things I did:
- I downloaded the controller test program, ran that, and it worked.
- I changed the controller test to get the source via cmake, and that still worked.
- Breakpoint on the switch statement. No events firing at all.
- Adding allow background events hint. No change.
- Initializing the event subsystem. Nothing
- Initializing the video subsystem. Nothing.
- Listening for JOYDEVICE events. No events firing still.
- Disabling everything except for the directly relevant files.
- Removing key_controller.
Going over the subsystems I was using and comparing them step by step doesn’t seem to reveal any major differences aside from my choice to use a vector instead of an array, wait event instead of pump events, and not using a screen (another library to be added). But that to me still doesn’t explain why no events are being pushed. Everything I read shows that JOYSTICK and GAMECONTROLLER should still fire their events.
Here is the code (Most of the code has been moved to the main file for quick testing):
#define SDL_MAIN_HANDLED
#include <SDL.h>
#include <vector>
#include <iostream>
#include <thread>
#include "KeyBindController.h"
//More includes not relevant
void sdl_loop(KeyBindController* key_controller)
{
bool active = true ;
SDL_Event event ;
while( active )
{
if( SDL_WaitEvent( &event ) )
{
switch( event.type )
{
//case SDL_JOYDEVICEADDED:
case SDL_CONTROLLERDEVICEADDED:
std::cout << "Added device" << std::endl ;
key_controller->notify_device( &event ) ;
break ;
case SDL_CONTROLLERDEVICEREMOVED:
std::cout << "Removed device" << std::endl ;
key_controller->notify_device( &event ) ;
break ;
case SDL_USEREVENT:
std::cout << "Quitting SDL\n" ;
active = false ;
break ;
}
}
}
}
std::vector<SDL_GameController*> game_controllers ;
SDL_GameController* find_device( SDL_JoystickID _dev_id )
{
//Loop through devices. Uses vector instead of array.
for( auto iter = game_controllers.begin() ; iter != game_controllers.end() ; iter++ )
{
if( _dev_id == SDL_JoystickInstanceID( SDL_GameControllerGetJoystick( *iter ) ) )
{
return *iter ;
}
}
return nullptr ;
}
void add_device( int device_index )
{
SDL_JoystickID controller_id = SDL_JoystickGetDeviceInstanceID( device_index ) ;
// Check if controller id exists
if( controller_id < 0 )
return ;
//Check if this exists in the list. If it does, quit this function as we don't need it.
if( find_device( controller_id ) )
return ;
SDL_GameController* controller = SDL_GameControllerOpen( device_index ) ;
// Check if controller was created
if( !controller )
return ;
game_controllers.push_back( controller ) ;
}
void remove_device( SDL_JoystickID _controller )
{
SDL_GameController* control_p = find_device( _controller ) ;
// Check for nullptr
if( !control_p )
return ;
//Search through vector
for( auto iter = game_controllers.begin() ; iter != game_controllers.end() ; iter++ )
{
//Erase item
if( *iter == control_p )
{
game_controllers.erase( iter ) ;
return ;
}
}
}
int main()
{
//Start testing
if( SDL_Init( SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER ) < 0 )
{
std::cerr << "Failed to initialize SDL: " << SDL_GetError() << std::endl ;
return 1 ;
}
//Add in the initial gamecontrollers
for( int iter = 0 ; iter < SDL_NumJoysticks() ; iter++ )
{
if( SDL_IsGameController( iter ) )
{
add_device( iter ) ;
}
}
//key1 can be removed from this whole thing, nothing changes
KeyBindController key1(...);
key1.import( ...) ;
std::thread sdl( sdl_loop, &key1 ) ;
//Another thread here fires the USEREVENT that results in quitting when given a text input
sdl.join() ;
for( auto iter = game_controllers.begin() ; iter != game_controllers.end() ; iter++ )
{
SDL_GameControllerClose( ( *iter ) ) ;
}
SDL_Quit() ;
return 0;
}
Any suggestions or help would be appreciated.