|
@@ -112,6 +112,74 @@ struct _SDL_GameController |
|
|
}; |
|
|
|
|
|
|
|
|
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) { |
|
|
entry = SDL_strtol(spot, &spot, 0); |
|
|
entry <<= 16; |
|
|
spot = SDL_strstr(spot, "0x"); |
|
|
if (!spot) { |
|
|
break; |
|
|
} |
|
|
entry |= SDL_strtol(spot, &spot, 0); |
|
|
|
|
|
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); |
|
|
} |
|
|
} |
|
|
|
|
|
static void |
|
|
SDL_GameControllerIgnoreDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint) |
|
|
{ |
|
|
SDL_LoadVIDPIDListFromHint(hint, &SDL_ignored_controllers); |
|
|
} |
|
|
|
|
|
static void |
|
|
SDL_GameControllerIgnoreDevicesExceptChanged(void *userdata, const char *name, const char *oldValue, const char *hint) |
|
|
{ |
|
|
SDL_LoadVIDPIDListFromHint(hint, &SDL_allowed_controllers); |
|
|
} |
|
|
|
|
|
static int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value); |
|
|
static int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state); |
|
|
|
|
@@ -799,50 +867,51 @@ SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, |
|
|
/* |
|
|
* Helper function to determine pre-calculated offset to certain joystick mappings |
|
|
*/ |
|
|
static ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index) |
|
|
static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const char *name, SDL_JoystickGUID guid) |
|
|
{ |
|
|
SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index); |
|
|
ControllerMapping_t *mapping; |
|
|
|
|
|
(void) s_pEmscriptenMapping; /* pacify ARMCC */ |
|
|
|
|
|
mapping = SDL_PrivateGetControllerMappingForGUID(&jGUID); |
|
|
#if SDL_JOYSTICK_XINPUT |
|
|
if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) { |
|
|
mapping = s_pXInputMapping; |
|
|
} |
|
|
#endif |
|
|
mapping = SDL_PrivateGetControllerMappingForGUID(&guid); |
|
|
#if defined(SDL_JOYSTICK_EMSCRIPTEN) |
|
|
if (!mapping && s_pEmscriptenMapping) { |
|
|
mapping = s_pEmscriptenMapping; |
|
|
} |
|
|
#else |
|
|
(void) s_pEmscriptenMapping; /* pacify ARMCC */ |
|
|
#endif |
|
|
#ifdef __LINUX__ |
|
|
if (!mapping) { |
|
|
const char *name = SDL_JoystickNameForIndex(device_index); |
|
|
if (name) { |
|
|
if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) { |
|
|
/* The Linux driver xpad.c maps the wireless dpad to buttons */ |
|
|
SDL_bool existing; |
|
|
mapping = SDL_PrivateAddMappingForGUID(jGUID, |
|
|
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; |
|
|
mapping = SDL_PrivateAddMappingForGUID(jGUID, |
|
|
"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,", |
|
|
&existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); |
|
|
} |
|
|
&existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); |
|
|
} |
|
|
} |
|
|
#endif /* __LINUX__ */ |
|
|
|
|
|
if (!mapping) { |
|
|
const char *name = SDL_JoystickNameForIndex(device_index); |
|
|
if (name) { |
|
|
if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box")) { |
|
|
mapping = s_pXInputMapping; |
|
|
} |
|
|
if (!mapping && name) { |
|
|
if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box")) { |
|
|
mapping = s_pXInputMapping; |
|
|
} |
|
|
} |
|
|
return mapping; |
|
|
} |
|
|
|
|
|
static ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index) |
|
|
{ |
|
|
const char *name = SDL_JoystickNameForIndex(device_index); |
|
|
SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index); |
|
|
ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid); |
|
|
#if SDL_JOYSTICK_XINPUT |
|
|
if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) { |
|
|
mapping = s_pXInputMapping; |
|
|
} |
|
|
#endif |
|
|
return mapping; |
|
|
} |
|
|
|
|
|
/* |
|
|
* Add or update an entry into the Mappings Database |
|
|
*/ |
|
@@ -1092,7 +1161,7 @@ SDL_GameControllerLoadHints() |
|
|
* Initialize the game controller system, mostly load our DB of controller config mappings |
|
|
*/ |
|
|
int |
|
|
SDL_GameControllerInit(void) |
|
|
SDL_GameControllerInitMappings(void) |
|
|
{ |
|
|
int i = 0; |
|
|
const char *pMappingString = NULL; |
|
@@ -1107,6 +1176,19 @@ SDL_GameControllerInit(void) |
|
|
/* load in any user supplied config */ |
|
|
SDL_GameControllerLoadHints(); |
|
|
|
|
|
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; |
|
|
|
|
|
/* watch for joy events and fire controller ones if needed */ |
|
|
SDL_AddEventWatch(SDL_GameControllerEventWatcher, NULL); |
|
|
|
|
@@ -1138,6 +1220,19 @@ SDL_GameControllerNameForIndex(int device_index) |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* 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; |
|
|
} |
|
|
|
|
|
/* |
|
|
* Return 1 if the joystick at this device index is a supported controller |
|
|
*/ |
|
@@ -1151,6 +1246,41 @@ SDL_IsGameController(int device_index) |
|
|
return SDL_FALSE; |
|
|
} |
|
|
|
|
|
/* |
|
|
* Return 1 if the game controller should be ignored by SDL |
|
|
*/ |
|
|
SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid) |
|
|
{ |
|
|
int i; |
|
|
Uint16 vendor; |
|
|
Uint16 product; |
|
|
Uint32 vidpid; |
|
|
|
|
|
if (SDL_allowed_controllers.num_entries == 0 && |
|
|
SDL_ignored_controllers.num_entries == 0) { |
|
|
return SDL_FALSE; |
|
|
} |
|
|
|
|
|
SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL); |
|
|
vidpid = MAKE_VIDPID(vendor, product); |
|
|
|
|
|
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; |
|
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|
* 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 |
|
@@ -1536,14 +1666,18 @@ SDL_GameControllerClose(SDL_GameController * gamecontroller) |
|
|
void |
|
|
SDL_GameControllerQuit(void) |
|
|
{ |
|
|
ControllerMapping_t *pControllerMap; |
|
|
|
|
|
SDL_LockJoystickList(); |
|
|
while (SDL_gamecontrollers) { |
|
|
SDL_gamecontrollers->ref_count = 1; |
|
|
SDL_GameControllerClose(SDL_gamecontrollers); |
|
|
} |
|
|
SDL_UnlockJoystickList(); |
|
|
} |
|
|
|
|
|
void |
|
|
SDL_GameControllerQuitMappings(void) |
|
|
{ |
|
|
ControllerMapping_t *pControllerMap; |
|
|
|
|
|
while (s_pSupportedControllers) { |
|
|
pControllerMap = s_pSupportedControllers; |
|
@@ -1555,6 +1689,19 @@ SDL_GameControllerQuit(void) |
|
|
|
|
|
SDL_DelEventWatch(SDL_GameControllerEventWatcher, NULL); |
|
|
|
|
|
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); |
|
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|