2015-06-21 15:33:46 +00:00
/*
Simple DirectMedia Layer
2020-01-17 04:49:25 +00:00
Copyright ( C ) 1997 - 2020 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"
2020-11-06 19:30:52 +00:00
# include "usb_ids.h"
2015-06-21 15:33:46 +00:00
# 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
2020-02-17 22:15:47 +00:00
# define SDL_CONTROLLER_PLATFORM_FIELD "platform:"
2020-03-13 02:47:28 +00:00
# define SDL_CONTROLLER_HINT_FIELD "hint:"
2020-02-17 22:15:47 +00:00
# define SDL_CONTROLLER_SDKGE_FIELD "sdk>=:"
# define SDL_CONTROLLER_SDKLE_FIELD "sdk<=:"
2015-06-21 15:33:46 +00:00
/* 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
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 ) ;
}
2020-11-06 19:30:52 +00:00
static ControllerMapping_t * SDL_PrivateAddMappingForGUID ( SDL_JoystickGUID jGUID , const char * mappingString , SDL_bool * existing , SDL_ControllerMappingPriority priority ) ;
2020-11-17 01:36:47 +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 ;
2018-10-23 00:50:32 +00:00
SDL_bool isstack ;
2016-08-26 19:18:08 +00:00
num_events = SDL_PeepEvents ( NULL , 0 , SDL_PEEKEVENT , SDL_CONTROLLERDEVICEADDED , SDL_CONTROLLERDEVICEADDED ) ;
if ( num_events < = 0 ) {
return ;
}
2018-10-23 00:50:32 +00:00
events = SDL_small_alloc ( SDL_Event , num_events , & isstack ) ;
2016-08-26 19:18:08 +00:00
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 ) ;
2018-10-23 00:50:32 +00:00
SDL_small_free ( events , isstack ) ;
2016-08-26 19:18:08 +00:00
}
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 ;
}
2020-04-20 20:01:36 +00:00
/* The joystick layer will _also_ send events to recenter before disconnect,
but it has to make ( sometimes incorrect ) guesses at what being " centered "
is . The game controller layer , however , can set a definite logical idle
position , so set them all here . If we happened to already be at the
center thanks to the joystick layer or idle hands , this won ' t generate
duplicate events . */
static void RecenterGameController ( SDL_GameController * gamecontroller )
{
SDL_GameControllerButton button ;
SDL_GameControllerAxis axis ;
for ( button = ( SDL_GameControllerButton ) 0 ; button < SDL_CONTROLLER_BUTTON_MAX ; button + + ) {
2020-04-20 22:58:18 +00:00
if ( SDL_GameControllerGetButton ( gamecontroller , button ) ) {
SDL_PrivateGameControllerButton ( gamecontroller , button , SDL_RELEASED ) ;
}
2020-04-20 20:01:36 +00:00
}
for ( axis = ( SDL_GameControllerAxis ) 0 ; axis < SDL_CONTROLLER_AXIS_MAX ; axis + + ) {
2020-04-20 22:58:18 +00:00
if ( SDL_GameControllerGetAxis ( gamecontroller , axis ) ! = 0 ) {
SDL_PrivateGameControllerAxis ( gamecontroller , axis , 0 ) ;
}
2020-04-20 20:01:36 +00:00
}
}
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
2020-04-20 20:01:36 +00:00
RecenterGameController ( controllerlist ) ;
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 ;
}
2020-11-06 19:30:52 +00:00
# ifdef __ANDROID__
2015-06-21 15:33:46 +00:00
/*
2020-11-06 19:30:52 +00:00
* Helper function to guess at a mapping based on the elements reported for this controller
2015-06-21 15:33:46 +00:00
*/
2020-11-06 19:30:52 +00:00
static ControllerMapping_t * SDL_CreateMappingForAndroidController ( SDL_JoystickGUID guid )
2015-06-21 15:33:46 +00:00
{
2020-11-06 19:30:52 +00:00
SDL_bool existing ;
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 ;
}
SDL_strlcpy ( mapping_string , " none,*, " , sizeof ( mapping_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 ) ) ;
}
if ( button_mask & ( 1 < < SDL_CONTROLLER_BUTTON_GUIDE ) ) {
/* The guide button generally isn't functional (or acts as a home button) on most Android controllers before Android 11 */
if ( SDL_GetAndroidSDKVersion ( ) > = 30 /* Android 11 */ ) {
SDL_strlcat ( mapping_string , " guide:b5, " , sizeof ( mapping_string ) ) ;
2015-06-21 15:33:46 +00:00
}
}
2020-11-06 19:30:52 +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__ */
/*
* Helper function to guess at a mapping for HIDAPI controllers
*/
static ControllerMapping_t * SDL_CreateMappingForHIDAPIController ( SDL_JoystickGUID guid )
{
SDL_bool existing ;
char mapping_string [ 1024 ] ;
Uint16 vendor ;
Uint16 product ;
SDL_strlcpy ( mapping_string , " none,*, " , sizeof ( mapping_string ) ) ;
SDL_GetJoystickGUIDInfo ( guid , & vendor , & product , NULL ) ;
if ( vendor = = USB_VENDOR_NINTENDO & & product = = USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER ) {
/* GameCube driver has 12 buttons and 6 axes */
SDL_strlcat ( mapping_string , " a:b0,b:b1,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3,start:b8,x:b2,y:b3, " , sizeof ( mapping_string ) ) ;
} else {
/* All other controllers have the standard set of 19 buttons and 6 axes */
2020-11-20 03:09:40 +00:00
if ( ! SDL_IsJoystickNintendoSwitchPro ( vendor , product ) | |
SDL_GetHintBoolean ( SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS , SDL_TRUE ) ) {
SDL_strlcat ( mapping_string , " a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3, " , sizeof ( mapping_string ) ) ;
} else {
/* Nintendo Switch Pro Controller with swapped face buttons to match Xbox Controller physical layout */
SDL_strlcat ( mapping_string , " a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2, " , sizeof ( mapping_string ) ) ;
}
2020-11-06 19:30:52 +00:00
2020-11-10 20:26:30 +00:00
if ( SDL_IsJoystickXboxOneSeriesX ( vendor , product ) ) {
/* XBox One Series X Controllers have a share button under the guide button */
SDL_strlcat ( mapping_string , " misc1:b15, " , sizeof ( mapping_string ) ) ;
} else if ( SDL_IsJoystickXboxOneElite ( vendor , product ) ) {
2020-11-06 19:30:52 +00:00
/* XBox One Elite Controllers have 4 back paddle buttons */
2020-11-07 10:22:15 +00:00
SDL_strlcat ( mapping_string , " paddle1:b15,paddle2:b17,paddle3:b16,paddle4:b18, " , sizeof ( mapping_string ) ) ;
2020-11-06 19:30:52 +00:00
} else if ( SDL_IsJoystickSteamController ( vendor , product ) ) {
/* Steam controllers have 2 back paddle buttons */
2020-11-07 10:22:15 +00:00
SDL_strlcat ( mapping_string , " paddle1:b16,paddle2:b15, " , sizeof ( mapping_string ) ) ;
2020-11-06 19:30:52 +00:00
} else {
switch ( SDL_GetJoystickGameControllerTypeFromGUID ( guid , NULL ) ) {
case SDL_CONTROLLER_TYPE_PS4 :
2020-11-14 02:01:29 +00:00
/* PS4 controllers have an additional touchpad button */
SDL_strlcat ( mapping_string , " touchpad:b15, " , sizeof ( mapping_string ) ) ;
break ;
2020-11-06 19:30:52 +00:00
case SDL_CONTROLLER_TYPE_PS5 :
2020-11-14 02:01:29 +00:00
/* PS5 controllers have a microphone button and an additional touchpad button */
SDL_strlcat ( mapping_string , " misc1:b15,touchpad:b16 " , sizeof ( mapping_string ) ) ;
2020-11-06 19:30:52 +00:00
break ;
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO :
/* Nintendo Switch Pro controllers have a screenshot button */
2020-11-07 10:22:15 +00:00
SDL_strlcat ( mapping_string , " misc1:b15, " , sizeof ( mapping_string ) ) ;
2020-11-06 19:30:52 +00:00
break ;
default :
break ;
}
2018-09-05 19:16:01 +00:00
}
2020-11-06 19:30:52 +00:00
}
return SDL_PrivateAddMappingForGUID ( guid , mapping_string ,
& existing , SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT ) ;
}
/*
* Helper function to guess at a mapping for RAWINPUT controllers
*/
static ControllerMapping_t * SDL_CreateMappingForRAWINPUTController ( SDL_JoystickGUID guid )
{
SDL_bool existing ;
char mapping_string [ 1024 ] ;
SDL_strlcpy ( mapping_string , " none,*, " , sizeof ( mapping_string ) ) ;
2020-11-24 02:24:05 +00:00
SDL_strlcat ( mapping_string , " a:b0,b:b1,x:b2,y:b3,back:b6,guide:b10,start:b7,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a1,lefty:a0,rightx:a3,righty:a2,lefttrigger:a4,righttrigger:a5, " , sizeof ( mapping_string ) ) ;
2020-11-06 19:30:52 +00:00
return SDL_PrivateAddMappingForGUID ( guid , mapping_string ,
& existing , SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT ) ;
}
/*
* Helper function to scan the mappings database for a controller with the specified GUID
*/
static ControllerMapping_t * SDL_PrivateGetControllerMappingForGUID ( SDL_JoystickGUID guid , SDL_bool exact_match )
{
ControllerMapping_t * mapping = s_pSupportedControllers ;
while ( mapping ) {
if ( SDL_memcmp ( & guid , & mapping - > guid , sizeof ( guid ) ) = = 0 ) {
return mapping ;
2020-03-16 19:23:38 +00:00
}
2020-11-06 19:30:52 +00:00
mapping = mapping - > next ;
}
if ( ! exact_match ) {
2018-03-07 21:30:40 +00:00
# if SDL_JOYSTICK_XINPUT
2020-11-06 19:30:52 +00:00
if ( SDL_IsJoystickXInput ( guid ) ) {
2018-09-05 19:16:01 +00:00
/* This is an XInput device */
return s_pXInputMapping ;
}
2018-03-07 21:30:40 +00:00
# endif
2020-11-06 19:30:52 +00:00
# ifdef __ANDROID__
if ( ! mapping & & ! SDL_IsJoystickHIDAPI ( guid ) ) {
mapping = SDL_CreateMappingForAndroidController ( guid ) ;
}
# endif
if ( ! mapping & & SDL_IsJoystickHIDAPI ( guid ) ) {
mapping = SDL_CreateMappingForHIDAPIController ( guid ) ;
}
if ( ! mapping & & SDL_IsJoystickRAWINPUT ( guid ) ) {
mapping = SDL_CreateMappingForRAWINPUTController ( guid ) ;
}
2018-09-05 19:16:01 +00:00
}
2020-11-06 19:30:52 +00:00
return mapping ;
2015-06-21 15:33:46 +00:00
}
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 " ,
2020-11-07 10:22:15 +00:00
" misc1 " ,
" paddle1 " ,
" paddle2 " ,
" paddle3 " ,
" paddle4 " ,
2020-11-14 02:01:29 +00:00
" touchpad " ,
2015-06-21 15:33:46 +00:00
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 ;
2019-07-30 22:22:02 +00:00
SDL_zeroa ( szGameButton ) ;
SDL_zeroa ( 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 ) ;
2019-07-30 22:22:02 +00:00
SDL_zeroa ( szGameButton ) ;
SDL_zeroa ( 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 + + ;
}
2019-01-21 22:41:43 +00:00
/* No more values if the string was terminated by a comma. Don't report an error. */
if ( szGameButton [ 0 ] ! = ' \0 ' | | szJoystickButton [ 0 ] ! = ' \0 ' ) {
SDL_PrivateGameControllerParseElement ( gamecontroller , szGameButton , szJoystickButton ) ;
}
2015-06-21 15:33:46 +00:00
}
/*
* Make a new button mapping struct
*/
2018-10-04 22:23:42 +00:00
static void SDL_PrivateLoadButtonMapping ( SDL_GameController * gamecontroller , 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 - > name = pchName ;
gamecontroller - > num_bindings = 0 ;
2019-10-23 07:53:23 +00:00
if ( gamecontroller - > joystick - > naxes ) {
SDL_memset ( gamecontroller - > last_match_axis , 0 , gamecontroller - > joystick - > naxes * sizeof ( * gamecontroller - > last_match_axis ) ) ;
}
2016-12-27 09:39:07 +00:00
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 ) {
2018-10-04 22:23:42 +00:00
if ( ! SDL_memcmp ( & gamecontrollerlist - > joystick - > guid , & pControllerMapping - > guid , sizeof ( pControllerMapping - > guid ) ) ) {
2015-06-21 15:33:46 +00:00
/* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */
2018-10-04 22:23:42 +00:00
SDL_PrivateLoadButtonMapping ( gamecontrollerlist , pControllerMapping - > name , pControllerMapping - > mapping ) ;
{
SDL_Event event ;
event . type = SDL_CONTROLLERDEVICEREMAPPED ;
event . cdevice . which = gamecontrollerlist - > joystick - > instance_id ;
SDL_PushEvent ( & event ) ;
}
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 ;
}
2020-11-06 19:30:52 +00:00
pControllerMapping = SDL_PrivateGetControllerMappingForGUID ( jGUID , SDL_TRUE ) ;
2015-12-09 20:11:40 +00:00
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 ) {
2019-10-30 14:36:17 +00:00
/* continue; */
2016-11-30 06:02:37 +00:00
}
pPrevMapping - > next = pControllerMapping ;
} else {
s_pSupportedControllers = pControllerMapping ;
}
2015-12-09 20:11:40 +00:00
* existing = SDL_FALSE ;
}
return pControllerMapping ;
}
/*
* 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 ;
2020-11-06 19:30:52 +00:00
mapping = SDL_PrivateGetControllerMappingForGUID ( guid , SDL_FALSE ) ;
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 ,
2019-01-16 13:03:35 +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__ */
2020-04-19 04:41:37 +00:00
if ( ! mapping & & name & & ! SDL_IsJoystickWGI ( guid ) ) {
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
if ( ! mapping ) {
mapping = s_pDefaultMapping ;
}
2015-12-09 20:11:40 +00:00
return mapping ;
}
2020-05-29 20:37:21 +00:00
static void SDL_PrivateAppendToMappingString ( char * mapping_string ,
size_t mapping_string_len ,
const char * input_name ,
SDL_InputMapping * mapping )
{
char buffer [ 16 ] ;
if ( mapping - > kind = = EMappingKind_None ) {
return ;
}
SDL_strlcat ( mapping_string , input_name , mapping_string_len ) ;
SDL_strlcat ( mapping_string , " : " , mapping_string_len ) ;
switch ( mapping - > kind ) {
case EMappingKind_Button :
SDL_snprintf ( buffer , sizeof ( buffer ) , " b%i " , mapping - > target ) ;
break ;
case EMappingKind_Axis :
SDL_snprintf ( buffer , sizeof ( buffer ) , " a%i " , mapping - > target ) ;
break ;
case EMappingKind_Hat :
SDL_snprintf ( buffer , sizeof ( buffer ) , " h%i.%i " , mapping - > target > > 4 , mapping - > target & 0x0F ) ;
break ;
default :
SDL_assert ( SDL_FALSE ) ;
}
SDL_strlcat ( mapping_string , buffer , mapping_string_len ) ;
SDL_strlcat ( mapping_string , " , " , mapping_string_len ) ;
}
static ControllerMapping_t * SDL_PrivateGenerateAutomaticControllerMapping ( const char * name ,
SDL_JoystickGUID guid ,
SDL_GamepadMapping * raw_map )
{
SDL_bool existing ;
char name_string [ 128 ] ;
char mapping [ 1024 ] ;
/* 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 , sizeof ( mapping ) , " none,%s, " , name_string ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " a " , & raw_map - > a ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " b " , & raw_map - > b ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " x " , & raw_map - > x ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " y " , & raw_map - > y ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " back " , & raw_map - > back ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " guide " , & raw_map - > guide ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " start " , & raw_map - > start ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " leftstick " , & raw_map - > leftstick ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " rightstick " , & raw_map - > rightstick ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " leftshoulder " , & raw_map - > leftshoulder ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " rightshoulder " , & raw_map - > rightshoulder ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " dpup " , & raw_map - > dpup ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " dpdown " , & raw_map - > dpdown ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " dpleft " , & raw_map - > dpleft ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " dpright " , & raw_map - > dpright ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " leftx " , & raw_map - > leftx ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " lefty " , & raw_map - > lefty ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " rightx " , & raw_map - > rightx ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " righty " , & raw_map - > righty ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " lefttrigger " , & raw_map - > lefttrigger ) ;
SDL_PrivateAppendToMappingString ( mapping , sizeof ( mapping ) , " righttrigger " , & raw_map - > righttrigger ) ;
/* Remove trailing comma */
{
int pos = ( int ) SDL_strlen ( mapping ) - 1 ;
if ( pos > = 0 ) {
if ( mapping [ pos ] = = ' , ' ) {
mapping [ pos ] = ' \0 ' ;
}
}
}
return SDL_PrivateAddMappingForGUID ( guid , mapping ,
& existing , SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT ) ;
}
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 ) ;
2020-05-29 20:37:21 +00:00
if ( ! mapping ) {
SDL_GamepadMapping raw_map ;
2020-05-29 21:48:39 +00:00
SDL_zero ( raw_map ) ;
2020-05-29 20:37:21 +00:00
if ( SDL_PrivateJoystickGetAutoGamepadMapping ( device_index , & raw_map ) ) {
mapping = SDL_PrivateGenerateAutomaticControllerMapping ( name , guid , & raw_map ) ;
}
}
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 + + ;
}
}
}
}
2020-02-17 22:15:47 +00:00
2015-06-21 15:33:46 +00:00
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 " ) ;
}
2020-03-13 02:47:28 +00:00
{ /* Extract and verify the hint field */
const char * tmp ;
tmp = SDL_strstr ( mappingString , SDL_CONTROLLER_HINT_FIELD ) ;
if ( tmp ! = NULL ) {
SDL_bool default_value , value , negate ;
int len ;
char hint [ 128 ] ;
tmp + = SDL_strlen ( SDL_CONTROLLER_HINT_FIELD ) ;
if ( * tmp = = ' ! ' ) {
negate = SDL_TRUE ;
+ + tmp ;
} else {
negate = SDL_FALSE ;
}
len = 0 ;
while ( * tmp & & * tmp ! = ' , ' & & * tmp ! = ' : ' & & len < ( sizeof ( hint ) - 1 ) ) {
hint [ len + + ] = * tmp + + ;
}
hint [ len ] = ' \0 ' ;
if ( tmp [ 0 ] = = ' : ' & & tmp [ 1 ] = = ' = ' ) {
tmp + = 2 ;
default_value = SDL_atoi ( tmp ) ;
} else {
default_value = SDL_FALSE ;
}
value = SDL_GetHintBoolean ( hint , default_value ) ;
if ( negate ) {
value = ! value ;
}
if ( ! value ) {
return 0 ;
}
}
}
2020-02-17 22:15:47 +00:00
# ifdef ANDROID
{ /* Extract and verify the SDK version */
const char * tmp ;
tmp = SDL_strstr ( mappingString , SDL_CONTROLLER_SDKGE_FIELD ) ;
if ( tmp ! = NULL ) {
tmp + = SDL_strlen ( SDL_CONTROLLER_SDKGE_FIELD ) ;
if ( ! ( SDL_GetAndroidSDKVersion ( ) > = SDL_atoi ( tmp ) ) ) {
return SDL_SetError ( " SDK version %d < minimum version %d " , SDL_GetAndroidSDKVersion ( ) , SDL_atoi ( tmp ) ) ;
}
}
tmp = SDL_strstr ( mappingString , SDL_CONTROLLER_SDKLE_FIELD ) ;
if ( tmp ! = NULL ) {
tmp + = SDL_strlen ( SDL_CONTROLLER_SDKLE_FIELD ) ;
if ( ! ( SDL_GetAndroidSDKVersion ( ) < = SDL_atoi ( tmp ) ) ) {
return SDL_SetError ( " SDK version %d > maximum version %d " , SDL_GetAndroidSDKVersion ( ) , SDL_atoi ( tmp ) ) ;
}
}
}
# endif
2015-06-21 15:33:46 +00:00
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 ;
2020-11-06 19:30:52 +00:00
ControllerMapping_t * mapping = SDL_PrivateGetControllerMappingForGUID ( guid , SDL_FALSE ) ;
2015-06-21 15:33:46 +00:00
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 *
2020-11-17 01:36:47 +00:00
SDL_GameControllerMapping ( SDL_GameController * gamecontroller )
2015-06-21 15:33:46 +00:00
{
if ( ! gamecontroller ) {
return NULL ;
}
2018-10-04 22:23:42 +00:00
return SDL_GameControllerMappingForGUID ( gamecontroller - > joystick - > 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 .
2018-12-07 20:02:08 +00:00
* Usually this will just be SDL_HINT_GAMECONTROLLERCONFIG_FILE , but for
* Android , we want to get the internal storage path .
2017-09-22 15:30:52 +00:00
*/
static SDL_bool SDL_GetControllerMappingFilePath ( char * path , size_t size )
{
2018-12-07 20:02:08 +00:00
const char * hint = SDL_GetHint ( SDL_HINT_GAMECONTROLLERCONFIG_FILE ) ;
if ( hint & & * hint ) {
return SDL_strlcpy ( path , hint , size ) < size ;
}
# if defined(__ANDROID__)
2017-09-22 15:30:52 +00:00
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 ;
}
2019-11-22 21:12:12 +00:00
/**
* Get the type of a game controller .
*/
SDL_GameControllerType
SDL_GameControllerTypeForIndex ( int joystick_index )
{
2019-11-22 22:09:24 +00:00
return SDL_GetJoystickGameControllerTypeFromGUID ( SDL_JoystickGetDeviceGUID ( joystick_index ) , SDL_JoystickNameForIndex ( joystick_index ) ) ;
2019-11-22 21:12:12 +00:00
}
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 ;
2018-09-14 19:41:29 +00:00
Uint16 version ;
2017-08-09 18:59:29 +00:00
Uint32 vidpid ;
2018-12-04 22:21:29 +00:00
# if defined(__LINUX__)
2020-07-15 17:15:52 +00:00
if ( name & & SDL_strstr ( name , " Motion Sensors " ) ) {
2020-02-05 02:36:23 +00:00
/* Don't treat the PS3 and PS4 motion controls as a separate game controller */
2018-12-04 22:21:29 +00:00
return SDL_TRUE ;
}
# endif
2017-08-09 18:59:29 +00:00
if ( SDL_allowed_controllers . num_entries = = 0 & &
SDL_ignored_controllers . num_entries = = 0 ) {
return SDL_FALSE ;
}
2018-09-14 19:41:29 +00:00
SDL_GetJoystickGUIDInfo ( guid , & vendor , & product , & version ) ;
2017-08-09 18:59:29 +00:00
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__)
2018-09-14 19:41:29 +00:00
bSteamVirtualGamepad = ( vendor = = 0x045E & & product = = 0x028E & & version = = 1 ) ;
2017-08-09 19:38:20 +00:00
# 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 ;
}
}
2018-08-09 23:00:17 +00:00
vidpid = MAKE_VIDPID ( vendor , product ) ;
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 )
{
2018-08-09 23:00:17 +00:00
SDL_JoystickID instance_id ;
2015-06-21 15:33:46 +00:00
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
gamecontrollerlist = SDL_gamecontrollers ;
/* If the controller is already open, return it */
2018-08-09 23:00:17 +00:00
instance_id = SDL_JoystickGetDeviceInstanceID ( device_index ) ;
2015-06-21 15:33:46 +00:00
while ( gamecontrollerlist ) {
2018-08-09 23:00:17 +00:00
if ( instance_id = = gamecontrollerlist - > joystick - > instance_id ) {
2015-06-21 15:33:46 +00:00
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
2018-10-04 22:23:42 +00:00
SDL_PrivateLoadButtonMapping ( gamecontroller , 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 ( ) ;
}
2020-11-14 02:01:29 +00:00
/**
* Return whether a game controller has a given axis
*/
SDL_bool
SDL_GameControllerHasAxis ( SDL_GameController * gamecontroller , SDL_GameControllerAxis axis )
{
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis ( gamecontroller , axis ) ;
return ( bind . bindType ! = SDL_CONTROLLER_BINDTYPE_NONE ) ? SDL_TRUE : SDL_FALSE ;
}
2015-06-21 15:33:46 +00:00
/*
* Get the current state of an axis control on a controller
*/
Sint16
2020-11-17 01:36:47 +00:00
SDL_GameControllerGetAxis ( SDL_GameController * gamecontroller , SDL_GameControllerAxis axis )
2015-06-21 15:33:46 +00:00
{
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 ) ) ;
}
2019-03-17 01:12:26 +00:00
} else {
value = 0 ;
2016-12-27 09:39:07 +00:00
}
} 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 ;
}
2020-11-14 02:01:29 +00:00
/**
* Return whether a game controller has a given button
*/
SDL_bool
SDL_GameControllerHasButton ( SDL_GameController * gamecontroller , SDL_GameControllerButton button )
{
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton ( gamecontroller , button ) ;
return ( bind . bindType ! = SDL_CONTROLLER_BINDTYPE_NONE ) ? SDL_TRUE : SDL_FALSE ;
}
2015-06-21 15:33:46 +00:00
/*
* Get the current state of a button on a controller
*/
Uint8
2020-11-17 01:36:47 +00:00
SDL_GameControllerGetButton ( SDL_GameController * gamecontroller , SDL_GameControllerButton button )
2015-06-21 15:33:46 +00:00
{
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
}
2020-11-14 02:01:29 +00:00
/**
* Get the number of touchpads on a game controller .
*/
int
SDL_GameControllerGetNumTouchpads ( SDL_GameController * gamecontroller )
{
SDL_Joystick * joystick = SDL_GameControllerGetJoystick ( gamecontroller ) ;
if ( joystick ) {
return joystick - > ntouchpads ;
}
return 0 ;
}
/**
* Get the number of supported simultaneous fingers on a touchpad on a game controller .
*/
int SDL_GameControllerGetNumTouchpadFingers ( SDL_GameController * gamecontroller , int touchpad )
{
SDL_Joystick * joystick = SDL_GameControllerGetJoystick ( gamecontroller ) ;
if ( joystick & & touchpad > = 0 & & touchpad < joystick - > ntouchpads ) {
return joystick - > touchpads [ touchpad ] . nfingers ;
}
return 0 ;
}
/**
* Get the current state of a finger on a touchpad on a game controller .
*/
int
SDL_GameControllerGetTouchpadFinger ( SDL_GameController * gamecontroller , int touchpad , int finger , Uint8 * state , float * x , float * y , float * pressure )
{
SDL_Joystick * joystick = SDL_GameControllerGetJoystick ( gamecontroller ) ;
if ( joystick ) {
if ( touchpad > = 0 & & touchpad < joystick - > ntouchpads ) {
SDL_JoystickTouchpadInfo * touchpad_info = & joystick - > touchpads [ touchpad ] ;
if ( finger > = 0 & & finger < touchpad_info - > nfingers ) {
SDL_JoystickTouchpadFingerInfo * info = & touchpad_info - > fingers [ finger ] ;
if ( state ) {
* state = info - > state ;
}
if ( x ) {
* x = info - > x ;
}
if ( y ) {
* y = info - > y ;
}
if ( pressure ) {
* pressure = info - > pressure ;
}
return 0 ;
} else {
return SDL_InvalidParamError ( " finger " ) ;
}
} else {
return SDL_InvalidParamError ( " touchpad " ) ;
}
} else {
return SDL_InvalidParamError ( " gamecontroller " ) ;
}
}
2020-11-17 18:30:20 +00:00
/**
* Return whether a game controller has a particular sensor .
*/
SDL_bool
SDL_GameControllerHasSensor ( SDL_GameController * gamecontroller , SDL_SensorType type )
{
SDL_Joystick * joystick = SDL_GameControllerGetJoystick ( gamecontroller ) ;
int i ;
if ( joystick ) {
for ( i = 0 ; i < joystick - > nsensors ; + + i ) {
if ( joystick - > sensors [ i ] . type = = type ) {
return SDL_TRUE ;
}
}
}
return SDL_FALSE ;
}
/*
* Set whether data reporting for a game controller sensor is enabled
*/
int SDL_GameControllerSetSensorEnabled ( SDL_GameController * gamecontroller , SDL_SensorType type , SDL_bool enabled )
{
SDL_Joystick * joystick = SDL_GameControllerGetJoystick ( gamecontroller ) ;
int i ;
if ( ! joystick ) {
return SDL_InvalidParamError ( " gamecontroller " ) ;
}
for ( i = 0 ; i < joystick - > nsensors ; + + i ) {
SDL_JoystickSensorInfo * sensor = & joystick - > sensors [ i ] ;
if ( sensor - > type = = type ) {
if ( sensor - > enabled = = enabled ) {
return 0 ;
}
if ( enabled ) {
if ( joystick - > nsensors_enabled = = 0 ) {
if ( joystick - > driver - > SetSensorsEnabled ( joystick , SDL_TRUE ) < 0 ) {
return - 1 ;
}
}
+ + joystick - > nsensors_enabled ;
} else {
if ( joystick - > nsensors_enabled = = 1 ) {
if ( joystick - > driver - > SetSensorsEnabled ( joystick , SDL_FALSE ) < 0 ) {
return - 1 ;
}
}
- - joystick - > nsensors_enabled ;
}
sensor - > enabled = enabled ;
return 0 ;
}
}
return SDL_Unsupported ( ) ;
}
/*
* Query whether sensor data reporting is enabled for a game controller
*/
SDL_bool SDL_GameControllerIsSensorEnabled ( SDL_GameController * gamecontroller , SDL_SensorType type )
{
SDL_Joystick * joystick = SDL_GameControllerGetJoystick ( gamecontroller ) ;
int i ;
if ( joystick ) {
for ( i = 0 ; i < joystick - > nsensors ; + + i ) {
if ( joystick - > sensors [ i ] . type = = type ) {
return joystick - > sensors [ i ] . enabled ;
}
}
}
return SDL_FALSE ;
}
/*
* Get the current state of a game controller sensor .
*/
int
SDL_GameControllerGetSensorData ( SDL_GameController * gamecontroller , SDL_SensorType type , float * data , int num_values )
{
SDL_Joystick * joystick = SDL_GameControllerGetJoystick ( gamecontroller ) ;
int i ;
if ( ! joystick ) {
return SDL_InvalidParamError ( " gamecontroller " ) ;
}
for ( i = 0 ; i < joystick - > nsensors ; + + i ) {
SDL_JoystickSensorInfo * sensor = & joystick - > sensors [ i ] ;
if ( sensor - > type = = type ) {
num_values = SDL_min ( num_values , SDL_arraysize ( sensor - > data ) ) ;
SDL_memcpy ( data , sensor - > data , num_values * sizeof ( * data ) ) ;
return 0 ;
}
}
return SDL_Unsupported ( ) ;
}
2016-11-11 01:19:34 +00:00
const char *
2020-11-17 01:36:47 +00:00
SDL_GameControllerName ( SDL_GameController * gamecontroller )
2016-11-11 01:19:34 +00:00
{
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
}
2019-11-22 21:12:12 +00:00
SDL_GameControllerType
SDL_GameControllerGetType ( SDL_GameController * gamecontroller )
{
2019-11-22 22:09:24 +00:00
return SDL_GetJoystickGameControllerTypeFromGUID ( SDL_JoystickGetGUID ( SDL_GameControllerGetJoystick ( gamecontroller ) ) , SDL_JoystickName ( SDL_GameControllerGetJoystick ( gamecontroller ) ) ) ;
2019-11-22 21:12:12 +00:00
}
2018-10-25 23:53:14 +00:00
int
SDL_GameControllerGetPlayerIndex ( SDL_GameController * gamecontroller )
{
return SDL_JoystickGetPlayerIndex ( SDL_GameControllerGetJoystick ( gamecontroller ) ) ;
}
2019-12-21 04:12:03 +00:00
/**
* Set the player index of an opened game controller
*/
void
SDL_GameControllerSetPlayerIndex ( SDL_GameController * gamecontroller , int player_index )
{
SDL_JoystickSetPlayerIndex ( SDL_GameControllerGetJoystick ( gamecontroller ) , player_index ) ;
}
2016-11-11 01:19:34 +00:00
Uint16
2020-11-17 01:36:47 +00:00
SDL_GameControllerGetVendor ( SDL_GameController * gamecontroller )
2016-11-11 01:19:34 +00:00
{
return SDL_JoystickGetVendor ( SDL_GameControllerGetJoystick ( gamecontroller ) ) ;
}
Uint16
2020-11-17 01:36:47 +00:00
SDL_GameControllerGetProduct ( SDL_GameController * gamecontroller )
2016-11-11 01:19:34 +00:00
{
return SDL_JoystickGetProduct ( SDL_GameControllerGetJoystick ( gamecontroller ) ) ;
}
Uint16
2020-11-17 01:36:47 +00:00
SDL_GameControllerGetProductVersion ( SDL_GameController * gamecontroller )
2016-11-11 01:19:34 +00:00
{
return SDL_JoystickGetProductVersion ( SDL_GameControllerGetJoystick ( gamecontroller ) ) ;
}
2020-11-17 01:36:47 +00:00
const char *
SDL_GameControllerGetSerial ( SDL_GameController * gamecontroller )
{
return SDL_JoystickGetSerial ( 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
2020-11-17 01:36:47 +00:00
SDL_GameControllerGetAttached ( SDL_GameController * gamecontroller )
2015-06-21 15:33:46 +00:00
{
if ( ! gamecontroller )
return SDL_FALSE ;
return SDL_JoystickGetAttached ( gamecontroller - > joystick ) ;
}
/*
* Get the joystick for this controller
*/
2020-11-17 01:36:47 +00:00
SDL_Joystick *
SDL_GameControllerGetJoystick ( SDL_GameController * gamecontroller )
2015-06-21 15:33:46 +00:00
{
if ( ! gamecontroller )
return NULL ;
return gamecontroller - > joystick ;
}
2015-11-14 17:35:45 +00:00
/*
2019-12-21 04:12:03 +00:00
* Return the SDL_GameController associated with an instance id .
2015-11-14 17:35:45 +00:00
*/
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 ;
}
2019-12-21 04:12:03 +00:00
/**
* Return the SDL_GameController associated with a player index .
*/
SDL_GameController * SDL_GameControllerFromPlayerIndex ( int player_index )
{
SDL_Joystick * joystick = SDL_JoystickFromPlayerIndex ( player_index ) ;
if ( joystick ) {
return SDL_GameControllerFromInstanceID ( joystick - > instance_id ) ;
}
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
*/
2020-11-17 01:36:47 +00:00
SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis ( SDL_GameController * gamecontroller , SDL_GameControllerAxis axis )
2015-06-21 15:33:46 +00:00
{
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
*/
2020-11-17 01:36:47 +00:00
SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton ( SDL_GameController * gamecontroller , SDL_GameControllerButton button )
2015-06-21 15:33:46 +00:00
{
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 ;
}
2018-08-09 23:00:17 +00:00
int
SDL_GameControllerRumble ( SDL_GameController * gamecontroller , Uint16 low_frequency_rumble , Uint16 high_frequency_rumble , Uint32 duration_ms )
{
return SDL_JoystickRumble ( SDL_GameControllerGetJoystick ( gamecontroller ) , low_frequency_rumble , high_frequency_rumble , duration_ms ) ;
}
2020-11-12 02:57:37 +00:00
int
SDL_GameControllerRumbleTriggers ( SDL_GameController * gamecontroller , Uint16 left_rumble , Uint16 right_rumble , Uint32 duration_ms )
{
return SDL_JoystickRumbleTriggers ( SDL_GameControllerGetJoystick ( gamecontroller ) , left_rumble , right_rumble , duration_ms ) ;
}
2020-11-05 19:07:54 +00:00
SDL_bool
SDL_GameControllerHasLED ( SDL_GameController * gamecontroller )
{
return SDL_JoystickHasLED ( SDL_GameControllerGetJoystick ( gamecontroller ) ) ;
}
2020-04-30 15:57:29 +00:00
int
SDL_GameControllerSetLED ( SDL_GameController * gamecontroller , Uint8 red , Uint8 green , Uint8 blue )
{
return SDL_JoystickSetLED ( SDL_GameControllerGetJoystick ( gamecontroller ) , red , green , blue ) ;
}
2015-06-21 15:33:46 +00:00
void
2020-11-17 01:36:47 +00:00
SDL_GameControllerClose ( SDL_GameController * gamecontroller )
2015-06-21 15:33:46 +00:00
{
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
2020-11-17 01:36:47 +00:00
SDL_PrivateGameControllerAxis ( SDL_GameController * gamecontroller , SDL_GameControllerAxis axis , Sint16 value )
2015-06-21 15:33:46 +00:00
{
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
2020-11-17 01:36:47 +00:00
SDL_PrivateGameControllerButton ( SDL_GameController * gamecontroller , SDL_GameControllerButton button , Uint8 state )
2015-06-21 15:33:46 +00:00
{
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 {
2020-04-08 03:17:27 +00:00
if ( ! SDL_TICKS_PASSED ( now , gamecontroller - > guide_button_down + SDL_MINIMUM_GUIDE_BUTTON_DELAY_MS ) ) {
2018-03-19 21:42:51 +00:00
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: */