SDL_gamecontroller.c (88892B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20 */ 21 #include "../SDL_internal.h" 22 23 /* This is the game controller API for Simple DirectMedia Layer */ 24 25 #include "SDL_events.h" 26 #include "SDL_hints.h" 27 #include "SDL_timer.h" 28 #include "SDL_sysjoystick.h" 29 #include "SDL_joystick_c.h" 30 #include "SDL_gamecontrollerdb.h" 31 #include "usb_ids.h" 32 33 #if !SDL_EVENTS_DISABLED 34 #include "../events/SDL_events_c.h" 35 #endif 36 37 #if defined(__ANDROID__) 38 #include "SDL_system.h" 39 #endif 40 41 42 /* Many controllers turn the center button into an instantaneous button press */ 43 #define SDL_MINIMUM_GUIDE_BUTTON_DELAY_MS 250 44 45 #define SDL_CONTROLLER_PLATFORM_FIELD "platform:" 46 #define SDL_CONTROLLER_HINT_FIELD "hint:" 47 #define SDL_CONTROLLER_SDKGE_FIELD "sdk>=:" 48 #define SDL_CONTROLLER_SDKLE_FIELD "sdk<=:" 49 50 /* a list of currently opened game controllers */ 51 static SDL_GameController *SDL_gamecontrollers = NULL; 52 53 typedef struct 54 { 55 SDL_GameControllerBindType inputType; 56 union 57 { 58 int button; 59 60 struct { 61 int axis; 62 int axis_min; 63 int axis_max; 64 } axis; 65 66 struct { 67 int hat; 68 int hat_mask; 69 } hat; 70 71 } input; 72 73 SDL_GameControllerBindType outputType; 74 union 75 { 76 SDL_GameControllerButton button; 77 78 struct { 79 SDL_GameControllerAxis axis; 80 int axis_min; 81 int axis_max; 82 } axis; 83 84 } output; 85 86 } SDL_ExtendedGameControllerBind; 87 88 /* our hard coded list of mapping support */ 89 typedef enum 90 { 91 SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT, 92 SDL_CONTROLLER_MAPPING_PRIORITY_API, 93 SDL_CONTROLLER_MAPPING_PRIORITY_USER, 94 } SDL_ControllerMappingPriority; 95 96 typedef struct _ControllerMapping_t 97 { 98 SDL_JoystickGUID guid; 99 char *name; 100 char *mapping; 101 SDL_ControllerMappingPriority priority; 102 struct _ControllerMapping_t *next; 103 } ControllerMapping_t; 104 105 static SDL_JoystickGUID s_zeroGUID; 106 static ControllerMapping_t *s_pSupportedControllers = NULL; 107 static ControllerMapping_t *s_pDefaultMapping = NULL; 108 static ControllerMapping_t *s_pXInputMapping = NULL; 109 110 /* The SDL game controller structure */ 111 struct _SDL_GameController 112 { 113 SDL_Joystick *joystick; /* underlying joystick device */ 114 int ref_count; 115 116 const char *name; 117 int num_bindings; 118 SDL_ExtendedGameControllerBind *bindings; 119 SDL_ExtendedGameControllerBind **last_match_axis; 120 Uint8 *last_hat_mask; 121 Uint32 guide_button_down; 122 123 struct _SDL_GameController *next; /* pointer to next game controller we have allocated */ 124 }; 125 126 127 typedef struct 128 { 129 int num_entries; 130 int max_entries; 131 Uint32 *entries; 132 } SDL_vidpid_list; 133 134 static SDL_vidpid_list SDL_allowed_controllers; 135 static SDL_vidpid_list SDL_ignored_controllers; 136 137 static void 138 SDL_LoadVIDPIDListFromHint(const char *hint, SDL_vidpid_list *list) 139 { 140 Uint32 entry; 141 char *spot; 142 char *file = NULL; 143 144 list->num_entries = 0; 145 146 if (hint && *hint == '@') { 147 spot = file = (char *)SDL_LoadFile(hint+1, NULL); 148 } else { 149 spot = (char *)hint; 150 } 151 152 if (!spot) { 153 return; 154 } 155 156 while ((spot = SDL_strstr(spot, "0x")) != NULL) { 157 entry = (Uint16)SDL_strtol(spot, &spot, 0); 158 entry <<= 16; 159 spot = SDL_strstr(spot, "0x"); 160 if (!spot) { 161 break; 162 } 163 entry |= (Uint16)SDL_strtol(spot, &spot, 0); 164 165 if (list->num_entries == list->max_entries) { 166 int max_entries = list->max_entries + 16; 167 Uint32 *entries = (Uint32 *)SDL_realloc(list->entries, max_entries*sizeof(*list->entries)); 168 if (entries == NULL) { 169 /* Out of memory, go with what we have already */ 170 break; 171 } 172 list->entries = entries; 173 list->max_entries = max_entries; 174 } 175 list->entries[list->num_entries++] = entry; 176 } 177 178 if (file) { 179 SDL_free(file); 180 } 181 } 182 183 static void SDLCALL 184 SDL_GameControllerIgnoreDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 185 { 186 SDL_LoadVIDPIDListFromHint(hint, &SDL_ignored_controllers); 187 } 188 189 static void SDLCALL 190 SDL_GameControllerIgnoreDevicesExceptChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 191 { 192 SDL_LoadVIDPIDListFromHint(hint, &SDL_allowed_controllers); 193 } 194 195 static ControllerMapping_t *SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing, SDL_ControllerMappingPriority priority); 196 static int SDL_PrivateGameControllerAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis, Sint16 value); 197 static int SDL_PrivateGameControllerButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button, Uint8 state); 198 199 /* 200 * If there is an existing add event in the queue, it needs to be modified 201 * to have the right value for which, because the number of controllers in 202 * the system is now one less. 203 */ 204 static void UpdateEventsForDeviceRemoval(int device_index) 205 { 206 int i, num_events; 207 SDL_Event *events; 208 SDL_bool isstack; 209 210 num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED); 211 if (num_events <= 0) { 212 return; 213 } 214 215 events = SDL_small_alloc(SDL_Event, num_events, &isstack); 216 if (!events) { 217 return; 218 } 219 220 num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED); 221 for (i = 0; i < num_events; ++i) { 222 if (events[i].cdevice.which < device_index) { 223 /* No change for index values lower than the removed device */ 224 } 225 else if (events[i].cdevice.which == device_index) { 226 /* Drop this event entirely */ 227 SDL_memmove(&events[i], &events[i + 1], sizeof(*events) * (num_events - (i + 1))); 228 --i; 229 --num_events; 230 } 231 else { 232 /* Fix up the device index if greater than the removed device */ 233 --events[i].cdevice.which; 234 } 235 } 236 SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0); 237 238 SDL_small_free(events, isstack); 239 } 240 241 static SDL_bool HasSameOutput(SDL_ExtendedGameControllerBind *a, SDL_ExtendedGameControllerBind *b) 242 { 243 if (a->outputType != b->outputType) { 244 return SDL_FALSE; 245 } 246 247 if (a->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 248 return (a->output.axis.axis == b->output.axis.axis); 249 } else { 250 return (a->output.button == b->output.button); 251 } 252 } 253 254 static void ResetOutput(SDL_GameController *gamecontroller, SDL_ExtendedGameControllerBind *bind) 255 { 256 if (bind->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 257 SDL_PrivateGameControllerAxis(gamecontroller, bind->output.axis.axis, 0); 258 } else { 259 SDL_PrivateGameControllerButton(gamecontroller, bind->output.button, SDL_RELEASED); 260 } 261 } 262 263 static void HandleJoystickAxis(SDL_GameController *gamecontroller, int axis, int value) 264 { 265 int i; 266 SDL_ExtendedGameControllerBind *last_match = gamecontroller->last_match_axis[axis]; 267 SDL_ExtendedGameControllerBind *match = NULL; 268 269 for (i = 0; i < gamecontroller->num_bindings; ++i) { 270 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 271 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS && 272 axis == binding->input.axis.axis) { 273 if (binding->input.axis.axis_min < binding->input.axis.axis_max) { 274 if (value >= binding->input.axis.axis_min && 275 value <= binding->input.axis.axis_max) { 276 match = binding; 277 break; 278 } 279 } else { 280 if (value >= binding->input.axis.axis_max && 281 value <= binding->input.axis.axis_min) { 282 match = binding; 283 break; 284 } 285 } 286 } 287 } 288 289 if (last_match && (!match || !HasSameOutput(last_match, match))) { 290 /* Clear the last input that this axis generated */ 291 ResetOutput(gamecontroller, last_match); 292 } 293 294 if (match) { 295 if (match->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 296 if (match->input.axis.axis_min != match->output.axis.axis_min || match->input.axis.axis_max != match->output.axis.axis_max) { 297 float normalized_value = (float)(value - match->input.axis.axis_min) / (match->input.axis.axis_max - match->input.axis.axis_min); 298 value = match->output.axis.axis_min + (int)(normalized_value * (match->output.axis.axis_max - match->output.axis.axis_min)); 299 } 300 SDL_PrivateGameControllerAxis(gamecontroller, match->output.axis.axis, (Sint16)value); 301 } else { 302 Uint8 state; 303 int threshold = match->input.axis.axis_min + (match->input.axis.axis_max - match->input.axis.axis_min) / 2; 304 if (match->input.axis.axis_max < match->input.axis.axis_min) { 305 state = (value <= threshold) ? SDL_PRESSED : SDL_RELEASED; 306 } else { 307 state = (value >= threshold) ? SDL_PRESSED : SDL_RELEASED; 308 } 309 SDL_PrivateGameControllerButton(gamecontroller, match->output.button, state); 310 } 311 } 312 gamecontroller->last_match_axis[axis] = match; 313 } 314 315 static void HandleJoystickButton(SDL_GameController *gamecontroller, int button, Uint8 state) 316 { 317 int i; 318 319 for (i = 0; i < gamecontroller->num_bindings; ++i) { 320 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 321 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON && 322 button == binding->input.button) { 323 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 324 int value = state ? binding->output.axis.axis_max : binding->output.axis.axis_min; 325 SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)value); 326 } else { 327 SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, state); 328 } 329 break; 330 } 331 } 332 } 333 334 static void HandleJoystickHat(SDL_GameController *gamecontroller, int hat, Uint8 value) 335 { 336 int i; 337 Uint8 last_mask = gamecontroller->last_hat_mask[hat]; 338 Uint8 changed_mask = (last_mask ^ value); 339 340 for (i = 0; i < gamecontroller->num_bindings; ++i) { 341 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 342 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT && hat == binding->input.hat.hat) { 343 if ((changed_mask & binding->input.hat.hat_mask) != 0) { 344 if (value & binding->input.hat.hat_mask) { 345 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 346 SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)binding->output.axis.axis_max); 347 } else { 348 SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, SDL_PRESSED); 349 } 350 } else { 351 ResetOutput(gamecontroller, binding); 352 } 353 } 354 } 355 } 356 gamecontroller->last_hat_mask[hat] = value; 357 } 358 359 360 /* The joystick layer will _also_ send events to recenter before disconnect, 361 but it has to make (sometimes incorrect) guesses at what being "centered" 362 is. The game controller layer, however, can set a definite logical idle 363 position, so set them all here. If we happened to already be at the 364 center thanks to the joystick layer or idle hands, this won't generate 365 duplicate events. */ 366 static void RecenterGameController(SDL_GameController *gamecontroller) 367 { 368 SDL_GameControllerButton button; 369 SDL_GameControllerAxis axis; 370 371 for (button = (SDL_GameControllerButton) 0; button < SDL_CONTROLLER_BUTTON_MAX; button++) { 372 if (SDL_GameControllerGetButton(gamecontroller, button)) { 373 SDL_PrivateGameControllerButton(gamecontroller, button, SDL_RELEASED); 374 } 375 } 376 377 for (axis = (SDL_GameControllerAxis) 0; axis < SDL_CONTROLLER_AXIS_MAX; axis++) { 378 if (SDL_GameControllerGetAxis(gamecontroller, axis) != 0) { 379 SDL_PrivateGameControllerAxis(gamecontroller, axis, 0); 380 } 381 } 382 } 383 384 385 /* 386 * Event filter to fire controller events from joystick ones 387 */ 388 static int SDLCALL SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event) 389 { 390 switch(event->type) { 391 case SDL_JOYAXISMOTION: 392 { 393 SDL_GameController *controllerlist = SDL_gamecontrollers; 394 while (controllerlist) { 395 if (controllerlist->joystick->instance_id == event->jaxis.which) { 396 HandleJoystickAxis(controllerlist, event->jaxis.axis, event->jaxis.value); 397 break; 398 } 399 controllerlist = controllerlist->next; 400 } 401 } 402 break; 403 case SDL_JOYBUTTONDOWN: 404 case SDL_JOYBUTTONUP: 405 { 406 SDL_GameController *controllerlist = SDL_gamecontrollers; 407 while (controllerlist) { 408 if (controllerlist->joystick->instance_id == event->jbutton.which) { 409 HandleJoystickButton(controllerlist, event->jbutton.button, event->jbutton.state); 410 break; 411 } 412 controllerlist = controllerlist->next; 413 } 414 } 415 break; 416 case SDL_JOYHATMOTION: 417 { 418 SDL_GameController *controllerlist = SDL_gamecontrollers; 419 while (controllerlist) { 420 if (controllerlist->joystick->instance_id == event->jhat.which) { 421 HandleJoystickHat(controllerlist, event->jhat.hat, event->jhat.value); 422 break; 423 } 424 controllerlist = controllerlist->next; 425 } 426 } 427 break; 428 case SDL_JOYDEVICEADDED: 429 { 430 if (SDL_IsGameController(event->jdevice.which)) { 431 SDL_Event deviceevent; 432 deviceevent.type = SDL_CONTROLLERDEVICEADDED; 433 deviceevent.cdevice.which = event->jdevice.which; 434 SDL_PushEvent(&deviceevent); 435 } 436 } 437 break; 438 case SDL_JOYDEVICEREMOVED: 439 { 440 SDL_GameController *controllerlist = SDL_gamecontrollers; 441 int device_index = 0; 442 while (controllerlist) { 443 if (controllerlist->joystick->instance_id == event->jdevice.which) { 444 SDL_Event deviceevent; 445 446 RecenterGameController(controllerlist); 447 448 deviceevent.type = SDL_CONTROLLERDEVICEREMOVED; 449 deviceevent.cdevice.which = event->jdevice.which; 450 SDL_PushEvent(&deviceevent); 451 452 UpdateEventsForDeviceRemoval(device_index); 453 break; 454 } 455 controllerlist = controllerlist->next; 456 ++device_index; 457 } 458 } 459 break; 460 default: 461 break; 462 } 463 464 return 1; 465 } 466 467 #ifdef __ANDROID__ 468 /* 469 * Helper function to guess at a mapping based on the elements reported for this controller 470 */ 471 static ControllerMapping_t *SDL_CreateMappingForAndroidController(SDL_JoystickGUID guid) 472 { 473 SDL_bool existing; 474 char mapping_string[1024]; 475 int button_mask; 476 int axis_mask; 477 478 button_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-4])); 479 axis_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-2])); 480 if (!button_mask && !axis_mask) { 481 /* Accelerometer, shouldn't have a game controller mapping */ 482 return NULL; 483 } 484 485 SDL_strlcpy(mapping_string, "none,*,", sizeof(mapping_string)); 486 487 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_A)) { 488 SDL_strlcat(mapping_string, "a:b0,", sizeof(mapping_string)); 489 } 490 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_B)) { 491 SDL_strlcat(mapping_string, "b:b1,", sizeof(mapping_string)); 492 } else if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) { 493 /* Use the back button as "B" for easy UI navigation with TV remotes */ 494 SDL_strlcat(mapping_string, "b:b4,", sizeof(mapping_string)); 495 button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_BACK); 496 } 497 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_X)) { 498 SDL_strlcat(mapping_string, "x:b2,", sizeof(mapping_string)); 499 } 500 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_Y)) { 501 SDL_strlcat(mapping_string, "y:b3,", sizeof(mapping_string)); 502 } 503 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) { 504 SDL_strlcat(mapping_string, "back:b4,", sizeof(mapping_string)); 505 } 506 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_GUIDE)) { 507 /* The guide button generally isn't functional (or acts as a home button) on most Android controllers before Android 11 */ 508 if (SDL_GetAndroidSDKVersion() >= 30 /* Android 11 */) { 509 SDL_strlcat(mapping_string, "guide:b5,", sizeof(mapping_string)); 510 } 511 } 512 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) { 513 SDL_strlcat(mapping_string, "start:b6,", sizeof(mapping_string)); 514 } 515 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK)) { 516 SDL_strlcat(mapping_string, "leftstick:b7,", sizeof(mapping_string)); 517 } 518 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK)) { 519 SDL_strlcat(mapping_string, "rightstick:b8,", sizeof(mapping_string)); 520 } 521 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) { 522 SDL_strlcat(mapping_string, "leftshoulder:b9,", sizeof(mapping_string)); 523 } 524 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) { 525 SDL_strlcat(mapping_string, "rightshoulder:b10,", sizeof(mapping_string)); 526 } 527 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_UP)) { 528 SDL_strlcat(mapping_string, "dpup:b11,", sizeof(mapping_string)); 529 } 530 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN)) { 531 SDL_strlcat(mapping_string, "dpdown:b12,", sizeof(mapping_string)); 532 } 533 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT)) { 534 SDL_strlcat(mapping_string, "dpleft:b13,", sizeof(mapping_string)); 535 } 536 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) { 537 SDL_strlcat(mapping_string, "dpright:b14,", sizeof(mapping_string)); 538 } 539 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTX)) { 540 SDL_strlcat(mapping_string, "leftx:a0,", sizeof(mapping_string)); 541 } 542 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTY)) { 543 SDL_strlcat(mapping_string, "lefty:a1,", sizeof(mapping_string)); 544 } 545 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTX)) { 546 SDL_strlcat(mapping_string, "rightx:a2,", sizeof(mapping_string)); 547 } 548 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTY)) { 549 SDL_strlcat(mapping_string, "righty:a3,", sizeof(mapping_string)); 550 } 551 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT)) { 552 SDL_strlcat(mapping_string, "lefttrigger:a4,", sizeof(mapping_string)); 553 } 554 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) { 555 SDL_strlcat(mapping_string, "righttrigger:a5,", sizeof(mapping_string)); 556 } 557 558 return SDL_PrivateAddMappingForGUID(guid, mapping_string, 559 &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); 560 } 561 #endif /* __ANDROID__ */ 562 563 /* 564 * Helper function to guess at a mapping for HIDAPI controllers 565 */ 566 static ControllerMapping_t *SDL_CreateMappingForHIDAPIController(SDL_JoystickGUID guid) 567 { 568 SDL_bool existing; 569 char mapping_string[1024]; 570 Uint16 vendor; 571 Uint16 product; 572 573 SDL_strlcpy(mapping_string, "none,*,", sizeof(mapping_string)); 574 575 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL); 576 577 if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER) { 578 /* GameCube driver has 12 buttons and 6 axes */ 579 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)); 580 } else { 581 /* All other controllers have the standard set of 19 buttons and 6 axes */ 582 if (!SDL_IsJoystickNintendoSwitchPro(vendor, product) || 583 SDL_GetHintBoolean(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, SDL_TRUE)) { 584 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)); 585 } else { 586 /* Nintendo Switch Pro Controller with swapped face buttons to match Xbox Controller physical layout */ 587 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)); 588 } 589 590 if (SDL_IsJoystickXboxOneSeriesX(vendor, product)) { 591 /* XBox One Series X Controllers have a share button under the guide button */ 592 SDL_strlcat(mapping_string, "misc1:b15,", sizeof(mapping_string)); 593 } else if (SDL_IsJoystickXboxOneElite(vendor, product)) { 594 /* XBox One Elite Controllers have 4 back paddle buttons */ 595 SDL_strlcat(mapping_string, "paddle1:b15,paddle2:b17,paddle3:b16,paddle4:b18,", sizeof(mapping_string)); 596 } else if (SDL_IsJoystickSteamController(vendor, product)) { 597 /* Steam controllers have 2 back paddle buttons */ 598 SDL_strlcat(mapping_string, "paddle1:b16,paddle2:b15,", sizeof(mapping_string)); 599 } else { 600 switch (SDL_GetJoystickGameControllerTypeFromGUID(guid, NULL)) { 601 case SDL_CONTROLLER_TYPE_PS4: 602 /* PS4 controllers have an additional touchpad button */ 603 SDL_strlcat(mapping_string, "touchpad:b15,", sizeof(mapping_string)); 604 break; 605 case SDL_CONTROLLER_TYPE_PS5: 606 /* PS5 controllers have a microphone button and an additional touchpad button */ 607 SDL_strlcat(mapping_string, "misc1:b15,touchpad:b16", sizeof(mapping_string)); 608 break; 609 case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO: 610 /* Nintendo Switch Pro controllers have a screenshot button */ 611 SDL_strlcat(mapping_string, "misc1:b15,", sizeof(mapping_string)); 612 break; 613 default: 614 break; 615 } 616 } 617 } 618 619 return SDL_PrivateAddMappingForGUID(guid, mapping_string, 620 &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); 621 } 622 623 /* 624 * Helper function to guess at a mapping for RAWINPUT controllers 625 */ 626 static ControllerMapping_t *SDL_CreateMappingForRAWINPUTController(SDL_JoystickGUID guid) 627 { 628 SDL_bool existing; 629 char mapping_string[1024]; 630 631 SDL_strlcpy(mapping_string, "none,*,", sizeof(mapping_string)); 632 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:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,", sizeof(mapping_string)); 633 634 return SDL_PrivateAddMappingForGUID(guid, mapping_string, 635 &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); 636 } 637 638 /* 639 * Helper function to scan the mappings database for a controller with the specified GUID 640 */ 641 static ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID guid, SDL_bool exact_match) 642 { 643 ControllerMapping_t *mapping = s_pSupportedControllers; 644 645 while (mapping) { 646 if (SDL_memcmp(&guid, &mapping->guid, sizeof(guid)) == 0) { 647 return mapping; 648 } 649 mapping = mapping->next; 650 } 651 652 if (!exact_match) { 653 #if SDL_JOYSTICK_XINPUT 654 if (SDL_IsJoystickXInput(guid)) { 655 /* This is an XInput device */ 656 return s_pXInputMapping; 657 } 658 #endif 659 #ifdef __ANDROID__ 660 if (!mapping && !SDL_IsJoystickHIDAPI(guid)) { 661 mapping = SDL_CreateMappingForAndroidController(guid); 662 } 663 #endif 664 if (!mapping && SDL_IsJoystickHIDAPI(guid)) { 665 mapping = SDL_CreateMappingForHIDAPIController(guid); 666 } 667 if (!mapping && SDL_IsJoystickRAWINPUT(guid)) { 668 mapping = SDL_CreateMappingForRAWINPUTController(guid); 669 } 670 } 671 return mapping; 672 } 673 674 static const char* map_StringForControllerAxis[] = { 675 "leftx", 676 "lefty", 677 "rightx", 678 "righty", 679 "lefttrigger", 680 "righttrigger", 681 NULL 682 }; 683 684 /* 685 * convert a string to its enum equivalent 686 */ 687 SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *pchString) 688 { 689 int entry; 690 691 if (pchString && (*pchString == '+' || *pchString == '-')) { 692 ++pchString; 693 } 694 695 if (!pchString || !pchString[0]) { 696 return SDL_CONTROLLER_AXIS_INVALID; 697 } 698 699 for (entry = 0; map_StringForControllerAxis[entry]; ++entry) { 700 if (!SDL_strcasecmp(pchString, map_StringForControllerAxis[entry])) 701 return (SDL_GameControllerAxis) entry; 702 } 703 return SDL_CONTROLLER_AXIS_INVALID; 704 } 705 706 /* 707 * convert an enum to its string equivalent 708 */ 709 const char* SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis) 710 { 711 if (axis > SDL_CONTROLLER_AXIS_INVALID && axis < SDL_CONTROLLER_AXIS_MAX) { 712 return map_StringForControllerAxis[axis]; 713 } 714 return NULL; 715 } 716 717 static const char* map_StringForControllerButton[] = { 718 "a", 719 "b", 720 "x", 721 "y", 722 "back", 723 "guide", 724 "start", 725 "leftstick", 726 "rightstick", 727 "leftshoulder", 728 "rightshoulder", 729 "dpup", 730 "dpdown", 731 "dpleft", 732 "dpright", 733 "misc1", 734 "paddle1", 735 "paddle2", 736 "paddle3", 737 "paddle4", 738 "touchpad", 739 NULL 740 }; 741 742 /* 743 * convert a string to its enum equivalent 744 */ 745 SDL_GameControllerButton SDL_GameControllerGetButtonFromString(const char *pchString) 746 { 747 int entry; 748 if (!pchString || !pchString[0]) 749 return SDL_CONTROLLER_BUTTON_INVALID; 750 751 for (entry = 0; map_StringForControllerButton[entry]; ++entry) { 752 if (SDL_strcasecmp(pchString, map_StringForControllerButton[entry]) == 0) 753 return (SDL_GameControllerButton) entry; 754 } 755 return SDL_CONTROLLER_BUTTON_INVALID; 756 } 757 758 /* 759 * convert an enum to its string equivalent 760 */ 761 const char* SDL_GameControllerGetStringForButton(SDL_GameControllerButton axis) 762 { 763 if (axis > SDL_CONTROLLER_BUTTON_INVALID && axis < SDL_CONTROLLER_BUTTON_MAX) { 764 return map_StringForControllerButton[axis]; 765 } 766 return NULL; 767 } 768 769 /* 770 * given a controller button name and a joystick name update our mapping structure with it 771 */ 772 static void SDL_PrivateGameControllerParseElement(SDL_GameController *gamecontroller, const char *szGameButton, const char *szJoystickButton) 773 { 774 SDL_ExtendedGameControllerBind bind; 775 SDL_GameControllerButton button; 776 SDL_GameControllerAxis axis; 777 SDL_bool invert_input = SDL_FALSE; 778 char half_axis_input = 0; 779 char half_axis_output = 0; 780 781 if (*szGameButton == '+' || *szGameButton == '-') { 782 half_axis_output = *szGameButton++; 783 } 784 785 axis = SDL_GameControllerGetAxisFromString(szGameButton); 786 button = SDL_GameControllerGetButtonFromString(szGameButton); 787 if (axis != SDL_CONTROLLER_AXIS_INVALID) { 788 bind.outputType = SDL_CONTROLLER_BINDTYPE_AXIS; 789 bind.output.axis.axis = axis; 790 if (axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) { 791 bind.output.axis.axis_min = 0; 792 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX; 793 } else { 794 if (half_axis_output == '+') { 795 bind.output.axis.axis_min = 0; 796 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX; 797 } else if (half_axis_output == '-') { 798 bind.output.axis.axis_min = 0; 799 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MIN; 800 } else { 801 bind.output.axis.axis_min = SDL_JOYSTICK_AXIS_MIN; 802 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX; 803 } 804 } 805 } else if (button != SDL_CONTROLLER_BUTTON_INVALID) { 806 bind.outputType = SDL_CONTROLLER_BINDTYPE_BUTTON; 807 bind.output.button = button; 808 } else { 809 SDL_SetError("Unexpected controller element %s", szGameButton); 810 return; 811 } 812 813 if (*szJoystickButton == '+' || *szJoystickButton == '-') { 814 half_axis_input = *szJoystickButton++; 815 } 816 if (szJoystickButton[SDL_strlen(szJoystickButton) - 1] == '~') { 817 invert_input = SDL_TRUE; 818 } 819 820 if (szJoystickButton[0] == 'a' && SDL_isdigit(szJoystickButton[1])) { 821 bind.inputType = SDL_CONTROLLER_BINDTYPE_AXIS; 822 bind.input.axis.axis = SDL_atoi(&szJoystickButton[1]); 823 if (half_axis_input == '+') { 824 bind.input.axis.axis_min = 0; 825 bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX; 826 } else if (half_axis_input == '-') { 827 bind.input.axis.axis_min = 0; 828 bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MIN; 829 } else { 830 bind.input.axis.axis_min = SDL_JOYSTICK_AXIS_MIN; 831 bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX; 832 } 833 if (invert_input) { 834 int tmp = bind.input.axis.axis_min; 835 bind.input.axis.axis_min = bind.input.axis.axis_max; 836 bind.input.axis.axis_max = tmp; 837 } 838 } else if (szJoystickButton[0] == 'b' && SDL_isdigit(szJoystickButton[1])) { 839 bind.inputType = SDL_CONTROLLER_BINDTYPE_BUTTON; 840 bind.input.button = SDL_atoi(&szJoystickButton[1]); 841 } else if (szJoystickButton[0] == 'h' && SDL_isdigit(szJoystickButton[1]) && 842 szJoystickButton[2] == '.' && SDL_isdigit(szJoystickButton[3])) { 843 int hat = SDL_atoi(&szJoystickButton[1]); 844 int mask = SDL_atoi(&szJoystickButton[3]); 845 bind.inputType = SDL_CONTROLLER_BINDTYPE_HAT; 846 bind.input.hat.hat = hat; 847 bind.input.hat.hat_mask = mask; 848 } else { 849 SDL_SetError("Unexpected joystick element: %s", szJoystickButton); 850 return; 851 } 852 853 ++gamecontroller->num_bindings; 854 gamecontroller->bindings = (SDL_ExtendedGameControllerBind *)SDL_realloc(gamecontroller->bindings, gamecontroller->num_bindings * sizeof(*gamecontroller->bindings)); 855 if (!gamecontroller->bindings) { 856 gamecontroller->num_bindings = 0; 857 SDL_OutOfMemory(); 858 return; 859 } 860 gamecontroller->bindings[gamecontroller->num_bindings - 1] = bind; 861 } 862 863 864 /* 865 * given a controller mapping string update our mapping object 866 */ 867 static void 868 SDL_PrivateGameControllerParseControllerConfigString(SDL_GameController *gamecontroller, const char *pchString) 869 { 870 char szGameButton[20]; 871 char szJoystickButton[20]; 872 SDL_bool bGameButton = SDL_TRUE; 873 int i = 0; 874 const char *pchPos = pchString; 875 876 SDL_zeroa(szGameButton); 877 SDL_zeroa(szJoystickButton); 878 879 while (pchPos && *pchPos) { 880 if (*pchPos == ':') { 881 i = 0; 882 bGameButton = SDL_FALSE; 883 } else if (*pchPos == ' ') { 884 885 } else if (*pchPos == ',') { 886 i = 0; 887 bGameButton = SDL_TRUE; 888 SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton); 889 SDL_zeroa(szGameButton); 890 SDL_zeroa(szJoystickButton); 891 892 } else if (bGameButton) { 893 if (i >= sizeof(szGameButton)) { 894 SDL_SetError("Button name too large: %s", szGameButton); 895 return; 896 } 897 szGameButton[i] = *pchPos; 898 i++; 899 } else { 900 if (i >= sizeof(szJoystickButton)) { 901 SDL_SetError("Joystick button name too large: %s", szJoystickButton); 902 return; 903 } 904 szJoystickButton[i] = *pchPos; 905 i++; 906 } 907 pchPos++; 908 } 909 910 /* No more values if the string was terminated by a comma. Don't report an error. */ 911 if (szGameButton[0] != '\0' || szJoystickButton[0] != '\0') { 912 SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton); 913 } 914 } 915 916 /* 917 * Make a new button mapping struct 918 */ 919 static void SDL_PrivateLoadButtonMapping(SDL_GameController *gamecontroller, const char *pchName, const char *pchMapping) 920 { 921 int i; 922 923 gamecontroller->name = pchName; 924 gamecontroller->num_bindings = 0; 925 if (gamecontroller->joystick->naxes) { 926 SDL_memset(gamecontroller->last_match_axis, 0, gamecontroller->joystick->naxes * sizeof(*gamecontroller->last_match_axis)); 927 } 928 929 SDL_PrivateGameControllerParseControllerConfigString(gamecontroller, pchMapping); 930 931 /* Set the zero point for triggers */ 932 for (i = 0; i < gamecontroller->num_bindings; ++i) { 933 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 934 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS && 935 binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && 936 (binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || 937 binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) { 938 if (binding->input.axis.axis < gamecontroller->joystick->naxes) { 939 gamecontroller->joystick->axes[binding->input.axis.axis].value = 940 gamecontroller->joystick->axes[binding->input.axis.axis].zero = (Sint16)binding->input.axis.axis_min; 941 } 942 } 943 } 944 } 945 946 947 /* 948 * grab the guid string from a mapping string 949 */ 950 static char *SDL_PrivateGetControllerGUIDFromMappingString(const char *pMapping) 951 { 952 const char *pFirstComma = SDL_strchr(pMapping, ','); 953 if (pFirstComma) { 954 char *pchGUID = SDL_malloc(pFirstComma - pMapping + 1); 955 if (!pchGUID) { 956 SDL_OutOfMemory(); 957 return NULL; 958 } 959 SDL_memcpy(pchGUID, pMapping, pFirstComma - pMapping); 960 pchGUID[pFirstComma - pMapping] = '\0'; 961 962 /* Convert old style GUIDs to the new style in 2.0.5 */ 963 #if __WIN32__ 964 if (SDL_strlen(pchGUID) == 32 && 965 SDL_memcmp(&pchGUID[20], "504944564944", 12) == 0) { 966 SDL_memcpy(&pchGUID[20], "000000000000", 12); 967 SDL_memcpy(&pchGUID[16], &pchGUID[4], 4); 968 SDL_memcpy(&pchGUID[8], &pchGUID[0], 4); 969 SDL_memcpy(&pchGUID[0], "03000000", 8); 970 } 971 #elif __MACOSX__ 972 if (SDL_strlen(pchGUID) == 32 && 973 SDL_memcmp(&pchGUID[4], "000000000000", 12) == 0 && 974 SDL_memcmp(&pchGUID[20], "000000000000", 12) == 0) { 975 SDL_memcpy(&pchGUID[20], "000000000000", 12); 976 SDL_memcpy(&pchGUID[8], &pchGUID[0], 4); 977 SDL_memcpy(&pchGUID[0], "03000000", 8); 978 } 979 #endif 980 return pchGUID; 981 } 982 return NULL; 983 } 984 985 986 /* 987 * grab the name string from a mapping string 988 */ 989 static char *SDL_PrivateGetControllerNameFromMappingString(const char *pMapping) 990 { 991 const char *pFirstComma, *pSecondComma; 992 char *pchName; 993 994 pFirstComma = SDL_strchr(pMapping, ','); 995 if (!pFirstComma) 996 return NULL; 997 998 pSecondComma = SDL_strchr(pFirstComma + 1, ','); 999 if (!pSecondComma) 1000 return NULL; 1001 1002 pchName = SDL_malloc(pSecondComma - pFirstComma); 1003 if (!pchName) { 1004 SDL_OutOfMemory(); 1005 return NULL; 1006 } 1007 SDL_memcpy(pchName, pFirstComma + 1, pSecondComma - pFirstComma); 1008 pchName[pSecondComma - pFirstComma - 1] = 0; 1009 return pchName; 1010 } 1011 1012 1013 /* 1014 * grab the button mapping string from a mapping string 1015 */ 1016 static char *SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping) 1017 { 1018 const char *pFirstComma, *pSecondComma; 1019 1020 pFirstComma = SDL_strchr(pMapping, ','); 1021 if (!pFirstComma) 1022 return NULL; 1023 1024 pSecondComma = SDL_strchr(pFirstComma + 1, ','); 1025 if (!pSecondComma) 1026 return NULL; 1027 1028 return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */ 1029 } 1030 1031 /* 1032 * Helper function to refresh a mapping 1033 */ 1034 static void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping) 1035 { 1036 SDL_GameController *gamecontrollerlist = SDL_gamecontrollers; 1037 while (gamecontrollerlist) { 1038 if (!SDL_memcmp(&gamecontrollerlist->joystick->guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid))) { 1039 /* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */ 1040 SDL_PrivateLoadButtonMapping(gamecontrollerlist, pControllerMapping->name, pControllerMapping->mapping); 1041 1042 { 1043 SDL_Event event; 1044 event.type = SDL_CONTROLLERDEVICEREMAPPED; 1045 event.cdevice.which = gamecontrollerlist->joystick->instance_id; 1046 SDL_PushEvent(&event); 1047 } 1048 } 1049 1050 gamecontrollerlist = gamecontrollerlist->next; 1051 } 1052 } 1053 1054 /* 1055 * Helper function to add a mapping for a guid 1056 */ 1057 static ControllerMapping_t * 1058 SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing, SDL_ControllerMappingPriority priority) 1059 { 1060 char *pchName; 1061 char *pchMapping; 1062 ControllerMapping_t *pControllerMapping; 1063 1064 pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString); 1065 if (!pchName) { 1066 SDL_SetError("Couldn't parse name from %s", mappingString); 1067 return NULL; 1068 } 1069 1070 pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString); 1071 if (!pchMapping) { 1072 SDL_free(pchName); 1073 SDL_SetError("Couldn't parse %s", mappingString); 1074 return NULL; 1075 } 1076 1077 pControllerMapping = SDL_PrivateGetControllerMappingForGUID(jGUID, SDL_TRUE); 1078 if (pControllerMapping) { 1079 /* Only overwrite the mapping if the priority is the same or higher. */ 1080 if (pControllerMapping->priority <= priority) { 1081 /* Update existing mapping */ 1082 SDL_free(pControllerMapping->name); 1083 pControllerMapping->name = pchName; 1084 SDL_free(pControllerMapping->mapping); 1085 pControllerMapping->mapping = pchMapping; 1086 pControllerMapping->priority = priority; 1087 /* refresh open controllers */ 1088 SDL_PrivateGameControllerRefreshMapping(pControllerMapping); 1089 } else { 1090 SDL_free(pchName); 1091 SDL_free(pchMapping); 1092 } 1093 *existing = SDL_TRUE; 1094 } else { 1095 pControllerMapping = SDL_malloc(sizeof(*pControllerMapping)); 1096 if (!pControllerMapping) { 1097 SDL_free(pchName); 1098 SDL_free(pchMapping); 1099 SDL_OutOfMemory(); 1100 return NULL; 1101 } 1102 pControllerMapping->guid = jGUID; 1103 pControllerMapping->name = pchName; 1104 pControllerMapping->mapping = pchMapping; 1105 pControllerMapping->next = NULL; 1106 pControllerMapping->priority = priority; 1107 1108 if (s_pSupportedControllers) { 1109 /* Add the mapping to the end of the list */ 1110 ControllerMapping_t *pCurrMapping, *pPrevMapping; 1111 1112 for ( pPrevMapping = s_pSupportedControllers, pCurrMapping = pPrevMapping->next; 1113 pCurrMapping; 1114 pPrevMapping = pCurrMapping, pCurrMapping = pCurrMapping->next ) { 1115 /* continue; */ 1116 } 1117 pPrevMapping->next = pControllerMapping; 1118 } else { 1119 s_pSupportedControllers = pControllerMapping; 1120 } 1121 *existing = SDL_FALSE; 1122 } 1123 return pControllerMapping; 1124 } 1125 1126 /* 1127 * Helper function to determine pre-calculated offset to certain joystick mappings 1128 */ 1129 static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const char *name, SDL_JoystickGUID guid) 1130 { 1131 ControllerMapping_t *mapping; 1132 1133 mapping = SDL_PrivateGetControllerMappingForGUID(guid, SDL_FALSE); 1134 #ifdef __LINUX__ 1135 if (!mapping && name) { 1136 if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) { 1137 /* The Linux driver xpad.c maps the wireless dpad to buttons */ 1138 SDL_bool existing; 1139 mapping = SDL_PrivateAddMappingForGUID(guid, 1140 "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", 1141 &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); 1142 } 1143 } 1144 #endif /* __LINUX__ */ 1145 1146 if (!mapping && name && !SDL_IsJoystickWGI(guid)) { 1147 if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box") || SDL_strstr(name, "XBOX")) { 1148 mapping = s_pXInputMapping; 1149 } 1150 } 1151 if (!mapping) { 1152 mapping = s_pDefaultMapping; 1153 } 1154 return mapping; 1155 } 1156 1157 static void SDL_PrivateAppendToMappingString(char *mapping_string, 1158 size_t mapping_string_len, 1159 const char *input_name, 1160 SDL_InputMapping *mapping) 1161 { 1162 char buffer[16]; 1163 if (mapping->kind == EMappingKind_None) { 1164 return; 1165 } 1166 1167 SDL_strlcat(mapping_string, input_name, mapping_string_len); 1168 SDL_strlcat(mapping_string, ":", mapping_string_len); 1169 switch (mapping->kind) { 1170 case EMappingKind_Button: 1171 SDL_snprintf(buffer, sizeof(buffer), "b%i", mapping->target); 1172 break; 1173 case EMappingKind_Axis: 1174 SDL_snprintf(buffer, sizeof(buffer), "a%i", mapping->target); 1175 break; 1176 case EMappingKind_Hat: 1177 SDL_snprintf(buffer, sizeof(buffer), "h%i.%i", mapping->target >> 4, mapping->target & 0x0F); 1178 break; 1179 default: 1180 SDL_assert(SDL_FALSE); 1181 } 1182 1183 SDL_strlcat(mapping_string, buffer, mapping_string_len); 1184 SDL_strlcat(mapping_string, ",", mapping_string_len); 1185 } 1186 1187 static ControllerMapping_t *SDL_PrivateGenerateAutomaticControllerMapping(const char *name, 1188 SDL_JoystickGUID guid, 1189 SDL_GamepadMapping *raw_map) 1190 { 1191 SDL_bool existing; 1192 char name_string[128]; 1193 char mapping[1024]; 1194 1195 /* Remove any commas in the name */ 1196 SDL_strlcpy(name_string, name, sizeof(name_string)); 1197 { 1198 char *spot; 1199 for (spot = name_string; *spot; ++spot) { 1200 if (*spot == ',') { 1201 *spot = ' '; 1202 } 1203 } 1204 } 1205 SDL_snprintf(mapping, sizeof(mapping), "none,%s,", name_string); 1206 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "a", &raw_map->a); 1207 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "b", &raw_map->b); 1208 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "x", &raw_map->x); 1209 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "y", &raw_map->y); 1210 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "back", &raw_map->back); 1211 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "guide", &raw_map->guide); 1212 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "start", &raw_map->start); 1213 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "leftstick", &raw_map->leftstick); 1214 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "rightstick", &raw_map->rightstick); 1215 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "leftshoulder", &raw_map->leftshoulder); 1216 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "rightshoulder", &raw_map->rightshoulder); 1217 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpup", &raw_map->dpup); 1218 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpdown", &raw_map->dpdown); 1219 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpleft", &raw_map->dpleft); 1220 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "dpright", &raw_map->dpright); 1221 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "leftx", &raw_map->leftx); 1222 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "lefty", &raw_map->lefty); 1223 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "rightx", &raw_map->rightx); 1224 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "righty", &raw_map->righty); 1225 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "lefttrigger", &raw_map->lefttrigger); 1226 SDL_PrivateAppendToMappingString(mapping, sizeof(mapping), "righttrigger", &raw_map->righttrigger); 1227 1228 /* Remove trailing comma */ 1229 { 1230 int pos = (int)SDL_strlen(mapping) - 1; 1231 if (pos >= 0) { 1232 if (mapping[pos] == ',') { 1233 mapping[pos] = '\0'; 1234 } 1235 } 1236 } 1237 1238 return SDL_PrivateAddMappingForGUID(guid, mapping, 1239 &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); 1240 } 1241 1242 static ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index) 1243 { 1244 const char *name; 1245 SDL_JoystickGUID guid; 1246 ControllerMapping_t *mapping; 1247 1248 SDL_LockJoysticks(); 1249 1250 if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) { 1251 SDL_SetError("There are %d joysticks available", SDL_NumJoysticks()); 1252 SDL_UnlockJoysticks(); 1253 return (NULL); 1254 } 1255 1256 name = SDL_JoystickNameForIndex(device_index); 1257 guid = SDL_JoystickGetDeviceGUID(device_index); 1258 mapping = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid); 1259 if (!mapping) { 1260 SDL_GamepadMapping raw_map; 1261 1262 SDL_zero(raw_map); 1263 if (SDL_PrivateJoystickGetAutoGamepadMapping(device_index, &raw_map)) { 1264 mapping = SDL_PrivateGenerateAutomaticControllerMapping(name, guid, &raw_map); 1265 } 1266 } 1267 1268 SDL_UnlockJoysticks(); 1269 return mapping; 1270 } 1271 1272 /* 1273 * Add or update an entry into the Mappings Database 1274 */ 1275 int 1276 SDL_GameControllerAddMappingsFromRW(SDL_RWops * rw, int freerw) 1277 { 1278 const char *platform = SDL_GetPlatform(); 1279 int controllers = 0; 1280 char *buf, *line, *line_end, *tmp, *comma, line_platform[64]; 1281 size_t db_size, platform_len; 1282 1283 if (rw == NULL) { 1284 return SDL_SetError("Invalid RWops"); 1285 } 1286 db_size = (size_t)SDL_RWsize(rw); 1287 1288 buf = (char *)SDL_malloc(db_size + 1); 1289 if (buf == NULL) { 1290 if (freerw) { 1291 SDL_RWclose(rw); 1292 } 1293 return SDL_SetError("Could not allocate space to read DB into memory"); 1294 } 1295 1296 if (SDL_RWread(rw, buf, db_size, 1) != 1) { 1297 if (freerw) { 1298 SDL_RWclose(rw); 1299 } 1300 SDL_free(buf); 1301 return SDL_SetError("Could not read DB"); 1302 } 1303 1304 if (freerw) { 1305 SDL_RWclose(rw); 1306 } 1307 1308 buf[db_size] = '\0'; 1309 line = buf; 1310 1311 while (line < buf + db_size) { 1312 line_end = SDL_strchr(line, '\n'); 1313 if (line_end != NULL) { 1314 *line_end = '\0'; 1315 } else { 1316 line_end = buf + db_size; 1317 } 1318 1319 /* Extract and verify the platform */ 1320 tmp = SDL_strstr(line, SDL_CONTROLLER_PLATFORM_FIELD); 1321 if (tmp != NULL) { 1322 tmp += SDL_strlen(SDL_CONTROLLER_PLATFORM_FIELD); 1323 comma = SDL_strchr(tmp, ','); 1324 if (comma != NULL) { 1325 platform_len = comma - tmp + 1; 1326 if (platform_len + 1 < SDL_arraysize(line_platform)) { 1327 SDL_strlcpy(line_platform, tmp, platform_len); 1328 if (SDL_strncasecmp(line_platform, platform, platform_len) == 0 && 1329 SDL_GameControllerAddMapping(line) > 0) { 1330 controllers++; 1331 } 1332 } 1333 } 1334 } 1335 1336 line = line_end + 1; 1337 } 1338 1339 SDL_free(buf); 1340 return controllers; 1341 } 1342 1343 /* 1344 * Add or update an entry into the Mappings Database with a priority 1345 */ 1346 static int 1347 SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMappingPriority priority) 1348 { 1349 char *pchGUID; 1350 SDL_JoystickGUID jGUID; 1351 SDL_bool is_default_mapping = SDL_FALSE; 1352 SDL_bool is_xinput_mapping = SDL_FALSE; 1353 SDL_bool existing = SDL_FALSE; 1354 ControllerMapping_t *pControllerMapping; 1355 1356 if (!mappingString) { 1357 return SDL_InvalidParamError("mappingString"); 1358 } 1359 1360 { /* Extract and verify the hint field */ 1361 const char *tmp; 1362 1363 tmp = SDL_strstr(mappingString, SDL_CONTROLLER_HINT_FIELD); 1364 if (tmp != NULL) { 1365 SDL_bool default_value, value, negate; 1366 int len; 1367 char hint[128]; 1368 1369 tmp += SDL_strlen(SDL_CONTROLLER_HINT_FIELD); 1370 1371 if (*tmp == '!') { 1372 negate = SDL_TRUE; 1373 ++tmp; 1374 } else { 1375 negate = SDL_FALSE; 1376 } 1377 1378 len = 0; 1379 while (*tmp && *tmp != ',' && *tmp != ':' && len < (sizeof(hint) - 1)) { 1380 hint[len++] = *tmp++; 1381 } 1382 hint[len] = '\0'; 1383 1384 if (tmp[0] == ':' && tmp[1] == '=') { 1385 tmp += 2; 1386 default_value = SDL_atoi(tmp); 1387 } else { 1388 default_value = SDL_FALSE; 1389 } 1390 1391 value = SDL_GetHintBoolean(hint, default_value); 1392 if (negate) { 1393 value = !value; 1394 } 1395 if (!value) { 1396 return 0; 1397 } 1398 } 1399 } 1400 1401 #ifdef ANDROID 1402 { /* Extract and verify the SDK version */ 1403 const char *tmp; 1404 1405 tmp = SDL_strstr(mappingString, SDL_CONTROLLER_SDKGE_FIELD); 1406 if (tmp != NULL) { 1407 tmp += SDL_strlen(SDL_CONTROLLER_SDKGE_FIELD); 1408 if (!(SDL_GetAndroidSDKVersion() >= SDL_atoi(tmp))) { 1409 return SDL_SetError("SDK version %d < minimum version %d", SDL_GetAndroidSDKVersion(), SDL_atoi(tmp)); 1410 } 1411 } 1412 tmp = SDL_strstr(mappingString, SDL_CONTROLLER_SDKLE_FIELD); 1413 if (tmp != NULL) { 1414 tmp += SDL_strlen(SDL_CONTROLLER_SDKLE_FIELD); 1415 if (!(SDL_GetAndroidSDKVersion() <= SDL_atoi(tmp))) { 1416 return SDL_SetError("SDK version %d > maximum version %d", SDL_GetAndroidSDKVersion(), SDL_atoi(tmp)); 1417 } 1418 } 1419 } 1420 #endif 1421 1422 pchGUID = SDL_PrivateGetControllerGUIDFromMappingString(mappingString); 1423 if (!pchGUID) { 1424 return SDL_SetError("Couldn't parse GUID from %s", mappingString); 1425 } 1426 if (!SDL_strcasecmp(pchGUID, "default")) { 1427 is_default_mapping = SDL_TRUE; 1428 } else if (!SDL_strcasecmp(pchGUID, "xinput")) { 1429 is_xinput_mapping = SDL_TRUE; 1430 } 1431 jGUID = SDL_JoystickGetGUIDFromString(pchGUID); 1432 SDL_free(pchGUID); 1433 1434 pControllerMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing, priority); 1435 if (!pControllerMapping) { 1436 return -1; 1437 } 1438 1439 if (existing) { 1440 return 0; 1441 } else { 1442 if (is_default_mapping) { 1443 s_pDefaultMapping = pControllerMapping; 1444 } else if (is_xinput_mapping) { 1445 s_pXInputMapping = pControllerMapping; 1446 } 1447 return 1; 1448 } 1449 } 1450 1451 /* 1452 * Add or update an entry into the Mappings Database 1453 */ 1454 int 1455 SDL_GameControllerAddMapping(const char *mappingString) 1456 { 1457 return SDL_PrivateGameControllerAddMapping(mappingString, SDL_CONTROLLER_MAPPING_PRIORITY_API); 1458 } 1459 1460 /* 1461 * Get the number of mappings installed 1462 */ 1463 int 1464 SDL_GameControllerNumMappings(void) 1465 { 1466 int num_mappings = 0; 1467 ControllerMapping_t *mapping; 1468 1469 for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) { 1470 if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) { 1471 continue; 1472 } 1473 ++num_mappings; 1474 } 1475 return num_mappings; 1476 } 1477 1478 /* 1479 * Get the mapping at a particular index. 1480 */ 1481 char * 1482 SDL_GameControllerMappingForIndex(int mapping_index) 1483 { 1484 ControllerMapping_t *mapping; 1485 1486 for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) { 1487 if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) { 1488 continue; 1489 } 1490 if (mapping_index == 0) { 1491 char *pMappingString; 1492 char pchGUID[33]; 1493 size_t needed; 1494 1495 SDL_JoystickGetGUIDString(mapping->guid, pchGUID, sizeof(pchGUID)); 1496 /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */ 1497 needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1; 1498 pMappingString = SDL_malloc(needed); 1499 if (!pMappingString) { 1500 SDL_OutOfMemory(); 1501 return NULL; 1502 } 1503 SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping); 1504 return pMappingString; 1505 } 1506 --mapping_index; 1507 } 1508 return NULL; 1509 } 1510 1511 /* 1512 * Get the mapping string for this GUID 1513 */ 1514 char * 1515 SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid) 1516 { 1517 char *pMappingString = NULL; 1518 ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(guid, SDL_FALSE); 1519 if (mapping) { 1520 char pchGUID[33]; 1521 size_t needed; 1522 SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID)); 1523 /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */ 1524 needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1; 1525 pMappingString = SDL_malloc(needed); 1526 if (!pMappingString) { 1527 SDL_OutOfMemory(); 1528 return NULL; 1529 } 1530 SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping); 1531 } 1532 return pMappingString; 1533 } 1534 1535 /* 1536 * Get the mapping string for this device 1537 */ 1538 char * 1539 SDL_GameControllerMapping(SDL_GameController *gamecontroller) 1540 { 1541 if (!gamecontroller) { 1542 return NULL; 1543 } 1544 1545 return SDL_GameControllerMappingForGUID(gamecontroller->joystick->guid); 1546 } 1547 1548 static void 1549 SDL_GameControllerLoadHints() 1550 { 1551 const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG); 1552 if (hint && hint[0]) { 1553 size_t nchHints = SDL_strlen(hint); 1554 char *pUserMappings = SDL_malloc(nchHints + 1); 1555 char *pTempMappings = pUserMappings; 1556 SDL_memcpy(pUserMappings, hint, nchHints); 1557 pUserMappings[nchHints] = '\0'; 1558 while (pUserMappings) { 1559 char *pchNewLine = NULL; 1560 1561 pchNewLine = SDL_strchr(pUserMappings, '\n'); 1562 if (pchNewLine) 1563 *pchNewLine = '\0'; 1564 1565 SDL_PrivateGameControllerAddMapping(pUserMappings, SDL_CONTROLLER_MAPPING_PRIORITY_USER); 1566 1567 if (pchNewLine) { 1568 pUserMappings = pchNewLine + 1; 1569 } else { 1570 pUserMappings = NULL; 1571 } 1572 } 1573 SDL_free(pTempMappings); 1574 } 1575 } 1576 1577 /* 1578 * Fill the given buffer with the expected controller mapping filepath. 1579 * Usually this will just be SDL_HINT_GAMECONTROLLERCONFIG_FILE, but for 1580 * Android, we want to get the internal storage path. 1581 */ 1582 static SDL_bool SDL_GetControllerMappingFilePath(char *path, size_t size) 1583 { 1584 const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG_FILE); 1585 if (hint && *hint) { 1586 return SDL_strlcpy(path, hint, size) < size; 1587 } 1588 1589 #if defined(__ANDROID__) 1590 return SDL_snprintf(path, size, "%s/controller_map.txt", SDL_AndroidGetInternalStoragePath()) < size; 1591 #else 1592 return SDL_FALSE; 1593 #endif 1594 } 1595 1596 /* 1597 * Initialize the game controller system, mostly load our DB of controller config mappings 1598 */ 1599 int 1600 SDL_GameControllerInitMappings(void) 1601 { 1602 char szControllerMapPath[1024]; 1603 int i = 0; 1604 const char *pMappingString = NULL; 1605 pMappingString = s_ControllerMappings[i]; 1606 while (pMappingString) { 1607 SDL_PrivateGameControllerAddMapping(pMappingString, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); 1608 1609 i++; 1610 pMappingString = s_ControllerMappings[i]; 1611 } 1612 1613 if (SDL_GetControllerMappingFilePath(szControllerMapPath, sizeof(szControllerMapPath))) { 1614 SDL_GameControllerAddMappingsFromFile(szControllerMapPath); 1615 } 1616 1617 /* load in any user supplied config */ 1618 SDL_GameControllerLoadHints(); 1619 1620 SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES, 1621 SDL_GameControllerIgnoreDevicesChanged, NULL); 1622 SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT, 1623 SDL_GameControllerIgnoreDevicesExceptChanged, NULL); 1624 1625 return (0); 1626 } 1627 1628 int 1629 SDL_GameControllerInit(void) 1630 { 1631 int i; 1632 1633 /* watch for joy events and fire controller ones if needed */ 1634 SDL_AddEventWatch(SDL_GameControllerEventWatcher, NULL); 1635 1636 /* Send added events for controllers currently attached */ 1637 for (i = 0; i < SDL_NumJoysticks(); ++i) { 1638 if (SDL_IsGameController(i)) { 1639 SDL_Event deviceevent; 1640 deviceevent.type = SDL_CONTROLLERDEVICEADDED; 1641 deviceevent.cdevice.which = i; 1642 SDL_PushEvent(&deviceevent); 1643 } 1644 } 1645 1646 return (0); 1647 } 1648 1649 1650 /* 1651 * Get the implementation dependent name of a controller 1652 */ 1653 const char * 1654 SDL_GameControllerNameForIndex(int device_index) 1655 { 1656 ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index); 1657 if (pSupportedController) { 1658 if (SDL_strcmp(pSupportedController->name, "*") == 0) { 1659 return SDL_JoystickNameForIndex(device_index); 1660 } else { 1661 return pSupportedController->name; 1662 } 1663 } 1664 return NULL; 1665 } 1666 1667 1668 /** 1669 * Get the type of a game controller. 1670 */ 1671 SDL_GameControllerType 1672 SDL_GameControllerTypeForIndex(int joystick_index) 1673 { 1674 return SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGetDeviceGUID(joystick_index), SDL_JoystickNameForIndex(joystick_index)); 1675 } 1676 1677 1678 /** 1679 * Get the mapping of a game controller. 1680 * This can be called before any controllers are opened. 1681 * If no mapping can be found, this function returns NULL. 1682 */ 1683 char * 1684 SDL_GameControllerMappingForDeviceIndex(int joystick_index) 1685 { 1686 char *pMappingString = NULL; 1687 ControllerMapping_t *mapping; 1688 1689 SDL_LockJoysticks(); 1690 mapping = SDL_PrivateGetControllerMapping(joystick_index); 1691 if (mapping) { 1692 SDL_JoystickGUID guid; 1693 char pchGUID[33]; 1694 size_t needed; 1695 guid = SDL_JoystickGetDeviceGUID(joystick_index); 1696 SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID)); 1697 /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */ 1698 needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1; 1699 pMappingString = SDL_malloc(needed); 1700 if (!pMappingString) { 1701 SDL_OutOfMemory(); 1702 SDL_UnlockJoysticks(); 1703 return NULL; 1704 } 1705 SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping); 1706 } 1707 SDL_UnlockJoysticks(); 1708 return pMappingString; 1709 } 1710 1711 1712 /* 1713 * Return 1 if the joystick with this name and GUID is a supported controller 1714 */ 1715 SDL_bool 1716 SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid) 1717 { 1718 ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid); 1719 if (pSupportedController) { 1720 return SDL_TRUE; 1721 } 1722 return SDL_FALSE; 1723 } 1724 1725 /* 1726 * Return 1 if the joystick at this device index is a supported controller 1727 */ 1728 SDL_bool 1729 SDL_IsGameController(int device_index) 1730 { 1731 ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index); 1732 if (pSupportedController) { 1733 return SDL_TRUE; 1734 } 1735 return SDL_FALSE; 1736 } 1737 1738 /* 1739 * Return 1 if the game controller should be ignored by SDL 1740 */ 1741 SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid) 1742 { 1743 int i; 1744 Uint16 vendor; 1745 Uint16 product; 1746 Uint16 version; 1747 Uint32 vidpid; 1748 1749 #if defined(__LINUX__) 1750 if (name && SDL_strstr(name, "Motion Sensors")) { 1751 /* Don't treat the PS3 and PS4 motion controls as a separate game controller */ 1752 return SDL_TRUE; 1753 } 1754 #endif 1755 1756 if (SDL_allowed_controllers.num_entries == 0 && 1757 SDL_ignored_controllers.num_entries == 0) { 1758 return SDL_FALSE; 1759 } 1760 1761 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, &version); 1762 1763 if (SDL_GetHintBoolean("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD", SDL_FALSE)) { 1764 /* 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 */ 1765 SDL_bool bSteamVirtualGamepad = SDL_FALSE; 1766 #if defined(__LINUX__) 1767 bSteamVirtualGamepad = (vendor == 0x28DE && product == 0x11FF); 1768 #elif defined(__MACOSX__) 1769 bSteamVirtualGamepad = (vendor == 0x045E && product == 0x028E && version == 1); 1770 #elif defined(__WIN32__) 1771 /* We can't tell on Windows, but Steam will block others in input hooks */ 1772 bSteamVirtualGamepad = SDL_TRUE; 1773 #endif 1774 if (bSteamVirtualGamepad) { 1775 return SDL_FALSE; 1776 } 1777 } 1778 1779 vidpid = MAKE_VIDPID(vendor, product); 1780 1781 if (SDL_allowed_controllers.num_entries > 0) { 1782 for (i = 0; i < SDL_allowed_controllers.num_entries; ++i) { 1783 if (vidpid == SDL_allowed_controllers.entries[i]) { 1784 return SDL_FALSE; 1785 } 1786 } 1787 return SDL_TRUE; 1788 } else { 1789 for (i = 0; i < SDL_ignored_controllers.num_entries; ++i) { 1790 if (vidpid == SDL_ignored_controllers.entries[i]) { 1791 return SDL_TRUE; 1792 } 1793 } 1794 return SDL_FALSE; 1795 } 1796 } 1797 1798 /* 1799 * Open a controller for use - the index passed as an argument refers to 1800 * the N'th controller on the system. This index is the value which will 1801 * identify this controller in future controller events. 1802 * 1803 * This function returns a controller identifier, or NULL if an error occurred. 1804 */ 1805 SDL_GameController * 1806 SDL_GameControllerOpen(int device_index) 1807 { 1808 SDL_JoystickID instance_id; 1809 SDL_GameController *gamecontroller; 1810 SDL_GameController *gamecontrollerlist; 1811 ControllerMapping_t *pSupportedController = NULL; 1812 1813 SDL_LockJoysticks(); 1814 1815 gamecontrollerlist = SDL_gamecontrollers; 1816 /* If the controller is already open, return it */ 1817 instance_id = SDL_JoystickGetDeviceInstanceID(device_index); 1818 while (gamecontrollerlist) { 1819 if (instance_id == gamecontrollerlist->joystick->instance_id) { 1820 gamecontroller = gamecontrollerlist; 1821 ++gamecontroller->ref_count; 1822 SDL_UnlockJoysticks(); 1823 return (gamecontroller); 1824 } 1825 gamecontrollerlist = gamecontrollerlist->next; 1826 } 1827 1828 /* Find a controller mapping */ 1829 pSupportedController = SDL_PrivateGetControllerMapping(device_index); 1830 if (!pSupportedController) { 1831 SDL_SetError("Couldn't find mapping for device (%d)", device_index); 1832 SDL_UnlockJoysticks(); 1833 return NULL; 1834 } 1835 1836 /* Create and initialize the controller */ 1837 gamecontroller = (SDL_GameController *) SDL_calloc(1, sizeof(*gamecontroller)); 1838 if (gamecontroller == NULL) { 1839 SDL_OutOfMemory(); 1840 SDL_UnlockJoysticks(); 1841 return NULL; 1842 } 1843 1844 gamecontroller->joystick = SDL_JoystickOpen(device_index); 1845 if (!gamecontroller->joystick) { 1846 SDL_free(gamecontroller); 1847 SDL_UnlockJoysticks(); 1848 return NULL; 1849 } 1850 1851 if (gamecontroller->joystick->naxes) { 1852 gamecontroller->last_match_axis = (SDL_ExtendedGameControllerBind **)SDL_calloc(gamecontroller->joystick->naxes, sizeof(*gamecontroller->last_match_axis)); 1853 if (!gamecontroller->last_match_axis) { 1854 SDL_OutOfMemory(); 1855 SDL_JoystickClose(gamecontroller->joystick); 1856 SDL_free(gamecontroller); 1857 SDL_UnlockJoysticks(); 1858 return NULL; 1859 } 1860 } 1861 if (gamecontroller->joystick->nhats) { 1862 gamecontroller->last_hat_mask = (Uint8 *)SDL_calloc(gamecontroller->joystick->nhats, sizeof(*gamecontroller->last_hat_mask)); 1863 if (!gamecontroller->last_hat_mask) { 1864 SDL_OutOfMemory(); 1865 SDL_JoystickClose(gamecontroller->joystick); 1866 SDL_free(gamecontroller->last_match_axis); 1867 SDL_free(gamecontroller); 1868 SDL_UnlockJoysticks(); 1869 return NULL; 1870 } 1871 } 1872 1873 SDL_PrivateLoadButtonMapping(gamecontroller, pSupportedController->name, pSupportedController->mapping); 1874 1875 /* Add the controller to list */ 1876 ++gamecontroller->ref_count; 1877 /* Link the controller in the list */ 1878 gamecontroller->next = SDL_gamecontrollers; 1879 SDL_gamecontrollers = gamecontroller; 1880 1881 SDL_UnlockJoysticks(); 1882 1883 return (gamecontroller); 1884 } 1885 1886 /* 1887 * Manually pump for controller updates. 1888 */ 1889 void 1890 SDL_GameControllerUpdate(void) 1891 { 1892 /* Just for API completeness; the joystick API does all the work. */ 1893 SDL_JoystickUpdate(); 1894 } 1895 1896 /** 1897 * Return whether a game controller has a given axis 1898 */ 1899 SDL_bool 1900 SDL_GameControllerHasAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis) 1901 { 1902 SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(gamecontroller, axis); 1903 return (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) ? SDL_TRUE : SDL_FALSE; 1904 } 1905 1906 /* 1907 * Get the current state of an axis control on a controller 1908 */ 1909 Sint16 1910 SDL_GameControllerGetAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis) 1911 { 1912 int i; 1913 1914 if (!gamecontroller) 1915 return 0; 1916 1917 for (i = 0; i < gamecontroller->num_bindings; ++i) { 1918 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 1919 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) { 1920 int value = 0; 1921 SDL_bool valid_input_range; 1922 SDL_bool valid_output_range; 1923 1924 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 1925 value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis); 1926 if (binding->input.axis.axis_min < binding->input.axis.axis_max) { 1927 valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max); 1928 } else { 1929 valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min); 1930 } 1931 if (valid_input_range) { 1932 if (binding->input.axis.axis_min != binding->output.axis.axis_min || binding->input.axis.axis_max != binding->output.axis.axis_max) { 1933 float normalized_value = (float)(value - binding->input.axis.axis_min) / (binding->input.axis.axis_max - binding->input.axis.axis_min); 1934 value = binding->output.axis.axis_min + (int)(normalized_value * (binding->output.axis.axis_max - binding->output.axis.axis_min)); 1935 } 1936 } else { 1937 value = 0; 1938 } 1939 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) { 1940 value = SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button); 1941 if (value == SDL_PRESSED) { 1942 value = binding->output.axis.axis_max; 1943 } 1944 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) { 1945 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat); 1946 if (hat_mask & binding->input.hat.hat_mask) { 1947 value = binding->output.axis.axis_max; 1948 } 1949 } 1950 1951 if (binding->output.axis.axis_min < binding->output.axis.axis_max) { 1952 valid_output_range = (value >= binding->output.axis.axis_min && value <= binding->output.axis.axis_max); 1953 } else { 1954 valid_output_range = (value >= binding->output.axis.axis_max && value <= binding->output.axis.axis_min); 1955 } 1956 /* If the value is zero, there might be another binding that makes it non-zero */ 1957 if (value != 0 && valid_output_range) { 1958 return (Sint16)value; 1959 } 1960 } 1961 } 1962 return 0; 1963 } 1964 1965 /** 1966 * Return whether a game controller has a given button 1967 */ 1968 SDL_bool 1969 SDL_GameControllerHasButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button) 1970 { 1971 SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(gamecontroller, button); 1972 return (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) ? SDL_TRUE : SDL_FALSE; 1973 } 1974 1975 /* 1976 * Get the current state of a button on a controller 1977 */ 1978 Uint8 1979 SDL_GameControllerGetButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button) 1980 { 1981 int i; 1982 1983 if (!gamecontroller) 1984 return 0; 1985 1986 for (i = 0; i < gamecontroller->num_bindings; ++i) { 1987 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 1988 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) { 1989 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 1990 SDL_bool valid_input_range; 1991 1992 int value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis); 1993 int threshold = binding->input.axis.axis_min + (binding->input.axis.axis_max - binding->input.axis.axis_min) / 2; 1994 if (binding->input.axis.axis_min < binding->input.axis.axis_max) { 1995 valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max); 1996 if (valid_input_range) { 1997 return (value >= threshold) ? SDL_PRESSED : SDL_RELEASED; 1998 } 1999 } else { 2000 valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min); 2001 if (valid_input_range) { 2002 return (value <= threshold) ? SDL_PRESSED : SDL_RELEASED; 2003 } 2004 } 2005 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) { 2006 return SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button); 2007 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) { 2008 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat); 2009 return (hat_mask & binding->input.hat.hat_mask) ? SDL_PRESSED : SDL_RELEASED; 2010 } 2011 } 2012 } 2013 return SDL_RELEASED; 2014 } 2015 2016 /** 2017 * Get the number of touchpads on a game controller. 2018 */ 2019 int 2020 SDL_GameControllerGetNumTouchpads(SDL_GameController *gamecontroller) 2021 { 2022 SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller); 2023 2024 if (joystick) { 2025 return joystick->ntouchpads; 2026 } 2027 return 0; 2028 } 2029 2030 /** 2031 * Get the number of supported simultaneous fingers on a touchpad on a game controller. 2032 */ 2033 int SDL_GameControllerGetNumTouchpadFingers(SDL_GameController *gamecontroller, int touchpad) 2034 { 2035 SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller); 2036 2037 if (joystick && touchpad >= 0 && touchpad < joystick->ntouchpads) { 2038 return joystick->touchpads[touchpad].nfingers; 2039 } 2040 return 0; 2041 } 2042 2043 /** 2044 * Get the current state of a finger on a touchpad on a game controller. 2045 */ 2046 int 2047 SDL_GameControllerGetTouchpadFinger(SDL_GameController *gamecontroller, int touchpad, int finger, Uint8 *state, float *x, float *y, float *pressure) 2048 { 2049 SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller); 2050 2051 if (joystick ) { 2052 if (touchpad >= 0 && touchpad < joystick->ntouchpads) { 2053 SDL_JoystickTouchpadInfo *touchpad_info = &joystick->touchpads[touchpad]; 2054 if (finger >= 0 && finger < touchpad_info->nfingers) { 2055 SDL_JoystickTouchpadFingerInfo *info = &touchpad_info->fingers[finger]; 2056 2057 if (state) { 2058 *state = info->state; 2059 } 2060 if (x) { 2061 *x = info->x; 2062 } 2063 if (y) { 2064 *y = info->y; 2065 } 2066 if (pressure) { 2067 *pressure = info->pressure; 2068 } 2069 return 0; 2070 } else { 2071 return SDL_InvalidParamError("finger"); 2072 } 2073 } else { 2074 return SDL_InvalidParamError("touchpad"); 2075 } 2076 } else { 2077 return SDL_InvalidParamError("gamecontroller"); 2078 } 2079 } 2080 2081 /** 2082 * Return whether a game controller has a particular sensor. 2083 */ 2084 SDL_bool 2085 SDL_GameControllerHasSensor(SDL_GameController *gamecontroller, SDL_SensorType type) 2086 { 2087 SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller); 2088 int i; 2089 2090 if (joystick) { 2091 for (i = 0; i < joystick->nsensors; ++i) { 2092 if (joystick->sensors[i].type == type) { 2093 return SDL_TRUE; 2094 } 2095 } 2096 } 2097 return SDL_FALSE; 2098 } 2099 2100 /* 2101 * Set whether data reporting for a game controller sensor is enabled 2102 */ 2103 int SDL_GameControllerSetSensorEnabled(SDL_GameController *gamecontroller, SDL_SensorType type, SDL_bool enabled) 2104 { 2105 SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller); 2106 int i; 2107 2108 if (!joystick) { 2109 return SDL_InvalidParamError("gamecontroller"); 2110 } 2111 2112 for (i = 0; i < joystick->nsensors; ++i) { 2113 SDL_JoystickSensorInfo *sensor = &joystick->sensors[i]; 2114 2115 if (sensor->type == type) { 2116 if (sensor->enabled == enabled) { 2117 return 0; 2118 } 2119 2120 if (enabled) { 2121 if (joystick->nsensors_enabled == 0) { 2122 if (joystick->driver->SetSensorsEnabled(joystick, SDL_TRUE) < 0) { 2123 return -1; 2124 } 2125 } 2126 ++joystick->nsensors_enabled; 2127 } else { 2128 if (joystick->nsensors_enabled == 1) { 2129 if (joystick->driver->SetSensorsEnabled(joystick, SDL_FALSE) < 0) { 2130 return -1; 2131 } 2132 } 2133 --joystick->nsensors_enabled; 2134 } 2135 2136 sensor->enabled = enabled; 2137 return 0; 2138 } 2139 } 2140 return SDL_Unsupported(); 2141 } 2142 2143 /* 2144 * Query whether sensor data reporting is enabled for a game controller 2145 */ 2146 SDL_bool SDL_GameControllerIsSensorEnabled(SDL_GameController *gamecontroller, SDL_SensorType type) 2147 { 2148 SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller); 2149 int i; 2150 2151 if (joystick) { 2152 for (i = 0; i < joystick->nsensors; ++i) { 2153 if (joystick->sensors[i].type == type) { 2154 return joystick->sensors[i].enabled; 2155 } 2156 } 2157 } 2158 return SDL_FALSE; 2159 } 2160 2161 /* 2162 * Get the current state of a game controller sensor. 2163 */ 2164 int 2165 SDL_GameControllerGetSensorData(SDL_GameController *gamecontroller, SDL_SensorType type, float *data, int num_values) 2166 { 2167 SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller); 2168 int i; 2169 2170 if (!joystick) { 2171 return SDL_InvalidParamError("gamecontroller"); 2172 } 2173 2174 for (i = 0; i < joystick->nsensors; ++i) { 2175 SDL_JoystickSensorInfo *sensor = &joystick->sensors[i]; 2176 2177 if (sensor->type == type) { 2178 num_values = SDL_min(num_values, SDL_arraysize(sensor->data)); 2179 SDL_memcpy(data, sensor->data, num_values*sizeof(*data)); 2180 return 0; 2181 } 2182 } 2183 return SDL_Unsupported(); 2184 } 2185 2186 const char * 2187 SDL_GameControllerName(SDL_GameController *gamecontroller) 2188 { 2189 if (!gamecontroller) 2190 return NULL; 2191 2192 if (SDL_strcmp(gamecontroller->name, "*") == 0) { 2193 return SDL_JoystickName(SDL_GameControllerGetJoystick(gamecontroller)); 2194 } else { 2195 return gamecontroller->name; 2196 } 2197 } 2198 2199 SDL_GameControllerType 2200 SDL_GameControllerGetType(SDL_GameController *gamecontroller) 2201 { 2202 return SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGetGUID(SDL_GameControllerGetJoystick(gamecontroller)), SDL_JoystickName(SDL_GameControllerGetJoystick(gamecontroller))); 2203 } 2204 2205 int 2206 SDL_GameControllerGetPlayerIndex(SDL_GameController *gamecontroller) 2207 { 2208 return SDL_JoystickGetPlayerIndex(SDL_GameControllerGetJoystick(gamecontroller)); 2209 } 2210 2211 /** 2212 * Set the player index of an opened game controller 2213 */ 2214 void 2215 SDL_GameControllerSetPlayerIndex(SDL_GameController *gamecontroller, int player_index) 2216 { 2217 SDL_JoystickSetPlayerIndex(SDL_GameControllerGetJoystick(gamecontroller), player_index); 2218 } 2219 2220 Uint16 2221 SDL_GameControllerGetVendor(SDL_GameController *gamecontroller) 2222 { 2223 return SDL_JoystickGetVendor(SDL_GameControllerGetJoystick(gamecontroller)); 2224 } 2225 2226 Uint16 2227 SDL_GameControllerGetProduct(SDL_GameController *gamecontroller) 2228 { 2229 return SDL_JoystickGetProduct(SDL_GameControllerGetJoystick(gamecontroller)); 2230 } 2231 2232 Uint16 2233 SDL_GameControllerGetProductVersion(SDL_GameController *gamecontroller) 2234 { 2235 return SDL_JoystickGetProductVersion(SDL_GameControllerGetJoystick(gamecontroller)); 2236 } 2237 2238 const char * 2239 SDL_GameControllerGetSerial(SDL_GameController *gamecontroller) 2240 { 2241 return SDL_JoystickGetSerial(SDL_GameControllerGetJoystick(gamecontroller)); 2242 } 2243 2244 /* 2245 * Return if the controller in question is currently attached to the system, 2246 * \return 0 if not plugged in, 1 if still present. 2247 */ 2248 SDL_bool 2249 SDL_GameControllerGetAttached(SDL_GameController *gamecontroller) 2250 { 2251 if (!gamecontroller) 2252 return SDL_FALSE; 2253 2254 return SDL_JoystickGetAttached(gamecontroller->joystick); 2255 } 2256 2257 /* 2258 * Get the joystick for this controller 2259 */ 2260 SDL_Joystick * 2261 SDL_GameControllerGetJoystick(SDL_GameController *gamecontroller) 2262 { 2263 if (!gamecontroller) 2264 return NULL; 2265 2266 return gamecontroller->joystick; 2267 } 2268 2269 2270 /* 2271 * Return the SDL_GameController associated with an instance id. 2272 */ 2273 SDL_GameController * 2274 SDL_GameControllerFromInstanceID(SDL_JoystickID joyid) 2275 { 2276 SDL_GameController *gamecontroller; 2277 2278 SDL_LockJoysticks(); 2279 gamecontroller = SDL_gamecontrollers; 2280 while (gamecontroller) { 2281 if (gamecontroller->joystick->instance_id == joyid) { 2282 SDL_UnlockJoysticks(); 2283 return gamecontroller; 2284 } 2285 gamecontroller = gamecontroller->next; 2286 } 2287 SDL_UnlockJoysticks(); 2288 return NULL; 2289 } 2290 2291 2292 /** 2293 * Return the SDL_GameController associated with a player index. 2294 */ 2295 SDL_GameController *SDL_GameControllerFromPlayerIndex(int player_index) 2296 { 2297 SDL_Joystick *joystick = SDL_JoystickFromPlayerIndex(player_index); 2298 if (joystick) { 2299 return SDL_GameControllerFromInstanceID(joystick->instance_id); 2300 } 2301 return NULL; 2302 } 2303 2304 2305 /* 2306 * Get the SDL joystick layer binding for this controller axis mapping 2307 */ 2308 SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis) 2309 { 2310 int i; 2311 SDL_GameControllerButtonBind bind; 2312 SDL_zero(bind); 2313 2314 if (!gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID) 2315 return bind; 2316 2317 for (i = 0; i < gamecontroller->num_bindings; ++i) { 2318 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 2319 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) { 2320 bind.bindType = binding->inputType; 2321 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 2322 /* FIXME: There might be multiple axes bound now that we have axis ranges... */ 2323 bind.value.axis = binding->input.axis.axis; 2324 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) { 2325 bind.value.button = binding->input.button; 2326 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) { 2327 bind.value.hat.hat = binding->input.hat.hat; 2328 bind.value.hat.hat_mask = binding->input.hat.hat_mask; 2329 } 2330 break; 2331 } 2332 } 2333 return bind; 2334 } 2335 2336 2337 /* 2338 * Get the SDL joystick layer binding for this controller button mapping 2339 */ 2340 SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button) 2341 { 2342 int i; 2343 SDL_GameControllerButtonBind bind; 2344 SDL_zero(bind); 2345 2346 if (!gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID) 2347 return bind; 2348 2349 for (i = 0; i < gamecontroller->num_bindings; ++i) { 2350 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 2351 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) { 2352 bind.bindType = binding->inputType; 2353 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 2354 bind.value.axis = binding->input.axis.axis; 2355 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) { 2356 bind.value.button = binding->input.button; 2357 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) { 2358 bind.value.hat.hat = binding->input.hat.hat; 2359 bind.value.hat.hat_mask = binding->input.hat.hat_mask; 2360 } 2361 break; 2362 } 2363 } 2364 return bind; 2365 } 2366 2367 2368 int 2369 SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) 2370 { 2371 return SDL_JoystickRumble(SDL_GameControllerGetJoystick(gamecontroller), low_frequency_rumble, high_frequency_rumble, duration_ms); 2372 } 2373 2374 int 2375 SDL_GameControllerRumbleTriggers(SDL_GameController *gamecontroller, Uint16 left_rumble, Uint16 right_rumble, Uint32 duration_ms) 2376 { 2377 return SDL_JoystickRumbleTriggers(SDL_GameControllerGetJoystick(gamecontroller), left_rumble, right_rumble, duration_ms); 2378 } 2379 2380 SDL_bool 2381 SDL_GameControllerHasLED(SDL_GameController *gamecontroller) 2382 { 2383 return SDL_JoystickHasLED(SDL_GameControllerGetJoystick(gamecontroller)); 2384 } 2385 2386 int 2387 SDL_GameControllerSetLED(SDL_GameController *gamecontroller, Uint8 red, Uint8 green, Uint8 blue) 2388 { 2389 return SDL_JoystickSetLED(SDL_GameControllerGetJoystick(gamecontroller), red, green, blue); 2390 } 2391 2392 void 2393 SDL_GameControllerClose(SDL_GameController *gamecontroller) 2394 { 2395 SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev; 2396 2397 if (!gamecontroller) 2398 return; 2399 2400 SDL_LockJoysticks(); 2401 2402 /* First decrement ref count */ 2403 if (--gamecontroller->ref_count > 0) { 2404 SDL_UnlockJoysticks(); 2405 return; 2406 } 2407 2408 SDL_JoystickClose(gamecontroller->joystick); 2409 2410 gamecontrollerlist = SDL_gamecontrollers; 2411 gamecontrollerlistprev = NULL; 2412 while (gamecontrollerlist) { 2413 if (gamecontroller == gamecontrollerlist) { 2414 if (gamecontrollerlistprev) { 2415 /* unlink this entry */ 2416 gamecontrollerlistprev->next = gamecontrollerlist->next; 2417 } else { 2418 SDL_gamecontrollers = gamecontroller->next; 2419 } 2420 break; 2421 } 2422 gamecontrollerlistprev = gamecontrollerlist; 2423 gamecontrollerlist = gamecontrollerlist->next; 2424 } 2425 2426 SDL_free(gamecontroller->bindings); 2427 SDL_free(gamecontroller->last_match_axis); 2428 SDL_free(gamecontroller->last_hat_mask); 2429 SDL_free(gamecontroller); 2430 2431 SDL_UnlockJoysticks(); 2432 } 2433 2434 2435 /* 2436 * Quit the controller subsystem 2437 */ 2438 void 2439 SDL_GameControllerQuit(void) 2440 { 2441 SDL_LockJoysticks(); 2442 while (SDL_gamecontrollers) { 2443 SDL_gamecontrollers->ref_count = 1; 2444 SDL_GameControllerClose(SDL_gamecontrollers); 2445 } 2446 SDL_UnlockJoysticks(); 2447 } 2448 2449 void 2450 SDL_GameControllerQuitMappings(void) 2451 { 2452 ControllerMapping_t *pControllerMap; 2453 2454 while (s_pSupportedControllers) { 2455 pControllerMap = s_pSupportedControllers; 2456 s_pSupportedControllers = s_pSupportedControllers->next; 2457 SDL_free(pControllerMap->name); 2458 SDL_free(pControllerMap->mapping); 2459 SDL_free(pControllerMap); 2460 } 2461 2462 SDL_DelEventWatch(SDL_GameControllerEventWatcher, NULL); 2463 2464 SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES, 2465 SDL_GameControllerIgnoreDevicesChanged, NULL); 2466 SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT, 2467 SDL_GameControllerIgnoreDevicesExceptChanged, NULL); 2468 2469 if (SDL_allowed_controllers.entries) { 2470 SDL_free(SDL_allowed_controllers.entries); 2471 SDL_zero(SDL_allowed_controllers); 2472 } 2473 if (SDL_ignored_controllers.entries) { 2474 SDL_free(SDL_ignored_controllers.entries); 2475 SDL_zero(SDL_ignored_controllers); 2476 } 2477 } 2478 2479 /* 2480 * Event filter to transform joystick events into appropriate game controller ones 2481 */ 2482 static int 2483 SDL_PrivateGameControllerAxis(SDL_GameController *gamecontroller, SDL_GameControllerAxis axis, Sint16 value) 2484 { 2485 int posted; 2486 2487 /* translate the event, if desired */ 2488 posted = 0; 2489 #if !SDL_EVENTS_DISABLED 2490 if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) { 2491 SDL_Event event; 2492 event.type = SDL_CONTROLLERAXISMOTION; 2493 event.caxis.which = gamecontroller->joystick->instance_id; 2494 event.caxis.axis = axis; 2495 event.caxis.value = value; 2496 posted = SDL_PushEvent(&event) == 1; 2497 } 2498 #endif /* !SDL_EVENTS_DISABLED */ 2499 return (posted); 2500 } 2501 2502 2503 /* 2504 * Event filter to transform joystick events into appropriate game controller ones 2505 */ 2506 static int 2507 SDL_PrivateGameControllerButton(SDL_GameController *gamecontroller, SDL_GameControllerButton button, Uint8 state) 2508 { 2509 int posted; 2510 #if !SDL_EVENTS_DISABLED 2511 SDL_Event event; 2512 2513 if (button == SDL_CONTROLLER_BUTTON_INVALID) 2514 return (0); 2515 2516 switch (state) { 2517 case SDL_PRESSED: 2518 event.type = SDL_CONTROLLERBUTTONDOWN; 2519 break; 2520 case SDL_RELEASED: 2521 event.type = SDL_CONTROLLERBUTTONUP; 2522 break; 2523 default: 2524 /* Invalid state -- bail */ 2525 return (0); 2526 } 2527 #endif /* !SDL_EVENTS_DISABLED */ 2528 2529 if (button == SDL_CONTROLLER_BUTTON_GUIDE) { 2530 Uint32 now = SDL_GetTicks(); 2531 if (state == SDL_PRESSED) { 2532 gamecontroller->guide_button_down = now; 2533 2534 if (gamecontroller->joystick->delayed_guide_button) { 2535 /* Skip duplicate press */ 2536 return (0); 2537 } 2538 } else { 2539 if (!SDL_TICKS_PASSED(now, gamecontroller->guide_button_down+SDL_MINIMUM_GUIDE_BUTTON_DELAY_MS)) { 2540 gamecontroller->joystick->delayed_guide_button = SDL_TRUE; 2541 return (0); 2542 } 2543 gamecontroller->joystick->delayed_guide_button = SDL_FALSE; 2544 } 2545 } 2546 2547 /* translate the event, if desired */ 2548 posted = 0; 2549 #if !SDL_EVENTS_DISABLED 2550 if (SDL_GetEventState(event.type) == SDL_ENABLE) { 2551 event.cbutton.which = gamecontroller->joystick->instance_id; 2552 event.cbutton.button = button; 2553 event.cbutton.state = state; 2554 posted = SDL_PushEvent(&event) == 1; 2555 } 2556 #endif /* !SDL_EVENTS_DISABLED */ 2557 return (posted); 2558 } 2559 2560 /* 2561 * Turn off controller events 2562 */ 2563 int 2564 SDL_GameControllerEventState(int state) 2565 { 2566 #if SDL_EVENTS_DISABLED 2567 return SDL_IGNORE; 2568 #else 2569 const Uint32 event_list[] = { 2570 SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP, 2571 SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED, 2572 }; 2573 unsigned int i; 2574 2575 switch (state) { 2576 case SDL_QUERY: 2577 state = SDL_IGNORE; 2578 for (i = 0; i < SDL_arraysize(event_list); ++i) { 2579 state = SDL_EventState(event_list[i], SDL_QUERY); 2580 if (state == SDL_ENABLE) { 2581 break; 2582 } 2583 } 2584 break; 2585 default: 2586 for (i = 0; i < SDL_arraysize(event_list); ++i) { 2587 SDL_EventState(event_list[i], state); 2588 } 2589 break; 2590 } 2591 return (state); 2592 #endif /* SDL_EVENTS_DISABLED */ 2593 } 2594 2595 void 2596 SDL_GameControllerHandleDelayedGuideButton(SDL_Joystick *joystick) 2597 { 2598 SDL_GameController *controllerlist = SDL_gamecontrollers; 2599 while (controllerlist) { 2600 if (controllerlist->joystick == joystick) { 2601 SDL_PrivateGameControllerButton(controllerlist, SDL_CONTROLLER_BUTTON_GUIDE, SDL_RELEASED); 2602 break; 2603 } 2604 controllerlist = controllerlist->next; 2605 } 2606 } 2607 2608 /* vi: set ts=4 sw=4 expandtab: */