2015-06-21 15:33:46 +00:00
/*
Simple DirectMedia Layer
2018-01-03 18:03:25 +00:00
Copyright ( C ) 1997 - 2018 Sam Lantinga < slouken @ libsdl . org >
2015-06-21 15:33:46 +00:00
This software is provided ' as - is ' , without any express or implied
warranty . In no event will the authors be held liable for any damages
arising from the use of this software .
Permission is granted to anyone to use this software for any purpose ,
including commercial applications , and to alter it and redistribute it
freely , subject to the following restrictions :
1. The origin of this software must not be misrepresented ; you must not
claim that you wrote the original software . If you use this software
in a product , an acknowledgment in the product documentation would be
appreciated but is not required .
2. Altered source versions must be plainly marked as such , and must not be
misrepresented as being the original software .
3. This notice may not be removed or altered from any source distribution .
*/
# include "../SDL_internal.h"
/* This is the game controller API for Simple DirectMedia Layer */
# include "SDL_events.h"
# include "SDL_assert.h"
2017-10-10 18:10:15 +00:00
# include "SDL_hints.h"
2018-03-19 21:42:51 +00:00
# include "SDL_timer.h"
2015-06-21 15:33:46 +00:00
# include "SDL_sysjoystick.h"
2016-12-08 18:13:45 +00:00
# include "SDL_joystick_c.h"
2015-06-21 15:33:46 +00:00
# include "SDL_gamecontrollerdb.h"
# if !SDL_EVENTS_DISABLED
# include "../events/SDL_events_c.h"
# endif
2017-09-22 15:30:52 +00:00
# if defined(__ANDROID__)
# include "SDL_system.h"
# endif
2018-03-19 21:42:51 +00:00
/* Many controllers turn the center button into an instantaneous button press */
2018-05-18 20:09:30 +00:00
# define SDL_MINIMUM_GUIDE_BUTTON_DELAY_MS 250
2018-03-19 21:42:51 +00:00
2015-06-21 15:33:46 +00:00
# define SDL_CONTROLLER_PLATFORM_FIELD "platform:"
/* a list of currently opened game controllers */
static SDL_GameController * SDL_gamecontrollers = NULL ;
2016-12-27 09:39:07 +00:00
typedef struct
2015-06-21 15:33:46 +00:00
{
2016-12-27 09:39:07 +00:00
SDL_GameControllerBindType inputType ;
union
{
int button ;
2015-06-21 15:33:46 +00:00
2016-12-27 09:39:07 +00:00
struct {
int axis ;
int axis_min ;
int axis_max ;
} axis ;
2015-06-21 15:33:46 +00:00
2016-12-27 09:39:07 +00:00
struct {
int hat ;
int hat_mask ;
} hat ;
2015-06-21 15:33:46 +00:00
2016-12-27 09:39:07 +00:00
} input ;
2015-06-21 15:33:46 +00:00
2016-12-27 09:39:07 +00:00
SDL_GameControllerBindType outputType ;
union
{
SDL_GameControllerButton button ;
2015-06-21 15:33:46 +00:00
2016-12-27 09:39:07 +00:00
struct {
SDL_GameControllerAxis axis ;
int axis_min ;
int axis_max ;
} axis ;
2015-06-21 15:33:46 +00:00
2016-12-27 09:39:07 +00:00
} output ;
2015-06-21 15:33:46 +00:00
2016-12-27 09:39:07 +00:00
} SDL_ExtendedGameControllerBind ;
2015-06-21 15:33:46 +00:00
/* our hard coded list of mapping support */
2016-11-11 21:29:23 +00:00
typedef enum
{
SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT ,
SDL_CONTROLLER_MAPPING_PRIORITY_API ,
SDL_CONTROLLER_MAPPING_PRIORITY_USER ,
} SDL_ControllerMappingPriority ;
2015-06-21 15:33:46 +00:00
typedef struct _ControllerMapping_t
{
SDL_JoystickGUID guid ;
char * name ;
char * mapping ;
2016-11-11 21:29:23 +00:00
SDL_ControllerMappingPriority priority ;
2015-06-21 15:33:46 +00:00
struct _ControllerMapping_t * next ;
} ControllerMapping_t ;
2016-11-29 14:36:57 +00:00
static SDL_JoystickGUID s_zeroGUID ;
2015-06-21 15:33:46 +00:00
static ControllerMapping_t * s_pSupportedControllers = NULL ;
2018-03-06 22:51:50 +00:00
static ControllerMapping_t * s_pDefaultMapping = NULL ;
2015-06-21 15:33:46 +00:00
static ControllerMapping_t * s_pXInputMapping = NULL ;
/* The SDL game controller structure */
struct _SDL_GameController
{
SDL_Joystick * joystick ; /* underlying joystick device */
int ref_count ;
2016-12-27 09:39:07 +00:00
SDL_JoystickGUID guid ;
const char * name ;
int num_bindings ;
SDL_ExtendedGameControllerBind * bindings ;
SDL_ExtendedGameControllerBind * * last_match_axis ;
Uint8 * last_hat_mask ;
2018-03-19 21:42:51 +00:00
Uint32 guide_button_down ;
2016-12-27 09:39:07 +00:00
2015-06-21 15:33:46 +00:00
struct _SDL_GameController * next ; /* pointer to next game controller we have allocated */
} ;
2017-08-09 18:59:29 +00:00
typedef struct
{
int num_entries ;
int max_entries ;
Uint32 * entries ;
} SDL_vidpid_list ;
static SDL_vidpid_list SDL_allowed_controllers ;
static SDL_vidpid_list SDL_ignored_controllers ;
static void
SDL_LoadVIDPIDListFromHint ( const char * hint , SDL_vidpid_list * list )
{
Uint32 entry ;
char * spot ;
char * file = NULL ;
list - > num_entries = 0 ;
if ( hint & & * hint = = ' @ ' ) {
spot = file = ( char * ) SDL_LoadFile ( hint + 1 , NULL ) ;
} else {
spot = ( char * ) hint ;
}
if ( ! spot ) {
return ;
}
while ( ( spot = SDL_strstr ( spot , " 0x " ) ) ! = NULL ) {
2017-08-12 07:04:46 +00:00
entry = ( Uint16 ) SDL_strtol ( spot , & spot , 0 ) ;
2017-08-09 18:59:29 +00:00
entry < < = 16 ;
spot = SDL_strstr ( spot , " 0x " ) ;
if ( ! spot ) {
break ;
}
2017-08-12 07:04:46 +00:00
entry | = ( Uint16 ) SDL_strtol ( spot , & spot , 0 ) ;
2017-08-09 18:59:29 +00:00
if ( list - > num_entries = = list - > max_entries ) {
int max_entries = list - > max_entries + 16 ;
Uint32 * entries = ( Uint32 * ) SDL_realloc ( list - > entries , max_entries * sizeof ( * list - > entries ) ) ;
if ( entries = = NULL ) {
/* Out of memory, go with what we have already */
break ;
}
list - > entries = entries ;
list - > max_entries = max_entries ;
}
list - > entries [ list - > num_entries + + ] = entry ;
}
if ( file ) {
SDL_free ( file ) ;
}
}
2017-08-14 13:28:21 +00:00
static void SDLCALL
2017-08-09 18:59:29 +00:00
SDL_GameControllerIgnoreDevicesChanged ( void * userdata , const char * name , const char * oldValue , const char * hint )
{
SDL_LoadVIDPIDListFromHint ( hint , & SDL_ignored_controllers ) ;
}
2017-08-14 13:28:21 +00:00
static void SDLCALL
2017-08-09 18:59:29 +00:00
SDL_GameControllerIgnoreDevicesExceptChanged ( void * userdata , const char * name , const char * oldValue , const char * hint )
{
SDL_LoadVIDPIDListFromHint ( hint , & SDL_allowed_controllers ) ;
}
2016-12-27 09:39:07 +00:00
static int SDL_PrivateGameControllerAxis ( SDL_GameController * gamecontroller , SDL_GameControllerAxis axis , Sint16 value ) ;
static int SDL_PrivateGameControllerButton ( SDL_GameController * gamecontroller , SDL_GameControllerButton button , Uint8 state ) ;
2015-06-21 15:33:46 +00:00
2016-08-26 19:18:08 +00:00
/*
* If there is an existing add event in the queue , it needs to be modified
* to have the right value for which , because the number of controllers in
* the system is now one less .
*/
static void UpdateEventsForDeviceRemoval ( )
{
int i , num_events ;
SDL_Event * events ;
num_events = SDL_PeepEvents ( NULL , 0 , SDL_PEEKEVENT , SDL_CONTROLLERDEVICEADDED , SDL_CONTROLLERDEVICEADDED ) ;
if ( num_events < = 0 ) {
return ;
}
events = SDL_stack_alloc ( SDL_Event , num_events ) ;
if ( ! events ) {
return ;
}
num_events = SDL_PeepEvents ( events , num_events , SDL_GETEVENT , SDL_CONTROLLERDEVICEADDED , SDL_CONTROLLERDEVICEADDED ) ;
for ( i = 0 ; i < num_events ; + + i ) {
- - events [ i ] . cdevice . which ;
}
SDL_PeepEvents ( events , num_events , SDL_ADDEVENT , 0 , 0 ) ;
SDL_stack_free ( events ) ;
}
2016-12-27 09:39:07 +00:00
static SDL_bool HasSameOutput ( SDL_ExtendedGameControllerBind * a , SDL_ExtendedGameControllerBind * b )
{
if ( a - > outputType ! = b - > outputType ) {
return SDL_FALSE ;
}
if ( a - > outputType = = SDL_CONTROLLER_BINDTYPE_AXIS ) {
return ( a - > output . axis . axis = = b - > output . axis . axis ) ;
} else {
return ( a - > output . button = = b - > output . button ) ;
}
}
static void ResetOutput ( SDL_GameController * gamecontroller , SDL_ExtendedGameControllerBind * bind )
{
if ( bind - > outputType = = SDL_CONTROLLER_BINDTYPE_AXIS ) {
SDL_PrivateGameControllerAxis ( gamecontroller , bind - > output . axis . axis , 0 ) ;
} else {
SDL_PrivateGameControllerButton ( gamecontroller , bind - > output . button , SDL_RELEASED ) ;
}
}
static void HandleJoystickAxis ( SDL_GameController * gamecontroller , int axis , int value )
{
int i ;
SDL_ExtendedGameControllerBind * last_match = gamecontroller - > last_match_axis [ axis ] ;
SDL_ExtendedGameControllerBind * match = NULL ;
for ( i = 0 ; i < gamecontroller - > num_bindings ; + + i ) {
SDL_ExtendedGameControllerBind * binding = & gamecontroller - > bindings [ i ] ;
if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_AXIS & &
axis = = binding - > input . axis . axis ) {
if ( binding - > input . axis . axis_min < binding - > input . axis . axis_max ) {
if ( value > = binding - > input . axis . axis_min & &
value < = binding - > input . axis . axis_max ) {
match = binding ;
break ;
}
} else {
if ( value > = binding - > input . axis . axis_max & &
value < = binding - > input . axis . axis_min ) {
match = binding ;
break ;
}
}
}
}
if ( last_match & & ( ! match | | ! HasSameOutput ( last_match , match ) ) ) {
/* Clear the last input that this axis generated */
ResetOutput ( gamecontroller , last_match ) ;
}
if ( match ) {
if ( match - > outputType = = SDL_CONTROLLER_BINDTYPE_AXIS ) {
if ( match - > input . axis . axis_min ! = match - > output . axis . axis_min | | match - > input . axis . axis_max ! = match - > output . axis . axis_max ) {
float normalized_value = ( float ) ( value - match - > input . axis . axis_min ) / ( match - > input . axis . axis_max - match - > input . axis . axis_min ) ;
value = match - > output . axis . axis_min + ( int ) ( normalized_value * ( match - > output . axis . axis_max - match - > output . axis . axis_min ) ) ;
}
SDL_PrivateGameControllerAxis ( gamecontroller , match - > output . axis . axis , ( Sint16 ) value ) ;
} else {
Uint8 state ;
int threshold = match - > input . axis . axis_min + ( match - > input . axis . axis_max - match - > input . axis . axis_min ) / 2 ;
if ( match - > input . axis . axis_max < match - > input . axis . axis_min ) {
state = ( value < = threshold ) ? SDL_PRESSED : SDL_RELEASED ;
} else {
state = ( value > = threshold ) ? SDL_PRESSED : SDL_RELEASED ;
}
SDL_PrivateGameControllerButton ( gamecontroller , match - > output . button , state ) ;
}
}
gamecontroller - > last_match_axis [ axis ] = match ;
}
static void HandleJoystickButton ( SDL_GameController * gamecontroller , int button , Uint8 state )
{
int i ;
for ( i = 0 ; i < gamecontroller - > num_bindings ; + + i ) {
SDL_ExtendedGameControllerBind * binding = & gamecontroller - > bindings [ i ] ;
if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_BUTTON & &
button = = binding - > input . button ) {
if ( binding - > outputType = = SDL_CONTROLLER_BINDTYPE_AXIS ) {
int value = state ? binding - > output . axis . axis_max : binding - > output . axis . axis_min ;
SDL_PrivateGameControllerAxis ( gamecontroller , binding - > output . axis . axis , ( Sint16 ) value ) ;
} else {
SDL_PrivateGameControllerButton ( gamecontroller , binding - > output . button , state ) ;
}
break ;
}
}
}
static void HandleJoystickHat ( SDL_GameController * gamecontroller , int hat , Uint8 value )
{
int i ;
Uint8 last_mask = gamecontroller - > last_hat_mask [ hat ] ;
Uint8 changed_mask = ( last_mask ^ value ) ;
for ( i = 0 ; i < gamecontroller - > num_bindings ; + + i ) {
SDL_ExtendedGameControllerBind * binding = & gamecontroller - > bindings [ i ] ;
if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_HAT & & hat = = binding - > input . hat . hat ) {
if ( ( changed_mask & binding - > input . hat . hat_mask ) ! = 0 ) {
if ( value & binding - > input . hat . hat_mask ) {
if ( binding - > outputType = = SDL_CONTROLLER_BINDTYPE_AXIS ) {
SDL_PrivateGameControllerAxis ( gamecontroller , binding - > output . axis . axis , ( Sint16 ) binding - > output . axis . axis_max ) ;
} else {
SDL_PrivateGameControllerButton ( gamecontroller , binding - > output . button , SDL_PRESSED ) ;
}
} else {
ResetOutput ( gamecontroller , binding ) ;
}
}
}
}
gamecontroller - > last_hat_mask [ hat ] = value ;
}
2015-06-21 15:33:46 +00:00
/*
* Event filter to fire controller events from joystick ones
*/
2017-08-14 04:06:52 +00:00
static int SDLCALL SDL_GameControllerEventWatcher ( void * userdata , SDL_Event * event )
2015-06-21 15:33:46 +00:00
{
switch ( event - > type ) {
case SDL_JOYAXISMOTION :
{
2016-12-27 09:39:07 +00:00
SDL_GameController * controllerlist = SDL_gamecontrollers ;
2015-06-21 15:33:46 +00:00
while ( controllerlist ) {
if ( controllerlist - > joystick - > instance_id = = event - > jaxis . which ) {
2016-12-27 09:39:07 +00:00
HandleJoystickAxis ( controllerlist , event - > jaxis . axis , event - > jaxis . value ) ;
2015-06-21 15:33:46 +00:00
break ;
}
controllerlist = controllerlist - > next ;
}
}
break ;
case SDL_JOYBUTTONDOWN :
case SDL_JOYBUTTONUP :
{
2016-12-27 09:39:07 +00:00
SDL_GameController * controllerlist = SDL_gamecontrollers ;
2015-06-21 15:33:46 +00:00
while ( controllerlist ) {
if ( controllerlist - > joystick - > instance_id = = event - > jbutton . which ) {
2016-12-27 09:39:07 +00:00
HandleJoystickButton ( controllerlist , event - > jbutton . button , event - > jbutton . state ) ;
2015-06-21 15:33:46 +00:00
break ;
}
controllerlist = controllerlist - > next ;
}
}
break ;
case SDL_JOYHATMOTION :
{
2016-12-27 09:39:07 +00:00
SDL_GameController * controllerlist = SDL_gamecontrollers ;
2015-06-21 15:33:46 +00:00
while ( controllerlist ) {
if ( controllerlist - > joystick - > instance_id = = event - > jhat . which ) {
2016-12-27 09:39:07 +00:00
HandleJoystickHat ( controllerlist , event - > jhat . hat , event - > jhat . value ) ;
2015-06-21 15:33:46 +00:00
break ;
}
controllerlist = controllerlist - > next ;
}
}
break ;
case SDL_JOYDEVICEADDED :
{
if ( SDL_IsGameController ( event - > jdevice . which ) ) {
SDL_Event deviceevent ;
deviceevent . type = SDL_CONTROLLERDEVICEADDED ;
deviceevent . cdevice . which = event - > jdevice . which ;
SDL_PushEvent ( & deviceevent ) ;
}
}
break ;
case SDL_JOYDEVICEREMOVED :
{
SDL_GameController * controllerlist = SDL_gamecontrollers ;
while ( controllerlist ) {
if ( controllerlist - > joystick - > instance_id = = event - > jdevice . which ) {
SDL_Event deviceevent ;
2016-08-26 18:16:44 +00:00
2015-06-21 15:33:46 +00:00
deviceevent . type = SDL_CONTROLLERDEVICEREMOVED ;
deviceevent . cdevice . which = event - > jdevice . which ;
SDL_PushEvent ( & deviceevent ) ;
2016-08-26 19:18:08 +00:00
UpdateEventsForDeviceRemoval ( ) ;
2015-06-21 15:33:46 +00:00
break ;
}
controllerlist = controllerlist - > next ;
}
}
break ;
default :
break ;
}
return 1 ;
}
/*
* Helper function to scan the mappings database for a controller with the specified GUID
*/
2016-11-14 06:57:41 +00:00
static ControllerMapping_t * SDL_PrivateGetControllerMappingForGUID ( SDL_JoystickGUID * guid )
2015-06-21 15:33:46 +00:00
{
ControllerMapping_t * pSupportedController = s_pSupportedControllers ;
while ( pSupportedController ) {
if ( SDL_memcmp ( guid , & pSupportedController - > guid , sizeof ( * guid ) ) = = 0 ) {
return pSupportedController ;
}
pSupportedController = pSupportedController - > next ;
}
2018-03-07 21:30:40 +00:00
# if SDL_JOYSTICK_XINPUT
if ( guid - > data [ 14 ] = = ' x ' ) {
/* This is an XInput device */
return s_pXInputMapping ;
}
# endif
2015-06-21 15:33:46 +00:00
return NULL ;
}
static const char * map_StringForControllerAxis [ ] = {
" leftx " ,
" lefty " ,
" rightx " ,
" righty " ,
" lefttrigger " ,
" righttrigger " ,
NULL
} ;
/*
* convert a string to its enum equivalent
*/
SDL_GameControllerAxis SDL_GameControllerGetAxisFromString ( const char * pchString )
{
int entry ;
2016-12-27 09:39:07 +00:00
if ( pchString & & ( * pchString = = ' + ' | | * pchString = = ' - ' ) ) {
+ + pchString ;
}
if ( ! pchString | | ! pchString [ 0 ] ) {
2015-06-21 15:33:46 +00:00
return SDL_CONTROLLER_AXIS_INVALID ;
2016-12-27 09:39:07 +00:00
}
2015-06-21 15:33:46 +00:00
for ( entry = 0 ; map_StringForControllerAxis [ entry ] ; + + entry ) {
if ( ! SDL_strcasecmp ( pchString , map_StringForControllerAxis [ entry ] ) )
2017-03-03 21:38:17 +00:00
return ( SDL_GameControllerAxis ) entry ;
2015-06-21 15:33:46 +00:00
}
return SDL_CONTROLLER_AXIS_INVALID ;
}
/*
* convert an enum to its string equivalent
*/
const char * SDL_GameControllerGetStringForAxis ( SDL_GameControllerAxis axis )
{
if ( axis > SDL_CONTROLLER_AXIS_INVALID & & axis < SDL_CONTROLLER_AXIS_MAX ) {
return map_StringForControllerAxis [ axis ] ;
}
return NULL ;
}
static const char * map_StringForControllerButton [ ] = {
" a " ,
" b " ,
" x " ,
" y " ,
" back " ,
" guide " ,
" start " ,
" leftstick " ,
" rightstick " ,
" leftshoulder " ,
" rightshoulder " ,
" dpup " ,
" dpdown " ,
" dpleft " ,
" dpright " ,
NULL
} ;
/*
* convert a string to its enum equivalent
*/
SDL_GameControllerButton SDL_GameControllerGetButtonFromString ( const char * pchString )
{
int entry ;
if ( ! pchString | | ! pchString [ 0 ] )
return SDL_CONTROLLER_BUTTON_INVALID ;
for ( entry = 0 ; map_StringForControllerButton [ entry ] ; + + entry ) {
if ( SDL_strcasecmp ( pchString , map_StringForControllerButton [ entry ] ) = = 0 )
2017-03-03 21:38:17 +00:00
return ( SDL_GameControllerButton ) entry ;
2015-06-21 15:33:46 +00:00
}
return SDL_CONTROLLER_BUTTON_INVALID ;
}
/*
* convert an enum to its string equivalent
*/
const char * SDL_GameControllerGetStringForButton ( SDL_GameControllerButton axis )
{
if ( axis > SDL_CONTROLLER_BUTTON_INVALID & & axis < SDL_CONTROLLER_BUTTON_MAX ) {
return map_StringForControllerButton [ axis ] ;
}
return NULL ;
}
/*
* given a controller button name and a joystick name update our mapping structure with it
*/
2016-12-27 09:39:07 +00:00
static void SDL_PrivateGameControllerParseElement ( SDL_GameController * gamecontroller , const char * szGameButton , const char * szJoystickButton )
2015-06-21 15:33:46 +00:00
{
2016-12-27 09:39:07 +00:00
SDL_ExtendedGameControllerBind bind ;
2015-06-21 15:33:46 +00:00
SDL_GameControllerButton button ;
SDL_GameControllerAxis axis ;
2016-12-27 09:39:07 +00:00
SDL_bool invert_input = SDL_FALSE ;
char half_axis_input = 0 ;
char half_axis_output = 0 ;
2015-06-21 15:33:46 +00:00
2016-12-27 09:39:07 +00:00
if ( * szGameButton = = ' + ' | | * szGameButton = = ' - ' ) {
half_axis_output = * szGameButton + + ;
}
axis = SDL_GameControllerGetAxisFromString ( szGameButton ) ;
button = SDL_GameControllerGetButtonFromString ( szGameButton ) ;
if ( axis ! = SDL_CONTROLLER_AXIS_INVALID ) {
bind . outputType = SDL_CONTROLLER_BINDTYPE_AXIS ;
bind . output . axis . axis = axis ;
if ( axis = = SDL_CONTROLLER_AXIS_TRIGGERLEFT | | axis = = SDL_CONTROLLER_AXIS_TRIGGERRIGHT ) {
bind . output . axis . axis_min = 0 ;
bind . output . axis . axis_max = SDL_JOYSTICK_AXIS_MAX ;
2015-06-21 15:33:46 +00:00
} else {
2016-12-27 09:39:07 +00:00
if ( half_axis_output = = ' + ' ) {
bind . output . axis . axis_min = 0 ;
bind . output . axis . axis_max = SDL_JOYSTICK_AXIS_MAX ;
} else if ( half_axis_output = = ' - ' ) {
bind . output . axis . axis_min = 0 ;
bind . output . axis . axis_max = SDL_JOYSTICK_AXIS_MIN ;
} else {
bind . output . axis . axis_min = SDL_JOYSTICK_AXIS_MIN ;
bind . output . axis . axis_max = SDL_JOYSTICK_AXIS_MAX ;
}
2015-06-21 15:33:46 +00:00
}
2016-12-27 09:39:07 +00:00
} else if ( button ! = SDL_CONTROLLER_BUTTON_INVALID ) {
bind . outputType = SDL_CONTROLLER_BINDTYPE_BUTTON ;
bind . output . button = button ;
} else {
SDL_SetError ( " Unexpected controller element %s " , szGameButton ) ;
return ;
}
2015-06-21 15:33:46 +00:00
2016-12-27 09:39:07 +00:00
if ( * szJoystickButton = = ' + ' | | * szJoystickButton = = ' - ' ) {
half_axis_input = * szJoystickButton + + ;
}
if ( szJoystickButton [ SDL_strlen ( szJoystickButton ) - 1 ] = = ' ~ ' ) {
invert_input = SDL_TRUE ;
}
if ( szJoystickButton [ 0 ] = = ' a ' & & SDL_isdigit ( szJoystickButton [ 1 ] ) ) {
bind . inputType = SDL_CONTROLLER_BINDTYPE_AXIS ;
bind . input . axis . axis = SDL_atoi ( & szJoystickButton [ 1 ] ) ;
if ( half_axis_input = = ' + ' ) {
bind . input . axis . axis_min = 0 ;
bind . input . axis . axis_max = SDL_JOYSTICK_AXIS_MAX ;
} else if ( half_axis_input = = ' - ' ) {
bind . input . axis . axis_min = 0 ;
bind . input . axis . axis_max = SDL_JOYSTICK_AXIS_MIN ;
2015-06-21 15:33:46 +00:00
} else {
2016-12-27 09:39:07 +00:00
bind . input . axis . axis_min = SDL_JOYSTICK_AXIS_MIN ;
bind . input . axis . axis_max = SDL_JOYSTICK_AXIS_MAX ;
}
if ( invert_input ) {
int tmp = bind . input . axis . axis_min ;
bind . input . axis . axis_min = bind . input . axis . axis_max ;
bind . input . axis . axis_max = tmp ;
2015-06-21 15:33:46 +00:00
}
2016-12-27 09:39:07 +00:00
} else if ( szJoystickButton [ 0 ] = = ' b ' & & SDL_isdigit ( szJoystickButton [ 1 ] ) ) {
bind . inputType = SDL_CONTROLLER_BINDTYPE_BUTTON ;
bind . input . button = SDL_atoi ( & szJoystickButton [ 1 ] ) ;
} else if ( szJoystickButton [ 0 ] = = ' h ' & & SDL_isdigit ( szJoystickButton [ 1 ] ) & &
szJoystickButton [ 2 ] = = ' . ' & & SDL_isdigit ( szJoystickButton [ 3 ] ) ) {
2015-06-21 15:33:46 +00:00
int hat = SDL_atoi ( & szJoystickButton [ 1 ] ) ;
int mask = SDL_atoi ( & szJoystickButton [ 3 ] ) ;
2016-12-27 09:39:07 +00:00
bind . inputType = SDL_CONTROLLER_BINDTYPE_HAT ;
bind . input . hat . hat = hat ;
bind . input . hat . hat_mask = mask ;
} else {
SDL_SetError ( " Unexpected joystick element: %s " , szJoystickButton ) ;
return ;
}
2015-06-21 15:33:46 +00:00
2016-12-27 09:39:07 +00:00
+ + gamecontroller - > num_bindings ;
gamecontroller - > bindings = ( SDL_ExtendedGameControllerBind * ) SDL_realloc ( gamecontroller - > bindings , gamecontroller - > num_bindings * sizeof ( * gamecontroller - > bindings ) ) ;
if ( ! gamecontroller - > bindings ) {
gamecontroller - > num_bindings = 0 ;
SDL_OutOfMemory ( ) ;
return ;
2015-06-21 15:33:46 +00:00
}
2016-12-27 09:39:07 +00:00
gamecontroller - > bindings [ gamecontroller - > num_bindings - 1 ] = bind ;
2015-06-21 15:33:46 +00:00
}
/*
* given a controller mapping string update our mapping object
*/
static void
2016-12-27 09:39:07 +00:00
SDL_PrivateGameControllerParseControllerConfigString ( SDL_GameController * gamecontroller , const char * pchString )
2015-06-21 15:33:46 +00:00
{
char szGameButton [ 20 ] ;
char szJoystickButton [ 20 ] ;
SDL_bool bGameButton = SDL_TRUE ;
int i = 0 ;
const char * pchPos = pchString ;
2016-12-27 09:39:07 +00:00
SDL_zero ( szGameButton ) ;
SDL_zero ( szJoystickButton ) ;
2015-06-21 15:33:46 +00:00
while ( pchPos & & * pchPos ) {
if ( * pchPos = = ' : ' ) {
i = 0 ;
bGameButton = SDL_FALSE ;
} else if ( * pchPos = = ' ' ) {
} else if ( * pchPos = = ' , ' ) {
i = 0 ;
bGameButton = SDL_TRUE ;
2016-12-27 09:39:07 +00:00
SDL_PrivateGameControllerParseElement ( gamecontroller , szGameButton , szJoystickButton ) ;
SDL_zero ( szGameButton ) ;
SDL_zero ( szJoystickButton ) ;
2015-06-21 15:33:46 +00:00
} else if ( bGameButton ) {
if ( i > = sizeof ( szGameButton ) ) {
SDL_SetError ( " Button name too large: %s " , szGameButton ) ;
return ;
}
szGameButton [ i ] = * pchPos ;
i + + ;
} else {
if ( i > = sizeof ( szJoystickButton ) ) {
SDL_SetError ( " Joystick button name too large: %s " , szJoystickButton ) ;
return ;
}
szJoystickButton [ i ] = * pchPos ;
i + + ;
}
pchPos + + ;
}
2016-12-27 09:39:07 +00:00
SDL_PrivateGameControllerParseElement ( gamecontroller , szGameButton , szJoystickButton ) ;
2015-06-21 15:33:46 +00:00
}
/*
* Make a new button mapping struct
*/
2016-12-27 09:39:07 +00:00
static void SDL_PrivateLoadButtonMapping ( SDL_GameController * gamecontroller , SDL_JoystickGUID guid , const char * pchName , const char * pchMapping )
2015-06-21 15:33:46 +00:00
{
2016-12-27 09:39:07 +00:00
int i ;
gamecontroller - > guid = guid ;
gamecontroller - > name = pchName ;
gamecontroller - > num_bindings = 0 ;
SDL_memset ( gamecontroller - > last_match_axis , 0 , gamecontroller - > joystick - > naxes * sizeof ( * gamecontroller - > last_match_axis ) ) ;
SDL_PrivateGameControllerParseControllerConfigString ( gamecontroller , pchMapping ) ;
/* Set the zero point for triggers */
for ( i = 0 ; i < gamecontroller - > num_bindings ; + + i ) {
SDL_ExtendedGameControllerBind * binding = & gamecontroller - > bindings [ i ] ;
if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_AXIS & &
binding - > outputType = = SDL_CONTROLLER_BINDTYPE_AXIS & &
( binding - > output . axis . axis = = SDL_CONTROLLER_AXIS_TRIGGERLEFT | |
binding - > output . axis . axis = = SDL_CONTROLLER_AXIS_TRIGGERRIGHT ) ) {
if ( binding - > input . axis . axis < gamecontroller - > joystick - > naxes ) {
gamecontroller - > joystick - > axes [ binding - > input . axis . axis ] . value =
gamecontroller - > joystick - > axes [ binding - > input . axis . axis ] . zero = ( Sint16 ) binding - > input . axis . axis_min ;
}
}
2015-06-21 15:33:46 +00:00
}
}
/*
* grab the guid string from a mapping string
*/
2016-11-14 06:57:41 +00:00
static char * SDL_PrivateGetControllerGUIDFromMappingString ( const char * pMapping )
2015-06-21 15:33:46 +00:00
{
const char * pFirstComma = SDL_strchr ( pMapping , ' , ' ) ;
if ( pFirstComma ) {
char * pchGUID = SDL_malloc ( pFirstComma - pMapping + 1 ) ;
if ( ! pchGUID ) {
SDL_OutOfMemory ( ) ;
return NULL ;
}
SDL_memcpy ( pchGUID , pMapping , pFirstComma - pMapping ) ;
2016-11-11 12:35:06 +00:00
pchGUID [ pFirstComma - pMapping ] = ' \0 ' ;
/* Convert old style GUIDs to the new style in 2.0.5 */
# if __WIN32__
if ( SDL_strlen ( pchGUID ) = = 32 & &
SDL_memcmp ( & pchGUID [ 20 ] , " 504944564944 " , 12 ) = = 0 ) {
SDL_memcpy ( & pchGUID [ 20 ] , " 000000000000 " , 12 ) ;
SDL_memcpy ( & pchGUID [ 16 ] , & pchGUID [ 4 ] , 4 ) ;
SDL_memcpy ( & pchGUID [ 8 ] , & pchGUID [ 0 ] , 4 ) ;
SDL_memcpy ( & pchGUID [ 0 ] , " 03000000 " , 8 ) ;
}
# elif __MACOSX__
if ( SDL_strlen ( pchGUID ) = = 32 & &
SDL_memcmp ( & pchGUID [ 4 ] , " 000000000000 " , 12 ) = = 0 & &
SDL_memcmp ( & pchGUID [ 20 ] , " 000000000000 " , 12 ) = = 0 ) {
SDL_memcpy ( & pchGUID [ 20 ] , " 000000000000 " , 12 ) ;
SDL_memcpy ( & pchGUID [ 8 ] , & pchGUID [ 0 ] , 4 ) ;
SDL_memcpy ( & pchGUID [ 0 ] , " 03000000 " , 8 ) ;
}
# endif
2015-06-21 15:33:46 +00:00
return pchGUID ;
}
return NULL ;
}
/*
* grab the name string from a mapping string
*/
2016-11-14 06:57:41 +00:00
static char * SDL_PrivateGetControllerNameFromMappingString ( const char * pMapping )
2015-06-21 15:33:46 +00:00
{
const char * pFirstComma , * pSecondComma ;
char * pchName ;
pFirstComma = SDL_strchr ( pMapping , ' , ' ) ;
if ( ! pFirstComma )
return NULL ;
pSecondComma = SDL_strchr ( pFirstComma + 1 , ' , ' ) ;
if ( ! pSecondComma )
return NULL ;
pchName = SDL_malloc ( pSecondComma - pFirstComma ) ;
if ( ! pchName ) {
SDL_OutOfMemory ( ) ;
return NULL ;
}
SDL_memcpy ( pchName , pFirstComma + 1 , pSecondComma - pFirstComma ) ;
2016-11-11 12:35:06 +00:00
pchName [ pSecondComma - pFirstComma - 1 ] = 0 ;
2015-06-21 15:33:46 +00:00
return pchName ;
}
/*
* grab the button mapping string from a mapping string
*/
2016-11-14 06:57:41 +00:00
static char * SDL_PrivateGetControllerMappingFromMappingString ( const char * pMapping )
2015-06-21 15:33:46 +00:00
{
const char * pFirstComma , * pSecondComma ;
pFirstComma = SDL_strchr ( pMapping , ' , ' ) ;
if ( ! pFirstComma )
return NULL ;
pSecondComma = SDL_strchr ( pFirstComma + 1 , ' , ' ) ;
if ( ! pSecondComma )
return NULL ;
return SDL_strdup ( pSecondComma + 1 ) ; /* mapping is everything after the 3rd comma */
}
2015-12-09 20:11:40 +00:00
/*
* Helper function to refresh a mapping
*/
2016-11-14 06:57:41 +00:00
static void SDL_PrivateGameControllerRefreshMapping ( ControllerMapping_t * pControllerMapping )
2015-06-21 15:33:46 +00:00
{
SDL_GameController * gamecontrollerlist = SDL_gamecontrollers ;
while ( gamecontrollerlist ) {
2016-12-27 09:39:07 +00:00
if ( ! SDL_memcmp ( & gamecontrollerlist - > guid , & pControllerMapping - > guid , sizeof ( pControllerMapping - > guid ) ) ) {
2015-06-21 15:33:46 +00:00
SDL_Event event ;
event . type = SDL_CONTROLLERDEVICEREMAPPED ;
event . cdevice . which = gamecontrollerlist - > joystick - > instance_id ;
SDL_PushEvent ( & event ) ;
/* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */
2016-12-27 09:39:07 +00:00
SDL_PrivateLoadButtonMapping ( gamecontrollerlist , pControllerMapping - > guid , pControllerMapping - > name , pControllerMapping - > mapping ) ;
2015-06-21 15:33:46 +00:00
}
gamecontrollerlist = gamecontrollerlist - > next ;
}
}
2015-12-09 20:11:40 +00:00
/*
* Helper function to add a mapping for a guid
*/
static ControllerMapping_t *
2016-11-11 21:29:23 +00:00
SDL_PrivateAddMappingForGUID ( SDL_JoystickGUID jGUID , const char * mappingString , SDL_bool * existing , SDL_ControllerMappingPriority priority )
2015-12-09 20:11:40 +00:00
{
char * pchName ;
char * pchMapping ;
ControllerMapping_t * pControllerMapping ;
pchName = SDL_PrivateGetControllerNameFromMappingString ( mappingString ) ;
if ( ! pchName ) {
SDL_SetError ( " Couldn't parse name from %s " , mappingString ) ;
return NULL ;
}
pchMapping = SDL_PrivateGetControllerMappingFromMappingString ( mappingString ) ;
if ( ! pchMapping ) {
SDL_free ( pchName ) ;
SDL_SetError ( " Couldn't parse %s " , mappingString ) ;
return NULL ;
}
pControllerMapping = SDL_PrivateGetControllerMappingForGUID ( & jGUID ) ;
if ( pControllerMapping ) {
2016-11-11 21:29:23 +00:00
/* Only overwrite the mapping if the priority is the same or higher. */
if ( pControllerMapping - > priority < = priority ) {
/* Update existing mapping */
SDL_free ( pControllerMapping - > name ) ;
pControllerMapping - > name = pchName ;
SDL_free ( pControllerMapping - > mapping ) ;
pControllerMapping - > mapping = pchMapping ;
pControllerMapping - > priority = priority ;
/* refresh open controllers */
SDL_PrivateGameControllerRefreshMapping ( pControllerMapping ) ;
2016-11-19 22:27:37 +00:00
} else {
SDL_free ( pchName ) ;
SDL_free ( pchMapping ) ;
2016-11-11 21:29:23 +00:00
}
2015-12-09 20:11:40 +00:00
* existing = SDL_TRUE ;
} else {
pControllerMapping = SDL_malloc ( sizeof ( * pControllerMapping ) ) ;
if ( ! pControllerMapping ) {
SDL_free ( pchName ) ;
SDL_free ( pchMapping ) ;
SDL_OutOfMemory ( ) ;
return NULL ;
}
pControllerMapping - > guid = jGUID ;
pControllerMapping - > name = pchName ;
pControllerMapping - > mapping = pchMapping ;
2016-11-30 06:02:37 +00:00
pControllerMapping - > next = NULL ;
2016-11-11 21:29:23 +00:00
pControllerMapping - > priority = priority ;
2016-11-30 06:02:37 +00:00
if ( s_pSupportedControllers ) {
/* Add the mapping to the end of the list */
ControllerMapping_t * pCurrMapping , * pPrevMapping ;
for ( pPrevMapping = s_pSupportedControllers , pCurrMapping = pPrevMapping - > next ;
pCurrMapping ;
pPrevMapping = pCurrMapping , pCurrMapping = pCurrMapping - > next ) {
continue ;
}
pPrevMapping - > next = pControllerMapping ;
} else {
s_pSupportedControllers = pControllerMapping ;
}
2015-12-09 20:11:40 +00:00
* existing = SDL_FALSE ;
}
return pControllerMapping ;
}
2018-03-06 22:51:50 +00:00
# ifdef __ANDROID__
/*
* Helper function to guess at a mapping based on the elements reported for this controller
*/
static ControllerMapping_t * SDL_CreateMappingForAndroidController ( const char * name , SDL_JoystickGUID guid )
{
SDL_bool existing ;
char name_string [ 128 ] ;
char mapping_string [ 1024 ] ;
int button_mask ;
int axis_mask ;
button_mask = SDL_SwapLE16 ( * ( Uint16 * ) ( & guid . data [ sizeof ( guid . data ) - 4 ] ) ) ;
axis_mask = SDL_SwapLE16 ( * ( Uint16 * ) ( & guid . data [ sizeof ( guid . data ) - 2 ] ) ) ;
if ( ! button_mask & & ! axis_mask ) {
/* Accelerometer, shouldn't have a game controller mapping */
return NULL ;
}
/* Remove any commas in the name */
SDL_strlcpy ( name_string , name , sizeof ( name_string ) ) ;
{
char * spot ;
for ( spot = name_string ; * spot ; + + spot ) {
if ( * spot = = ' , ' ) {
* spot = ' ' ;
}
}
}
SDL_snprintf ( mapping_string , sizeof ( mapping_string ) , " none,%s, " , name_string ) ;
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_A ) ) {
SDL_strlcat ( mapping_string , " a:b0, " , sizeof ( mapping_string ) ) ;
}
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_B ) ) {
SDL_strlcat ( mapping_string , " b:b1, " , sizeof ( mapping_string ) ) ;
} else if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_BACK ) ) {
/* Use the back button as "B" for easy UI navigation with TV remotes */
SDL_strlcat ( mapping_string , " b:b4, " , sizeof ( mapping_string ) ) ;
button_mask & = ~ ( 1 < < SDL_CONTROLLER_BUTTON_BACK ) ;
}
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_X ) ) {
SDL_strlcat ( mapping_string , " x:b2, " , sizeof ( mapping_string ) ) ;
}
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_Y ) ) {
SDL_strlcat ( mapping_string , " y:b3, " , sizeof ( mapping_string ) ) ;
}
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_BACK ) ) {
SDL_strlcat ( mapping_string , " back:b4, " , sizeof ( mapping_string ) ) ;
}
2018-05-18 20:09:30 +00:00
#if 0 /* The guide button generally isn't functional (or acts as a home button) on most Android controllers */
2018-03-06 22:51:50 +00:00
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_GUIDE ) ) {
SDL_strlcat ( mapping_string , " guide:b5, " , sizeof ( mapping_string ) ) ;
#if 0 /* Actually this will be done in Steam */
} else if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_START ) ) {
/* The guide button doesn't exist, use the start button instead,
so you can do Steam guide button chords and open the Steam overlay .
*/
SDL_strlcat ( mapping_string , " guide:b6, " , sizeof ( mapping_string ) ) ;
button_mask & = ~ ( 1 < < SDL_CONTROLLER_BUTTON_START ) ;
# endif
}
2018-05-18 20:09:30 +00:00
# endif
2018-03-06 22:51:50 +00:00
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_START ) ) {
SDL_strlcat ( mapping_string , " start:b6, " , sizeof ( mapping_string ) ) ;
}
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_LEFTSTICK ) ) {
SDL_strlcat ( mapping_string , " leftstick:b7, " , sizeof ( mapping_string ) ) ;
}
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_RIGHTSTICK ) ) {
SDL_strlcat ( mapping_string , " rightstick:b8, " , sizeof ( mapping_string ) ) ;
}
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_LEFTSHOULDER ) ) {
SDL_strlcat ( mapping_string , " leftshoulder:b9, " , sizeof ( mapping_string ) ) ;
}
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_RIGHTSHOULDER ) ) {
SDL_strlcat ( mapping_string , " rightshoulder:b10, " , sizeof ( mapping_string ) ) ;
}
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_DPAD_UP ) ) {
SDL_strlcat ( mapping_string , " dpup:b11, " , sizeof ( mapping_string ) ) ;
}
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_DPAD_DOWN ) ) {
SDL_strlcat ( mapping_string , " dpdown:b12, " , sizeof ( mapping_string ) ) ;
}
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_DPAD_LEFT ) ) {
SDL_strlcat ( mapping_string , " dpleft:b13, " , sizeof ( mapping_string ) ) ;
}
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_DPAD_RIGHT ) ) {
SDL_strlcat ( mapping_string , " dpright:b14, " , sizeof ( mapping_string ) ) ;
}
if ( axis_mask & ( 1 < < SDL_CONTROLLER_AXIS_LEFTX ) ) {
SDL_strlcat ( mapping_string , " leftx:a0, " , sizeof ( mapping_string ) ) ;
}
if ( axis_mask & ( 1 < < SDL_CONTROLLER_AXIS_LEFTY ) ) {
SDL_strlcat ( mapping_string , " lefty:a1, " , sizeof ( mapping_string ) ) ;
}
if ( axis_mask & ( 1 < < SDL_CONTROLLER_AXIS_RIGHTX ) ) {
SDL_strlcat ( mapping_string , " rightx:a2, " , sizeof ( mapping_string ) ) ;
}
if ( axis_mask & ( 1 < < SDL_CONTROLLER_AXIS_RIGHTY ) ) {
SDL_strlcat ( mapping_string , " righty:a3, " , sizeof ( mapping_string ) ) ;
}
if ( axis_mask & ( 1 < < SDL_CONTROLLER_AXIS_TRIGGERLEFT ) ) {
SDL_strlcat ( mapping_string , " lefttrigger:a4, " , sizeof ( mapping_string ) ) ;
}
if ( axis_mask & ( 1 < < SDL_CONTROLLER_AXIS_TRIGGERRIGHT ) ) {
SDL_strlcat ( mapping_string , " righttrigger:a5, " , sizeof ( mapping_string ) ) ;
}
return SDL_PrivateAddMappingForGUID ( guid , mapping_string ,
& existing , SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT ) ;
}
# endif /* __ANDROID__ */
2015-12-09 20:11:40 +00:00
/*
* Helper function to determine pre - calculated offset to certain joystick mappings
*/
2017-08-09 18:59:29 +00:00
static ControllerMapping_t * SDL_PrivateGetControllerMappingForNameAndGUID ( const char * name , SDL_JoystickGUID guid )
2015-12-09 20:11:40 +00:00
{
ControllerMapping_t * mapping ;
2017-08-09 18:59:29 +00:00
mapping = SDL_PrivateGetControllerMappingForGUID ( & guid ) ;
2015-12-09 20:11:40 +00:00
# ifdef __LINUX__
2017-08-09 18:59:29 +00:00
if ( ! mapping & & name ) {
if ( SDL_strstr ( name , " Xbox 360 Wireless Receiver " ) ) {
/* The Linux driver xpad.c maps the wireless dpad to buttons */
SDL_bool existing ;
2017-08-09 19:11:59 +00:00
mapping = SDL_PrivateAddMappingForGUID ( guid ,
2015-12-09 20:11:40 +00:00
" none,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3, " ,
2017-08-09 18:59:29 +00:00
& existing , SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT ) ;
2015-12-09 20:11:40 +00:00
}
}
# endif /* __LINUX__ */
2017-08-09 18:59:29 +00:00
if ( ! mapping & & name ) {
2017-08-14 03:39:00 +00:00
if ( SDL_strstr ( name , " Xbox " ) | | SDL_strstr ( name , " X-Box " ) | | SDL_strstr ( name , " XBOX " ) ) {
2017-08-09 18:59:29 +00:00
mapping = s_pXInputMapping ;
2015-12-09 20:11:40 +00:00
}
}
2018-03-06 22:51:50 +00:00
# ifdef __ANDROID__
if ( ! mapping ) {
mapping = SDL_CreateMappingForAndroidController ( name , guid ) ;
}
# endif
if ( ! mapping ) {
mapping = s_pDefaultMapping ;
}
2015-12-09 20:11:40 +00:00
return mapping ;
}
2017-08-09 18:59:29 +00:00
static ControllerMapping_t * SDL_PrivateGetControllerMapping ( int device_index )
{
2017-10-09 18:45:15 +00:00
const char * name ;
SDL_JoystickGUID guid ;
ControllerMapping_t * mapping ;
2017-10-10 18:10:15 +00:00
SDL_LockJoysticks ( ) ;
2017-12-19 18:48:29 +00:00
if ( ( device_index < 0 ) | | ( device_index > = SDL_NumJoysticks ( ) ) ) {
SDL_SetError ( " There are %d joysticks available " , SDL_NumJoysticks ( ) ) ;
SDL_UnlockJoysticks ( ) ;
return ( NULL ) ;
}
2017-10-09 18:45:15 +00:00
name = SDL_JoystickNameForIndex ( device_index ) ;
guid = SDL_JoystickGetDeviceGUID ( device_index ) ;
mapping = SDL_PrivateGetControllerMappingForNameAndGUID ( name , guid ) ;
2017-10-10 18:10:15 +00:00
SDL_UnlockJoysticks ( ) ;
2017-08-09 18:59:29 +00:00
return mapping ;
}
2015-06-21 15:33:46 +00:00
/*
* Add or update an entry into the Mappings Database
*/
int
SDL_GameControllerAddMappingsFromRW ( SDL_RWops * rw , int freerw )
{
const char * platform = SDL_GetPlatform ( ) ;
int controllers = 0 ;
char * buf , * line , * line_end , * tmp , * comma , line_platform [ 64 ] ;
size_t db_size , platform_len ;
if ( rw = = NULL ) {
return SDL_SetError ( " Invalid RWops " ) ;
}
db_size = ( size_t ) SDL_RWsize ( rw ) ;
buf = ( char * ) SDL_malloc ( db_size + 1 ) ;
if ( buf = = NULL ) {
if ( freerw ) {
SDL_RWclose ( rw ) ;
}
return SDL_SetError ( " Could not allocate space to read DB into memory " ) ;
}
if ( SDL_RWread ( rw , buf , db_size , 1 ) ! = 1 ) {
if ( freerw ) {
SDL_RWclose ( rw ) ;
}
SDL_free ( buf ) ;
return SDL_SetError ( " Could not read DB " ) ;
}
if ( freerw ) {
SDL_RWclose ( rw ) ;
}
buf [ db_size ] = ' \0 ' ;
line = buf ;
while ( line < buf + db_size ) {
line_end = SDL_strchr ( line , ' \n ' ) ;
if ( line_end ! = NULL ) {
* line_end = ' \0 ' ;
} else {
line_end = buf + db_size ;
}
/* Extract and verify the platform */
tmp = SDL_strstr ( line , SDL_CONTROLLER_PLATFORM_FIELD ) ;
if ( tmp ! = NULL ) {
tmp + = SDL_strlen ( SDL_CONTROLLER_PLATFORM_FIELD ) ;
comma = SDL_strchr ( tmp , ' , ' ) ;
if ( comma ! = NULL ) {
platform_len = comma - tmp + 1 ;
if ( platform_len + 1 < SDL_arraysize ( line_platform ) ) {
SDL_strlcpy ( line_platform , tmp , platform_len ) ;
if ( SDL_strncasecmp ( line_platform , platform , platform_len ) = = 0 & &
SDL_GameControllerAddMapping ( line ) > 0 ) {
controllers + + ;
}
}
}
}
line = line_end + 1 ;
}
SDL_free ( buf ) ;
return controllers ;
}
/*
2016-11-11 21:29:23 +00:00
* Add or update an entry into the Mappings Database with a priority
2015-06-21 15:33:46 +00:00
*/
2016-11-11 21:29:23 +00:00
static int
SDL_PrivateGameControllerAddMapping ( const char * mappingString , SDL_ControllerMappingPriority priority )
2015-06-21 15:33:46 +00:00
{
char * pchGUID ;
SDL_JoystickGUID jGUID ;
2018-03-06 22:51:50 +00:00
SDL_bool is_default_mapping = SDL_FALSE ;
2015-06-21 15:33:46 +00:00
SDL_bool is_xinput_mapping = SDL_FALSE ;
2015-12-09 20:11:40 +00:00
SDL_bool existing = SDL_FALSE ;
ControllerMapping_t * pControllerMapping ;
2015-06-21 15:33:46 +00:00
if ( ! mappingString ) {
return SDL_InvalidParamError ( " mappingString " ) ;
}
pchGUID = SDL_PrivateGetControllerGUIDFromMappingString ( mappingString ) ;
if ( ! pchGUID ) {
return SDL_SetError ( " Couldn't parse GUID from %s " , mappingString ) ;
}
2018-03-06 22:51:50 +00:00
if ( ! SDL_strcasecmp ( pchGUID , " default " ) ) {
is_default_mapping = SDL_TRUE ;
} else if ( ! SDL_strcasecmp ( pchGUID , " xinput " ) ) {
2015-06-21 15:33:46 +00:00
is_xinput_mapping = SDL_TRUE ;
}
jGUID = SDL_JoystickGetGUIDFromString ( pchGUID ) ;
SDL_free ( pchGUID ) ;
2016-11-11 21:29:23 +00:00
pControllerMapping = SDL_PrivateAddMappingForGUID ( jGUID , mappingString , & existing , priority ) ;
2015-12-09 20:11:40 +00:00
if ( ! pControllerMapping ) {
return - 1 ;
2015-06-21 15:33:46 +00:00
}
2015-12-09 20:11:40 +00:00
if ( existing ) {
2015-06-21 15:33:46 +00:00
return 0 ;
} else {
2018-03-06 22:51:50 +00:00
if ( is_default_mapping ) {
s_pDefaultMapping = pControllerMapping ;
} else if ( is_xinput_mapping ) {
2015-06-21 15:33:46 +00:00
s_pXInputMapping = pControllerMapping ;
}
return 1 ;
}
}
2016-11-11 21:29:23 +00:00
/*
* Add or update an entry into the Mappings Database
*/
int
SDL_GameControllerAddMapping ( const char * mappingString )
{
return SDL_PrivateGameControllerAddMapping ( mappingString , SDL_CONTROLLER_MAPPING_PRIORITY_API ) ;
}
2017-01-14 20:36:06 +00:00
/*
2016-11-29 14:36:57 +00:00
* Get the number of mappings installed
*/
int
2016-12-26 10:12:21 +00:00
SDL_GameControllerNumMappings ( void )
2016-11-29 14:36:57 +00:00
{
int num_mappings = 0 ;
ControllerMapping_t * mapping ;
for ( mapping = s_pSupportedControllers ; mapping ; mapping = mapping - > next ) {
if ( SDL_memcmp ( & mapping - > guid , & s_zeroGUID , sizeof ( mapping - > guid ) ) = = 0 ) {
continue ;
}
+ + num_mappings ;
}
return num_mappings ;
}
2017-01-14 20:36:06 +00:00
/*
2016-11-29 14:36:57 +00:00
* Get the mapping at a particular index .
*/
char *
SDL_GameControllerMappingForIndex ( int mapping_index )
{
ControllerMapping_t * mapping ;
for ( mapping = s_pSupportedControllers ; mapping ; mapping = mapping - > next ) {
if ( SDL_memcmp ( & mapping - > guid , & s_zeroGUID , sizeof ( mapping - > guid ) ) = = 0 ) {
continue ;
}
if ( mapping_index = = 0 ) {
char * pMappingString ;
char pchGUID [ 33 ] ;
size_t needed ;
SDL_JoystickGetGUIDString ( mapping - > guid , pchGUID , sizeof ( pchGUID ) ) ;
/* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
needed = SDL_strlen ( pchGUID ) + 1 + SDL_strlen ( mapping - > name ) + 1 + SDL_strlen ( mapping - > mapping ) + 1 ;
pMappingString = SDL_malloc ( needed ) ;
if ( ! pMappingString ) {
SDL_OutOfMemory ( ) ;
return NULL ;
}
SDL_snprintf ( pMappingString , needed , " %s,%s,%s " , pchGUID , mapping - > name , mapping - > mapping ) ;
return pMappingString ;
}
- - mapping_index ;
}
return NULL ;
}
2015-06-21 15:33:46 +00:00
/*
* Get the mapping string for this GUID
*/
char *
SDL_GameControllerMappingForGUID ( SDL_JoystickGUID guid )
{
char * pMappingString = NULL ;
ControllerMapping_t * mapping = SDL_PrivateGetControllerMappingForGUID ( & guid ) ;
if ( mapping ) {
char pchGUID [ 33 ] ;
size_t needed ;
SDL_JoystickGetGUIDString ( guid , pchGUID , sizeof ( pchGUID ) ) ;
/* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
needed = SDL_strlen ( pchGUID ) + 1 + SDL_strlen ( mapping - > name ) + 1 + SDL_strlen ( mapping - > mapping ) + 1 ;
pMappingString = SDL_malloc ( needed ) ;
if ( ! pMappingString ) {
SDL_OutOfMemory ( ) ;
return NULL ;
}
SDL_snprintf ( pMappingString , needed , " %s,%s,%s " , pchGUID , mapping - > name , mapping - > mapping ) ;
}
return pMappingString ;
}
/*
* Get the mapping string for this device
*/
char *
SDL_GameControllerMapping ( SDL_GameController * gamecontroller )
{
if ( ! gamecontroller ) {
return NULL ;
}
2016-12-27 09:39:07 +00:00
return SDL_GameControllerMappingForGUID ( gamecontroller - > guid ) ;
2015-06-21 15:33:46 +00:00
}
static void
SDL_GameControllerLoadHints ( )
{
const char * hint = SDL_GetHint ( SDL_HINT_GAMECONTROLLERCONFIG ) ;
if ( hint & & hint [ 0 ] ) {
size_t nchHints = SDL_strlen ( hint ) ;
char * pUserMappings = SDL_malloc ( nchHints + 1 ) ;
char * pTempMappings = pUserMappings ;
SDL_memcpy ( pUserMappings , hint , nchHints ) ;
pUserMappings [ nchHints ] = ' \0 ' ;
while ( pUserMappings ) {
char * pchNewLine = NULL ;
pchNewLine = SDL_strchr ( pUserMappings , ' \n ' ) ;
if ( pchNewLine )
* pchNewLine = ' \0 ' ;
2016-11-11 21:29:23 +00:00
SDL_PrivateGameControllerAddMapping ( pUserMappings , SDL_CONTROLLER_MAPPING_PRIORITY_USER ) ;
2015-06-21 15:33:46 +00:00
if ( pchNewLine ) {
pUserMappings = pchNewLine + 1 ;
} else {
pUserMappings = NULL ;
}
}
SDL_free ( pTempMappings ) ;
}
}
2017-09-22 15:30:52 +00:00
/*
* Fill the given buffer with the expected controller mapping filepath .
* Usually this will just be CONTROLLER_MAPPING_FILE , but for Android ,
* we want to get the internal storage path .
*/
static SDL_bool SDL_GetControllerMappingFilePath ( char * path , size_t size )
{
# ifdef CONTROLLER_MAPPING_FILE
# define STRING(X) SDL_STRINGIFY_ARG(X)
return SDL_strlcpy ( path , STRING ( CONTROLLER_MAPPING_FILE ) , size ) < size ;
# elif defined(__ANDROID__)
return SDL_snprintf ( path , size , " %s/controller_map.txt " , SDL_AndroidGetInternalStoragePath ( ) ) < size ;
# else
return SDL_FALSE ;
# endif
}
2015-06-21 15:33:46 +00:00
/*
* Initialize the game controller system , mostly load our DB of controller config mappings
*/
int
2017-08-09 18:59:29 +00:00
SDL_GameControllerInitMappings ( void )
2015-06-21 15:33:46 +00:00
{
2017-09-22 15:30:52 +00:00
char szControllerMapPath [ 1024 ] ;
2015-06-21 15:33:46 +00:00
int i = 0 ;
const char * pMappingString = NULL ;
pMappingString = s_ControllerMappings [ i ] ;
while ( pMappingString ) {
2016-11-11 21:29:23 +00:00
SDL_PrivateGameControllerAddMapping ( pMappingString , SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT ) ;
2015-06-21 15:33:46 +00:00
i + + ;
pMappingString = s_ControllerMappings [ i ] ;
}
2017-09-22 15:30:52 +00:00
if ( SDL_GetControllerMappingFilePath ( szControllerMapPath , sizeof ( szControllerMapPath ) ) ) {
SDL_GameControllerAddMappingsFromFile ( szControllerMapPath ) ;
}
2015-06-21 15:33:46 +00:00
/* load in any user supplied config */
SDL_GameControllerLoadHints ( ) ;
2017-08-09 18:59:29 +00:00
SDL_AddHintCallback ( SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES ,
SDL_GameControllerIgnoreDevicesChanged , NULL ) ;
SDL_AddHintCallback ( SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT ,
SDL_GameControllerIgnoreDevicesExceptChanged , NULL ) ;
return ( 0 ) ;
}
int
SDL_GameControllerInit ( void )
{
int i ;
2015-06-21 15:33:46 +00:00
/* watch for joy events and fire controller ones if needed */
SDL_AddEventWatch ( SDL_GameControllerEventWatcher , NULL ) ;
/* Send added events for controllers currently attached */
for ( i = 0 ; i < SDL_NumJoysticks ( ) ; + + i ) {
if ( SDL_IsGameController ( i ) ) {
SDL_Event deviceevent ;
deviceevent . type = SDL_CONTROLLERDEVICEADDED ;
deviceevent . cdevice . which = i ;
SDL_PushEvent ( & deviceevent ) ;
}
}
return ( 0 ) ;
}
/*
* Get the implementation dependent name of a controller
*/
const char *
SDL_GameControllerNameForIndex ( int device_index )
{
2016-12-27 09:39:07 +00:00
ControllerMapping_t * pSupportedController = SDL_PrivateGetControllerMapping ( device_index ) ;
2015-06-21 15:33:46 +00:00
if ( pSupportedController ) {
2018-03-02 18:56:21 +00:00
if ( SDL_strcmp ( pSupportedController - > name , " * " ) = = 0 ) {
return SDL_JoystickNameForIndex ( device_index ) ;
} else {
return pSupportedController - > name ;
}
2015-06-21 15:33:46 +00:00
}
return NULL ;
}
2018-03-07 21:30:40 +00:00
/**
* Get the mapping of a game controller .
* This can be called before any controllers are opened .
* If no mapping can be found , this function returns NULL .
*/
char *
SDL_GameControllerMappingForDeviceIndex ( int joystick_index )
{
char * pMappingString = NULL ;
ControllerMapping_t * mapping ;
SDL_LockJoysticks ( ) ;
mapping = SDL_PrivateGetControllerMapping ( joystick_index ) ;
if ( mapping ) {
SDL_JoystickGUID guid ;
char pchGUID [ 33 ] ;
size_t needed ;
guid = SDL_JoystickGetDeviceGUID ( joystick_index ) ;
SDL_JoystickGetGUIDString ( guid , pchGUID , sizeof ( pchGUID ) ) ;
/* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
needed = SDL_strlen ( pchGUID ) + 1 + SDL_strlen ( mapping - > name ) + 1 + SDL_strlen ( mapping - > mapping ) + 1 ;
pMappingString = SDL_malloc ( needed ) ;
if ( ! pMappingString ) {
SDL_OutOfMemory ( ) ;
SDL_UnlockJoysticks ( ) ;
return NULL ;
}
SDL_snprintf ( pMappingString , needed , " %s,%s,%s " , pchGUID , mapping - > name , mapping - > mapping ) ;
}
SDL_UnlockJoysticks ( ) ;
return pMappingString ;
}
2017-08-09 18:59:29 +00:00
/*
* Return 1 if the joystick with this name and GUID is a supported controller
*/
SDL_bool
SDL_IsGameControllerNameAndGUID ( const char * name , SDL_JoystickGUID guid )
{
ControllerMapping_t * pSupportedController = SDL_PrivateGetControllerMappingForNameAndGUID ( name , guid ) ;
if ( pSupportedController ) {
return SDL_TRUE ;
}
return SDL_FALSE ;
}
2015-06-21 15:33:46 +00:00
/*
* Return 1 if the joystick at this device index is a supported controller
*/
SDL_bool
SDL_IsGameController ( int device_index )
{
2016-12-27 09:39:07 +00:00
ControllerMapping_t * pSupportedController = SDL_PrivateGetControllerMapping ( device_index ) ;
2015-06-21 15:33:46 +00:00
if ( pSupportedController ) {
return SDL_TRUE ;
}
return SDL_FALSE ;
}
2017-08-09 18:59:29 +00:00
/*
* Return 1 if the game controller should be ignored by SDL
*/
SDL_bool SDL_ShouldIgnoreGameController ( const char * name , SDL_JoystickGUID guid )
{
int i ;
Uint16 vendor ;
Uint16 product ;
Uint32 vidpid ;
if ( SDL_allowed_controllers . num_entries = = 0 & &
SDL_ignored_controllers . num_entries = = 0 ) {
return SDL_FALSE ;
}
SDL_GetJoystickGUIDInfo ( guid , & vendor , & product , NULL ) ;
vidpid = MAKE_VIDPID ( vendor , product ) ;
2017-08-09 19:38:20 +00:00
if ( SDL_GetHintBoolean ( " SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD " , SDL_FALSE ) ) {
/* We shouldn't ignore Steam's virtual gamepad since it's using the hints to filter out the real controllers so it can remap input for the virtual controller */
SDL_bool bSteamVirtualGamepad = SDL_FALSE ;
# if defined(__LINUX__)
bSteamVirtualGamepad = ( vendor = = 0x28DE & & product = = 0x11FF ) ;
# elif defined(__MACOSX__)
bSteamVirtualGamepad = ( SDL_strncmp ( name , " GamePad- " , 8 ) = = 0 ) ;
# elif defined(__WIN32__)
/* We can't tell on Windows, but Steam will block others in input hooks */
bSteamVirtualGamepad = SDL_TRUE ;
# endif
if ( bSteamVirtualGamepad ) {
return SDL_FALSE ;
}
}
2017-08-09 18:59:29 +00:00
if ( SDL_allowed_controllers . num_entries > 0 ) {
for ( i = 0 ; i < SDL_allowed_controllers . num_entries ; + + i ) {
if ( vidpid = = SDL_allowed_controllers . entries [ i ] ) {
return SDL_FALSE ;
}
}
return SDL_TRUE ;
} else {
for ( i = 0 ; i < SDL_ignored_controllers . num_entries ; + + i ) {
if ( vidpid = = SDL_ignored_controllers . entries [ i ] ) {
return SDL_TRUE ;
}
}
return SDL_FALSE ;
}
}
2015-06-21 15:33:46 +00:00
/*
* Open a controller for use - the index passed as an argument refers to
* the N ' th controller on the system . This index is the value which will
* identify this controller in future controller events .
*
* This function returns a controller identifier , or NULL if an error occurred .
*/
SDL_GameController *
SDL_GameControllerOpen ( int device_index )
{
SDL_GameController * gamecontroller ;
SDL_GameController * gamecontrollerlist ;
ControllerMapping_t * pSupportedController = NULL ;
2017-12-19 18:48:29 +00:00
SDL_LockJoysticks ( ) ;
2015-06-21 15:33:46 +00:00
if ( ( device_index < 0 ) | | ( device_index > = SDL_NumJoysticks ( ) ) ) {
SDL_SetError ( " There are %d joysticks available " , SDL_NumJoysticks ( ) ) ;
2017-12-19 18:48:29 +00:00
SDL_UnlockJoysticks ( ) ;
2015-06-21 15:33:46 +00:00
return ( NULL ) ;
}
gamecontrollerlist = SDL_gamecontrollers ;
/* If the controller is already open, return it */
while ( gamecontrollerlist ) {
if ( SDL_SYS_GetInstanceIdOfDeviceIndex ( device_index ) = = gamecontrollerlist - > joystick - > instance_id ) {
gamecontroller = gamecontrollerlist ;
+ + gamecontroller - > ref_count ;
2017-10-10 18:10:15 +00:00
SDL_UnlockJoysticks ( ) ;
2015-06-21 15:33:46 +00:00
return ( gamecontroller ) ;
}
gamecontrollerlist = gamecontrollerlist - > next ;
}
/* Find a controller mapping */
pSupportedController = SDL_PrivateGetControllerMapping ( device_index ) ;
if ( ! pSupportedController ) {
SDL_SetError ( " Couldn't find mapping for device (%d) " , device_index ) ;
2017-10-10 18:10:15 +00:00
SDL_UnlockJoysticks ( ) ;
2016-12-08 18:13:45 +00:00
return NULL ;
2015-06-21 15:33:46 +00:00
}
2017-01-14 20:36:06 +00:00
/* Create and initialize the controller */
2016-12-27 09:39:07 +00:00
gamecontroller = ( SDL_GameController * ) SDL_calloc ( 1 , sizeof ( * gamecontroller ) ) ;
2015-06-21 15:33:46 +00:00
if ( gamecontroller = = NULL ) {
SDL_OutOfMemory ( ) ;
2017-10-10 18:10:15 +00:00
SDL_UnlockJoysticks ( ) ;
2015-06-21 15:33:46 +00:00
return NULL ;
}
gamecontroller - > joystick = SDL_JoystickOpen ( device_index ) ;
if ( ! gamecontroller - > joystick ) {
SDL_free ( gamecontroller ) ;
2017-10-10 18:10:15 +00:00
SDL_UnlockJoysticks ( ) ;
2015-06-21 15:33:46 +00:00
return NULL ;
}
2016-12-28 19:10:48 +00:00
if ( gamecontroller - > joystick - > naxes ) {
gamecontroller - > last_match_axis = ( SDL_ExtendedGameControllerBind * * ) SDL_calloc ( gamecontroller - > joystick - > naxes , sizeof ( * gamecontroller - > last_match_axis ) ) ;
if ( ! gamecontroller - > last_match_axis ) {
SDL_OutOfMemory ( ) ;
SDL_JoystickClose ( gamecontroller - > joystick ) ;
SDL_free ( gamecontroller ) ;
2017-10-10 18:10:15 +00:00
SDL_UnlockJoysticks ( ) ;
2016-12-28 19:10:48 +00:00
return NULL ;
}
}
if ( gamecontroller - > joystick - > nhats ) {
gamecontroller - > last_hat_mask = ( Uint8 * ) SDL_calloc ( gamecontroller - > joystick - > nhats , sizeof ( * gamecontroller - > last_hat_mask ) ) ;
if ( ! gamecontroller - > last_hat_mask ) {
SDL_OutOfMemory ( ) ;
SDL_JoystickClose ( gamecontroller - > joystick ) ;
SDL_free ( gamecontroller - > last_match_axis ) ;
SDL_free ( gamecontroller ) ;
2017-10-10 18:10:15 +00:00
SDL_UnlockJoysticks ( ) ;
2016-12-28 19:10:48 +00:00
return NULL ;
}
}
2015-06-21 15:33:46 +00:00
2016-12-27 09:39:07 +00:00
SDL_PrivateLoadButtonMapping ( gamecontroller , pSupportedController - > guid , pSupportedController - > name , pSupportedController - > mapping ) ;
2016-10-07 23:04:15 +00:00
2017-01-14 20:36:06 +00:00
/* Add the controller to list */
2015-06-21 15:33:46 +00:00
+ + gamecontroller - > ref_count ;
2017-01-14 20:36:06 +00:00
/* Link the controller in the list */
2015-06-21 15:33:46 +00:00
gamecontroller - > next = SDL_gamecontrollers ;
SDL_gamecontrollers = gamecontroller ;
2017-10-10 18:10:15 +00:00
SDL_UnlockJoysticks ( ) ;
2015-06-21 15:33:46 +00:00
return ( gamecontroller ) ;
}
/*
* Manually pump for controller updates .
*/
void
SDL_GameControllerUpdate ( void )
{
/* Just for API completeness; the joystick API does all the work. */
SDL_JoystickUpdate ( ) ;
}
/*
* Get the current state of an axis control on a controller
*/
Sint16
SDL_GameControllerGetAxis ( SDL_GameController * gamecontroller , SDL_GameControllerAxis axis )
{
2016-12-27 09:39:07 +00:00
int i ;
2015-06-21 15:33:46 +00:00
if ( ! gamecontroller )
return 0 ;
2016-12-27 09:39:07 +00:00
for ( i = 0 ; i < gamecontroller - > num_bindings ; + + i ) {
SDL_ExtendedGameControllerBind * binding = & gamecontroller - > bindings [ i ] ;
if ( binding - > outputType = = SDL_CONTROLLER_BINDTYPE_AXIS & & binding - > output . axis . axis = = axis ) {
int value = 0 ;
SDL_bool valid_input_range ;
SDL_bool valid_output_range ;
if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_AXIS ) {
value = SDL_JoystickGetAxis ( gamecontroller - > joystick , binding - > input . axis . axis ) ;
if ( binding - > input . axis . axis_min < binding - > input . axis . axis_max ) {
valid_input_range = ( value > = binding - > input . axis . axis_min & & value < = binding - > input . axis . axis_max ) ;
} else {
valid_input_range = ( value > = binding - > input . axis . axis_max & & value < = binding - > input . axis . axis_min ) ;
}
if ( valid_input_range ) {
if ( binding - > input . axis . axis_min ! = binding - > output . axis . axis_min | | binding - > input . axis . axis_max ! = binding - > output . axis . axis_max ) {
float normalized_value = ( float ) ( value - binding - > input . axis . axis_min ) / ( binding - > input . axis . axis_max - binding - > input . axis . axis_min ) ;
value = binding - > output . axis . axis_min + ( int ) ( normalized_value * ( binding - > output . axis . axis_max - binding - > output . axis . axis_min ) ) ;
}
}
} else if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_BUTTON ) {
value = SDL_JoystickGetButton ( gamecontroller - > joystick , binding - > input . button ) ;
if ( value = = SDL_PRESSED ) {
value = binding - > output . axis . axis_max ;
}
} else if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_HAT ) {
int hat_mask = SDL_JoystickGetHat ( gamecontroller - > joystick , binding - > input . hat . hat ) ;
if ( hat_mask & binding - > input . hat . hat_mask ) {
value = binding - > output . axis . axis_max ;
}
}
if ( binding - > output . axis . axis_min < binding - > output . axis . axis_max ) {
valid_output_range = ( value > = binding - > output . axis . axis_min & & value < = binding - > output . axis . axis_max ) ;
} else {
valid_output_range = ( value > = binding - > output . axis . axis_max & & value < = binding - > output . axis . axis_min ) ;
}
2016-12-27 10:04:38 +00:00
/* If the value is zero, there might be another binding that makes it non-zero */
2016-12-27 09:39:07 +00:00
if ( value ! = 0 & & valid_output_range ) {
return ( Sint16 ) value ;
}
2015-06-21 15:33:46 +00:00
}
}
return 0 ;
}
/*
* Get the current state of a button on a controller
*/
Uint8
SDL_GameControllerGetButton ( SDL_GameController * gamecontroller , SDL_GameControllerButton button )
{
2016-12-27 09:39:07 +00:00
int i ;
2015-06-21 15:33:46 +00:00
2016-12-27 09:39:07 +00:00
if ( ! gamecontroller )
2015-06-21 15:33:46 +00:00
return 0 ;
2016-12-27 09:39:07 +00:00
for ( i = 0 ; i < gamecontroller - > num_bindings ; + + i ) {
SDL_ExtendedGameControllerBind * binding = & gamecontroller - > bindings [ i ] ;
if ( binding - > outputType = = SDL_CONTROLLER_BINDTYPE_BUTTON & & binding - > output . button = = button ) {
if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_AXIS ) {
SDL_bool valid_input_range ;
int value = SDL_JoystickGetAxis ( gamecontroller - > joystick , binding - > input . axis . axis ) ;
int threshold = binding - > input . axis . axis_min + ( binding - > input . axis . axis_max - binding - > input . axis . axis_min ) / 2 ;
if ( binding - > input . axis . axis_min < binding - > input . axis . axis_max ) {
valid_input_range = ( value > = binding - > input . axis . axis_min & & value < = binding - > input . axis . axis_max ) ;
if ( valid_input_range ) {
return ( value > = threshold ) ? SDL_PRESSED : SDL_RELEASED ;
}
} else {
valid_input_range = ( value > = binding - > input . axis . axis_max & & value < = binding - > input . axis . axis_min ) ;
if ( valid_input_range ) {
return ( value < = threshold ) ? SDL_PRESSED : SDL_RELEASED ;
}
}
} else if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_BUTTON ) {
return SDL_JoystickGetButton ( gamecontroller - > joystick , binding - > input . button ) ;
} else if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_HAT ) {
int hat_mask = SDL_JoystickGetHat ( gamecontroller - > joystick , binding - > input . hat . hat ) ;
return ( hat_mask & binding - > input . hat . hat_mask ) ? SDL_PRESSED : SDL_RELEASED ;
}
}
2015-06-21 15:33:46 +00:00
}
2016-12-27 09:39:07 +00:00
return SDL_RELEASED ;
2015-06-21 15:33:46 +00:00
}
2016-11-11 01:19:34 +00:00
const char *
SDL_GameControllerName ( SDL_GameController * gamecontroller )
{
if ( ! gamecontroller )
return NULL ;
2018-03-02 18:56:21 +00:00
if ( SDL_strcmp ( gamecontroller - > name , " * " ) = = 0 ) {
return SDL_JoystickName ( SDL_GameControllerGetJoystick ( gamecontroller ) ) ;
} else {
return gamecontroller - > name ;
}
2016-11-11 01:19:34 +00:00
}
Uint16
SDL_GameControllerGetVendor ( SDL_GameController * gamecontroller )
{
return SDL_JoystickGetVendor ( SDL_GameControllerGetJoystick ( gamecontroller ) ) ;
}
Uint16
SDL_GameControllerGetProduct ( SDL_GameController * gamecontroller )
{
return SDL_JoystickGetProduct ( SDL_GameControllerGetJoystick ( gamecontroller ) ) ;
}
Uint16
SDL_GameControllerGetProductVersion ( SDL_GameController * gamecontroller )
{
return SDL_JoystickGetProductVersion ( SDL_GameControllerGetJoystick ( gamecontroller ) ) ;
}
2015-06-21 15:33:46 +00:00
/*
2017-01-14 20:36:06 +00:00
* Return if the controller in question is currently attached to the system ,
2015-06-21 15:33:46 +00:00
* \ return 0 if not plugged in , 1 if still present .
*/
SDL_bool
SDL_GameControllerGetAttached ( SDL_GameController * gamecontroller )
{
if ( ! gamecontroller )
return SDL_FALSE ;
return SDL_JoystickGetAttached ( gamecontroller - > joystick ) ;
}
/*
* Get the joystick for this controller
*/
SDL_Joystick * SDL_GameControllerGetJoystick ( SDL_GameController * gamecontroller )
{
if ( ! gamecontroller )
return NULL ;
return gamecontroller - > joystick ;
}
2015-11-14 17:35:45 +00:00
/*
* Find the SDL_GameController that owns this instance id
*/
SDL_GameController *
SDL_GameControllerFromInstanceID ( SDL_JoystickID joyid )
{
2016-12-08 18:13:45 +00:00
SDL_GameController * gamecontroller ;
2017-10-10 18:10:15 +00:00
SDL_LockJoysticks ( ) ;
2016-12-08 18:13:45 +00:00
gamecontroller = SDL_gamecontrollers ;
2015-11-14 17:35:45 +00:00
while ( gamecontroller ) {
if ( gamecontroller - > joystick - > instance_id = = joyid ) {
2017-10-10 18:10:15 +00:00
SDL_UnlockJoysticks ( ) ;
2015-11-14 17:35:45 +00:00
return gamecontroller ;
}
gamecontroller = gamecontroller - > next ;
}
2017-10-10 18:10:15 +00:00
SDL_UnlockJoysticks ( ) ;
2015-11-14 17:35:45 +00:00
return NULL ;
}
2017-01-14 20:36:06 +00:00
/*
2015-06-21 15:33:46 +00:00
* Get the SDL joystick layer binding for this controller axis mapping
*/
SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis ( SDL_GameController * gamecontroller , SDL_GameControllerAxis axis )
{
2016-12-27 09:39:07 +00:00
int i ;
2015-06-21 15:33:46 +00:00
SDL_GameControllerButtonBind bind ;
2016-12-27 09:39:07 +00:00
SDL_zero ( bind ) ;
2015-06-21 15:33:46 +00:00
if ( ! gamecontroller | | axis = = SDL_CONTROLLER_AXIS_INVALID )
return bind ;
2016-12-27 09:39:07 +00:00
for ( i = 0 ; i < gamecontroller - > num_bindings ; + + i ) {
SDL_ExtendedGameControllerBind * binding = & gamecontroller - > bindings [ i ] ;
if ( binding - > outputType = = SDL_CONTROLLER_BINDTYPE_AXIS & & binding - > output . axis . axis = = axis ) {
bind . bindType = binding - > inputType ;
if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_AXIS ) {
/* FIXME: There might be multiple axes bound now that we have axis ranges... */
bind . value . axis = binding - > input . axis . axis ;
} else if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_BUTTON ) {
bind . value . button = binding - > input . button ;
} else if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_HAT ) {
bind . value . hat . hat = binding - > input . hat . hat ;
bind . value . hat . hat_mask = binding - > input . hat . hat_mask ;
}
break ;
}
2015-06-21 15:33:46 +00:00
}
return bind ;
}
2017-01-14 20:36:06 +00:00
/*
2015-06-21 15:33:46 +00:00
* Get the SDL joystick layer binding for this controller button mapping
*/
SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton ( SDL_GameController * gamecontroller , SDL_GameControllerButton button )
{
2016-12-27 09:39:07 +00:00
int i ;
2015-06-21 15:33:46 +00:00
SDL_GameControllerButtonBind bind ;
2016-12-27 09:39:07 +00:00
SDL_zero ( bind ) ;
2015-06-21 15:33:46 +00:00
if ( ! gamecontroller | | button = = SDL_CONTROLLER_BUTTON_INVALID )
return bind ;
2016-12-27 09:39:07 +00:00
for ( i = 0 ; i < gamecontroller - > num_bindings ; + + i ) {
SDL_ExtendedGameControllerBind * binding = & gamecontroller - > bindings [ i ] ;
if ( binding - > outputType = = SDL_CONTROLLER_BINDTYPE_BUTTON & & binding - > output . button = = button ) {
bind . bindType = binding - > inputType ;
if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_AXIS ) {
bind . value . axis = binding - > input . axis . axis ;
} else if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_BUTTON ) {
bind . value . button = binding - > input . button ;
} else if ( binding - > inputType = = SDL_CONTROLLER_BINDTYPE_HAT ) {
bind . value . hat . hat = binding - > input . hat . hat ;
bind . value . hat . hat_mask = binding - > input . hat . hat_mask ;
}
break ;
}
2015-06-21 15:33:46 +00:00
}
return bind ;
}
void
SDL_GameControllerClose ( SDL_GameController * gamecontroller )
{
SDL_GameController * gamecontrollerlist , * gamecontrollerlistprev ;
if ( ! gamecontroller )
return ;
2017-10-10 18:10:15 +00:00
SDL_LockJoysticks ( ) ;
2016-12-08 18:13:45 +00:00
2015-06-21 15:33:46 +00:00
/* First decrement ref count */
if ( - - gamecontroller - > ref_count > 0 ) {
2017-10-10 18:10:15 +00:00
SDL_UnlockJoysticks ( ) ;
2015-06-21 15:33:46 +00:00
return ;
}
SDL_JoystickClose ( gamecontroller - > joystick ) ;
gamecontrollerlist = SDL_gamecontrollers ;
gamecontrollerlistprev = NULL ;
while ( gamecontrollerlist ) {
if ( gamecontroller = = gamecontrollerlist ) {
if ( gamecontrollerlistprev ) {
/* unlink this entry */
gamecontrollerlistprev - > next = gamecontrollerlist - > next ;
} else {
SDL_gamecontrollers = gamecontroller - > next ;
}
break ;
}
gamecontrollerlistprev = gamecontrollerlist ;
gamecontrollerlist = gamecontrollerlist - > next ;
}
2016-12-27 09:39:07 +00:00
SDL_free ( gamecontroller - > bindings ) ;
SDL_free ( gamecontroller - > last_match_axis ) ;
SDL_free ( gamecontroller - > last_hat_mask ) ;
2015-06-21 15:33:46 +00:00
SDL_free ( gamecontroller ) ;
2016-12-08 18:13:45 +00:00
2017-10-10 18:10:15 +00:00
SDL_UnlockJoysticks ( ) ;
2015-06-21 15:33:46 +00:00
}
/*
* Quit the controller subsystem
*/
void
SDL_GameControllerQuit ( void )
{
2017-10-10 18:10:15 +00:00
SDL_LockJoysticks ( ) ;
2015-06-21 15:33:46 +00:00
while ( SDL_gamecontrollers ) {
SDL_gamecontrollers - > ref_count = 1 ;
SDL_GameControllerClose ( SDL_gamecontrollers ) ;
}
2017-10-10 18:10:15 +00:00
SDL_UnlockJoysticks ( ) ;
2017-08-09 18:59:29 +00:00
}
void
SDL_GameControllerQuitMappings ( void )
{
ControllerMapping_t * pControllerMap ;
2015-06-21 15:33:46 +00:00
while ( s_pSupportedControllers ) {
pControllerMap = s_pSupportedControllers ;
s_pSupportedControllers = s_pSupportedControllers - > next ;
SDL_free ( pControllerMap - > name ) ;
SDL_free ( pControllerMap - > mapping ) ;
SDL_free ( pControllerMap ) ;
}
SDL_DelEventWatch ( SDL_GameControllerEventWatcher , NULL ) ;
2017-08-09 18:59:29 +00:00
SDL_DelHintCallback ( SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES ,
SDL_GameControllerIgnoreDevicesChanged , NULL ) ;
SDL_DelHintCallback ( SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT ,
SDL_GameControllerIgnoreDevicesExceptChanged , NULL ) ;
if ( SDL_allowed_controllers . entries ) {
SDL_free ( SDL_allowed_controllers . entries ) ;
SDL_zero ( SDL_allowed_controllers ) ;
}
if ( SDL_ignored_controllers . entries ) {
SDL_free ( SDL_ignored_controllers . entries ) ;
SDL_zero ( SDL_ignored_controllers ) ;
}
2015-06-21 15:33:46 +00:00
}
/*
* Event filter to transform joystick events into appropriate game controller ones
*/
2016-12-27 09:39:07 +00:00
static int
2015-06-21 15:33:46 +00:00
SDL_PrivateGameControllerAxis ( SDL_GameController * gamecontroller , SDL_GameControllerAxis axis , Sint16 value )
{
int posted ;
/* translate the event, if desired */
posted = 0 ;
# if !SDL_EVENTS_DISABLED
if ( SDL_GetEventState ( SDL_CONTROLLERAXISMOTION ) = = SDL_ENABLE ) {
SDL_Event event ;
event . type = SDL_CONTROLLERAXISMOTION ;
event . caxis . which = gamecontroller - > joystick - > instance_id ;
event . caxis . axis = axis ;
event . caxis . value = value ;
posted = SDL_PushEvent ( & event ) = = 1 ;
}
# endif /* !SDL_EVENTS_DISABLED */
return ( posted ) ;
}
/*
* Event filter to transform joystick events into appropriate game controller ones
*/
2016-12-27 09:39:07 +00:00
static int
2015-06-21 15:33:46 +00:00
SDL_PrivateGameControllerButton ( SDL_GameController * gamecontroller , SDL_GameControllerButton button , Uint8 state )
{
int posted ;
# if !SDL_EVENTS_DISABLED
SDL_Event event ;
if ( button = = SDL_CONTROLLER_BUTTON_INVALID )
return ( 0 ) ;
switch ( state ) {
case SDL_PRESSED :
event . type = SDL_CONTROLLERBUTTONDOWN ;
break ;
case SDL_RELEASED :
event . type = SDL_CONTROLLERBUTTONUP ;
break ;
default :
/* Invalid state -- bail */
return ( 0 ) ;
}
# endif /* !SDL_EVENTS_DISABLED */
2018-03-19 21:42:51 +00:00
if ( button = = SDL_CONTROLLER_BUTTON_GUIDE ) {
Uint32 now = SDL_GetTicks ( ) ;
if ( state = = SDL_PRESSED ) {
gamecontroller - > guide_button_down = now ;
if ( gamecontroller - > joystick - > delayed_guide_button ) {
/* Skip duplicate press */
2018-03-19 21:52:53 +00:00
return ( 0 ) ;
2018-03-19 21:42:51 +00:00
}
} else {
if ( ! SDL_TICKS_PASSED ( now , gamecontroller - > guide_button_down + SDL_MINIMUM_GUIDE_BUTTON_DELAY_MS ) & & ! gamecontroller - > joystick - > force_recentering ) {
gamecontroller - > joystick - > delayed_guide_button = SDL_TRUE ;
2018-03-19 21:52:53 +00:00
return ( 0 ) ;
2018-03-19 21:42:51 +00:00
}
gamecontroller - > joystick - > delayed_guide_button = SDL_FALSE ;
}
}
2015-06-21 15:33:46 +00:00
/* translate the event, if desired */
posted = 0 ;
# if !SDL_EVENTS_DISABLED
if ( SDL_GetEventState ( event . type ) = = SDL_ENABLE ) {
event . cbutton . which = gamecontroller - > joystick - > instance_id ;
event . cbutton . button = button ;
event . cbutton . state = state ;
posted = SDL_PushEvent ( & event ) = = 1 ;
}
# endif /* !SDL_EVENTS_DISABLED */
return ( posted ) ;
}
/*
* Turn off controller events
*/
int
SDL_GameControllerEventState ( int state )
{
# if SDL_EVENTS_DISABLED
return SDL_IGNORE ;
# else
const Uint32 event_list [ ] = {
SDL_CONTROLLERAXISMOTION , SDL_CONTROLLERBUTTONDOWN , SDL_CONTROLLERBUTTONUP ,
SDL_CONTROLLERDEVICEADDED , SDL_CONTROLLERDEVICEREMOVED , SDL_CONTROLLERDEVICEREMAPPED ,
} ;
unsigned int i ;
switch ( state ) {
case SDL_QUERY :
state = SDL_IGNORE ;
for ( i = 0 ; i < SDL_arraysize ( event_list ) ; + + i ) {
state = SDL_EventState ( event_list [ i ] , SDL_QUERY ) ;
if ( state = = SDL_ENABLE ) {
break ;
}
}
break ;
default :
for ( i = 0 ; i < SDL_arraysize ( event_list ) ; + + i ) {
SDL_EventState ( event_list [ i ] , state ) ;
}
break ;
}
return ( state ) ;
# endif /* SDL_EVENTS_DISABLED */
}
2018-03-19 21:42:51 +00:00
void
SDL_GameControllerHandleDelayedGuideButton ( SDL_Joystick * joystick )
{
SDL_GameController * controllerlist = SDL_gamecontrollers ;
while ( controllerlist ) {
if ( controllerlist - > joystick = = joystick ) {
SDL_PrivateGameControllerButton ( controllerlist , SDL_CONTROLLER_BUTTON_GUIDE , SDL_RELEASED ) ;
break ;
}
controllerlist = controllerlist - > next ;
}
}
2015-06-21 15:33:46 +00:00
/* vi: set ts=4 sw=4 expandtab: */