I don't know why this doesn't work, especially when the documentation tells me exactly how it's done. It appears to me that SDL events don't always work; I mean, I've had instances where NONE of the event types would be processesed for a few days, then suddenly start working again. I dunno, what the frell is going on?
This should be rather straight forward, but I guess not. This is the code I use to handle gamepads and such...
#include "KeGamepad.h"
#include <vector>
/* Gamepad handle */
class CKeGamepadHandle
{
public:
CKeGamepadHandle() : game_controller(NULL), haptic(NULL), joystick_id(0), id(0), connected(No) {}
~CKeGamepadHandle()
{
if( haptic )
SDL_HapticClose( haptic );
SDL_GameControllerClose( game_controller );
}
SDL_GameController* game_controller;
SDL_Haptic* haptic;
SDL_JoystickID joystick_id;
KeGamepadState state;
int id;
bool connected;
};
/* Gamepad handles */
std::vector<CKeGamepadHandle> GamepadHandles;
/*
* Name: KeInitializeGamepads
* Desc: Initializes the gamepad API for the target platform.
*/
bool KeInitializeGamepads()
{
int ret = 0;
/* Initialize SDL2 gamepad API */
ret = SDL_InitSubSystem( SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC );
if( ret != 0 )
DISPDBG( KE_ERROR, "An error has occured initializing SDL controller API!" );
return ret;
}
/*
* Name: KeUnintializeGamepads
* Desc: Uninitializes the above.
*/
void KeUninitializeGamepads()
{
/* Kill all open gamepad devices */
GamepadHandles.empty();
/* Uninitialize the gamepad API */
SDL_QuitSubSystem( SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC );
}
/*
* Name: KeOnGamepadAdded
* Desc: Called when a gamepad has been added/attached.
*/
void KeOnGamepadAdded( int device_id )
{
CKeGamepadHandle handle;
/* Attempt to open this device */
handle.game_controller = SDL_GameControllerOpen( device_id );
/* Get the joystick instance ID */
SDL_Joystick* j = SDL_GameControllerGetJoystick( handle.game_controller );
handle.joystick_id = SDL_JoystickInstanceID(j);
handle.connected = Yes;
handle.id = device_id;
ZeroMemory( &handle.state, sizeof( KeGamepadState ) );
/* Is this a haptic device? */
if( SDL_JoystickIsHaptic(j) )
{
handle.haptic = SDL_HapticOpenFromJoystick(j);
/* Is this a rumble supported haptic feature? */
if( SDL_HapticRumbleSupported( handle.haptic ) )
{
/* Can we initialize the rumble feature? */
if( SDL_HapticRumbleInit( handle.haptic ) )
{
/* An error occurred */
SDL_HapticClose( handle.haptic );
handle.haptic = 0;
DISPDBG( KE_WARNING, "Error initializing rumble feature for gamepad! "
"Device ID:" << device_id <<
"Joystick ID: " << handle.joystick_id <<
"Error code:" << SDL_GetError() );
}
}
else
{
/* This is not a rumble haptic */
SDL_HapticClose( handle.haptic );
handle.haptic = 0;
}
}
/* Add this to the list of handles */
GamepadHandles.push_back(handle);
}
/*
* Name: KeOnGamepadButtonPress
* Desc: Called when a gamepad button has been pressed
*/
void KeOnGamepadButtonPress( int device_id, void* context )
{
SDL_ControllerButtonEvent* event = static_cast<SDL_ControllerButtonEvent*>( context );
/* Search for the specified device and update the button info */
std::vector<CKeGamepadHandle>::iterator i = GamepadHandles.begin();
while( i != GamepadHandles.end() )
{
if( i->id == device_id )
{
i->state.buttons[event->button].pressed = event->state;
i->state.buttons[event->button].timestamp = event->timestamp;
return;
}
++i;
}
}
/*
* Name: KeOnGamepadRemoved
* Desc: Called when a gamepad has been removed/dettached.
*/
void KeOnGamepadRemoved( int device_id )
{
/* Search for this ID, if we find it, go ahead and remove it after unintializing it. */
std::vector<CKeGamepadHandle>::iterator i = GamepadHandles.begin();
while( i != GamepadHandles.end() )
{
if( i->id == device_id )
{
GamepadHandles.erase(i);
return;
}
++i;
}
}
/*
* Name: KeGetGamepadState
* Desc: Returns the input state of the specified gamepad
*/
bool KeGetGamepadState( int device_id, KeGamepadState* gamepad )
{
std::vector<CKeGamepadHandle>::iterator i = GamepadHandles.begin();
while( i != GamepadHandles.end() )
{
if( i->id == device_id )
{
memmove( gamepad, &i->state, sizeof( KeGamepadState ) );
return true;
}
++i;
}
return false;
}
And this is the event handling loop:
/*
* Name: KeProcessEvents
* Desc: Handles system events during the application's lifetime.
* TODO: Setup callbacks for each event type.
*/
void KeProcessEvents()
{
//ke_rdtsc();
SDL_Event event;
/* Check for any SDL supported events */
while( SDL_PollEvent( &event ) )
{
/* Respond to events accordingly */
switch( event.type )
{
case SDL_QUIT:
quitting = Yes;
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
KeProcessKeyEvent( &event );
KeOnKeyboard( KeGetContextPointer(), &event );
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
KeProcessMouseEvent( &event );
KeOnMouse( KeGetContextPointer(), &event );
break;
case SDL_MOUSEMOTION:
KeProcessMouseEvent( &event );
break;
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
KeOnGamepad( KeGetContextPointer(), &event );
KeOnGamepadButtonPress( event.cbutton.which, &event.cbutton );
break;
case SDL_CONTROLLERAXISMOTION:
break;
case SDL_CONTROLLERDEVICEADDED:
KeOnGamepadAdded( event.cdevice.which );
break;
case SDL_CONTROLLERDEVICEREMOVED:
KeOnGamepadRemoved( event.cdevice.which );
break;
}
}
/* Update keys */
KeUpdateKeys();
}
Now, I've inserted breakpoints at every controller event, and the only one that gets triggered is SDL_CONTROLLERDEVICEADDED. When I remove a controller, nothing happens, but when I reattach the same one, I get that message triggered. Button presses and axis movement also doesn't work.
I've also had this problem with mouse input, but then all of a sudden, it started working. Maybe this will happen with my gamepad code too. Anyone else experiencing this?
Shogun.
EDIT: I forgot to mention that I'm using both a Playstation 4 and an Xbox 360 controller to test this on. The SDL2 version I'm using is 2.0.3, and I also tried 2.0.4, same results.