Atlas - SDL_gamecontroller.c
Home / ext / SDL2 / src / joystick Lines: 3 | Size: 68789 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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_assert.h" 27#include "SDL_hints.h" 28#include "SDL_timer.h" 29#include "SDL_sysjoystick.h" 30#include "SDL_joystick_c.h" 31#include "SDL_gamecontrollerdb.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 47/* a list of currently opened game controllers */ 48static SDL_GameController *SDL_gamecontrollers = NULL; 49 50typedef struct 51{ 52 SDL_GameControllerBindType inputType; 53 union 54 { 55 int button; 56 57 struct { 58 int axis; 59 int axis_min; 60 int axis_max; 61 } axis; 62 63 struct { 64 int hat; 65 int hat_mask; 66 } hat; 67 68 } input; 69 70 SDL_GameControllerBindType outputType; 71 union 72 { 73 SDL_GameControllerButton button; 74 75 struct { 76 SDL_GameControllerAxis axis; 77 int axis_min; 78 int axis_max; 79 } axis; 80 81 } output; 82 83} SDL_ExtendedGameControllerBind; 84 85/* our hard coded list of mapping support */ 86typedef enum 87{ 88 SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT, 89 SDL_CONTROLLER_MAPPING_PRIORITY_API, 90 SDL_CONTROLLER_MAPPING_PRIORITY_USER, 91} SDL_ControllerMappingPriority; 92 93typedef struct _ControllerMapping_t 94{ 95 SDL_JoystickGUID guid; 96 char *name; 97 char *mapping; 98 SDL_ControllerMappingPriority priority; 99 struct _ControllerMapping_t *next; 100} ControllerMapping_t; 101 102static SDL_JoystickGUID s_zeroGUID; 103static ControllerMapping_t *s_pSupportedControllers = NULL; 104static ControllerMapping_t *s_pDefaultMapping = NULL; 105static ControllerMapping_t *s_pHIDAPIMapping = NULL; 106static ControllerMapping_t *s_pXInputMapping = NULL; 107 108/* The SDL game controller structure */ 109struct _SDL_GameController 110{ 111 SDL_Joystick *joystick; /* underlying joystick device */ 112 int ref_count; 113 114 SDL_JoystickGUID guid; 115 const char *name; 116 int num_bindings; 117 SDL_ExtendedGameControllerBind *bindings; 118 SDL_ExtendedGameControllerBind **last_match_axis; 119 Uint8 *last_hat_mask; 120 Uint32 guide_button_down; 121 122 struct _SDL_GameController *next; /* pointer to next game controller we have allocated */ 123}; 124 125 126typedef struct 127{ 128 int num_entries; 129 int max_entries; 130 Uint32 *entries; 131} SDL_vidpid_list; 132 133static SDL_vidpid_list SDL_allowed_controllers; 134static SDL_vidpid_list SDL_ignored_controllers; 135 136static void 137SDL_LoadVIDPIDListFromHint(const char *hint, SDL_vidpid_list *list) 138{ 139 Uint32 entry; 140 char *spot; 141 char *file = NULL; 142 143 list->num_entries = 0; 144 145 if (hint && *hint == '@') { 146 spot = file = (char *)SDL_LoadFile(hint+1, NULL); 147 } else { 148 spot = (char *)hint; 149 } 150 151 if (!spot) { 152 return; 153 } 154 155 while ((spot = SDL_strstr(spot, "0x")) != NULL) { 156 entry = (Uint16)SDL_strtol(spot, &spot, 0); 157 entry <<= 16; 158 spot = SDL_strstr(spot, "0x"); 159 if (!spot) { 160 break; 161 } 162 entry |= (Uint16)SDL_strtol(spot, &spot, 0); 163 164 if (list->num_entries == list->max_entries) { 165 int max_entries = list->max_entries + 16; 166 Uint32 *entries = (Uint32 *)SDL_realloc(list->entries, max_entries*sizeof(*list->entries)); 167 if (entries == NULL) { 168 /* Out of memory, go with what we have already */ 169 break; 170 } 171 list->entries = entries; 172 list->max_entries = max_entries; 173 } 174 list->entries[list->num_entries++] = entry; 175 } 176 177 if (file) { 178 SDL_free(file); 179 } 180} 181 182static void SDLCALL 183SDL_GameControllerIgnoreDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 184{ 185 SDL_LoadVIDPIDListFromHint(hint, &SDL_ignored_controllers); 186} 187 188static void SDLCALL 189SDL_GameControllerIgnoreDevicesExceptChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 190{ 191 SDL_LoadVIDPIDListFromHint(hint, &SDL_allowed_controllers); 192} 193 194static int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value); 195static int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state); 196 197/* 198 * If there is an existing add event in the queue, it needs to be modified 199 * to have the right value for which, because the number of controllers in 200 * the system is now one less. 201 */ 202static void UpdateEventsForDeviceRemoval() 203{ 204 int i, num_events; 205 SDL_Event *events; 206 207 num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED); 208 if (num_events <= 0) { 209 return; 210 } 211 212 events = SDL_stack_alloc(SDL_Event, num_events); 213 if (!events) { 214 return; 215 } 216 217 num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED); 218 for (i = 0; i < num_events; ++i) { 219 --events[i].cdevice.which; 220 } 221 SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0); 222 223 SDL_stack_free(events); 224} 225 226static SDL_bool HasSameOutput(SDL_ExtendedGameControllerBind *a, SDL_ExtendedGameControllerBind *b) 227{ 228 if (a->outputType != b->outputType) { 229 return SDL_FALSE; 230 } 231 232 if (a->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 233 return (a->output.axis.axis == b->output.axis.axis); 234 } else { 235 return (a->output.button == b->output.button); 236 } 237} 238 239static void ResetOutput(SDL_GameController *gamecontroller, SDL_ExtendedGameControllerBind *bind) 240{ 241 if (bind->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 242 SDL_PrivateGameControllerAxis(gamecontroller, bind->output.axis.axis, 0); 243 } else { 244 SDL_PrivateGameControllerButton(gamecontroller, bind->output.button, SDL_RELEASED); 245 } 246} 247 248static void HandleJoystickAxis(SDL_GameController *gamecontroller, int axis, int value) 249{ 250 int i; 251 SDL_ExtendedGameControllerBind *last_match = gamecontroller->last_match_axis[axis]; 252 SDL_ExtendedGameControllerBind *match = NULL; 253 254 for (i = 0; i < gamecontroller->num_bindings; ++i) { 255 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 256 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS && 257 axis == binding->input.axis.axis) { 258 if (binding->input.axis.axis_min < binding->input.axis.axis_max) { 259 if (value >= binding->input.axis.axis_min && 260 value <= binding->input.axis.axis_max) { 261 match = binding; 262 break; 263 } 264 } else { 265 if (value >= binding->input.axis.axis_max && 266 value <= binding->input.axis.axis_min) { 267 match = binding; 268 break; 269 } 270 } 271 } 272 } 273 274 if (last_match && (!match || !HasSameOutput(last_match, match))) { 275 /* Clear the last input that this axis generated */ 276 ResetOutput(gamecontroller, last_match); 277 } 278 279 if (match) { 280 if (match->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 281 if (match->input.axis.axis_min != match->output.axis.axis_min || match->input.axis.axis_max != match->output.axis.axis_max) { 282 float normalized_value = (float)(value - match->input.axis.axis_min) / (match->input.axis.axis_max - match->input.axis.axis_min); 283 value = match->output.axis.axis_min + (int)(normalized_value * (match->output.axis.axis_max - match->output.axis.axis_min)); 284 } 285 SDL_PrivateGameControllerAxis(gamecontroller, match->output.axis.axis, (Sint16)value); 286 } else { 287 Uint8 state; 288 int threshold = match->input.axis.axis_min + (match->input.axis.axis_max - match->input.axis.axis_min) / 2; 289 if (match->input.axis.axis_max < match->input.axis.axis_min) { 290 state = (value <= threshold) ? SDL_PRESSED : SDL_RELEASED; 291 } else { 292 state = (value >= threshold) ? SDL_PRESSED : SDL_RELEASED; 293 } 294 SDL_PrivateGameControllerButton(gamecontroller, match->output.button, state); 295 } 296 } 297 gamecontroller->last_match_axis[axis] = match; 298} 299 300static void HandleJoystickButton(SDL_GameController *gamecontroller, int button, Uint8 state) 301{ 302 int i; 303 304 for (i = 0; i < gamecontroller->num_bindings; ++i) { 305 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 306 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON && 307 button == binding->input.button) { 308 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 309 int value = state ? binding->output.axis.axis_max : binding->output.axis.axis_min; 310 SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)value); 311 } else { 312 SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, state); 313 } 314 break; 315 } 316 } 317} 318 319static void HandleJoystickHat(SDL_GameController *gamecontroller, int hat, Uint8 value) 320{ 321 int i; 322 Uint8 last_mask = gamecontroller->last_hat_mask[hat]; 323 Uint8 changed_mask = (last_mask ^ value); 324 325 for (i = 0; i < gamecontroller->num_bindings; ++i) { 326 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 327 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT && hat == binding->input.hat.hat) { 328 if ((changed_mask & binding->input.hat.hat_mask) != 0) { 329 if (value & binding->input.hat.hat_mask) { 330 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 331 SDL_PrivateGameControllerAxis(gamecontroller, binding->output.axis.axis, (Sint16)binding->output.axis.axis_max); 332 } else { 333 SDL_PrivateGameControllerButton(gamecontroller, binding->output.button, SDL_PRESSED); 334 } 335 } else { 336 ResetOutput(gamecontroller, binding); 337 } 338 } 339 } 340 } 341 gamecontroller->last_hat_mask[hat] = value; 342} 343 344/* 345 * Event filter to fire controller events from joystick ones 346 */ 347static int SDLCALL SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event) 348{ 349 switch(event->type) { 350 case SDL_JOYAXISMOTION: 351 { 352 SDL_GameController *controllerlist = SDL_gamecontrollers; 353 while (controllerlist) { 354 if (controllerlist->joystick->instance_id == event->jaxis.which) { 355 HandleJoystickAxis(controllerlist, event->jaxis.axis, event->jaxis.value); 356 break; 357 } 358 controllerlist = controllerlist->next; 359 } 360 } 361 break; 362 case SDL_JOYBUTTONDOWN: 363 case SDL_JOYBUTTONUP: 364 { 365 SDL_GameController *controllerlist = SDL_gamecontrollers; 366 while (controllerlist) { 367 if (controllerlist->joystick->instance_id == event->jbutton.which) { 368 HandleJoystickButton(controllerlist, event->jbutton.button, event->jbutton.state); 369 break; 370 } 371 controllerlist = controllerlist->next; 372 } 373 } 374 break; 375 case SDL_JOYHATMOTION: 376 { 377 SDL_GameController *controllerlist = SDL_gamecontrollers; 378 while (controllerlist) { 379 if (controllerlist->joystick->instance_id == event->jhat.which) { 380 HandleJoystickHat(controllerlist, event->jhat.hat, event->jhat.value); 381 break; 382 } 383 controllerlist = controllerlist->next; 384 } 385 } 386 break; 387 case SDL_JOYDEVICEADDED: 388 { 389 if (SDL_IsGameController(event->jdevice.which)) { 390 SDL_Event deviceevent; 391 deviceevent.type = SDL_CONTROLLERDEVICEADDED; 392 deviceevent.cdevice.which = event->jdevice.which; 393 SDL_PushEvent(&deviceevent); 394 } 395 } 396 break; 397 case SDL_JOYDEVICEREMOVED: 398 { 399 SDL_GameController *controllerlist = SDL_gamecontrollers; 400 while (controllerlist) { 401 if (controllerlist->joystick->instance_id == event->jdevice.which) { 402 SDL_Event deviceevent; 403 404 deviceevent.type = SDL_CONTROLLERDEVICEREMOVED; 405 deviceevent.cdevice.which = event->jdevice.which; 406 SDL_PushEvent(&deviceevent); 407 408 UpdateEventsForDeviceRemoval(); 409 break; 410 } 411 controllerlist = controllerlist->next; 412 } 413 } 414 break; 415 default: 416 break; 417 } 418 419 return 1; 420} 421 422/* 423 * Helper function to scan the mappings database for a controller with the specified GUID 424 */ 425static ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid) 426{ 427 ControllerMapping_t *pSupportedController = s_pSupportedControllers; 428 while (pSupportedController) { 429 if (SDL_memcmp(guid, &pSupportedController->guid, sizeof(*guid)) == 0) { 430 return pSupportedController; 431 } 432 pSupportedController = pSupportedController->next; 433 } 434 if (guid->data[14] == 'h') { 435 /* This is a HIDAPI device */ 436 return s_pHIDAPIMapping; 437 } 438#if SDL_JOYSTICK_XINPUT 439 if (guid->data[14] == 'x') { 440 /* This is an XInput device */ 441 return s_pXInputMapping; 442 } 443#endif 444 return NULL; 445} 446 447static const char* map_StringForControllerAxis[] = { 448 "leftx", 449 "lefty", 450 "rightx", 451 "righty", 452 "lefttrigger", 453 "righttrigger", 454 NULL 455}; 456 457/* 458 * convert a string to its enum equivalent 459 */ 460SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *pchString) 461{ 462 int entry; 463 464 if (pchString && (*pchString == '+' || *pchString == '-')) { 465 ++pchString; 466 } 467 468 if (!pchString || !pchString[0]) { 469 return SDL_CONTROLLER_AXIS_INVALID; 470 } 471 472 for (entry = 0; map_StringForControllerAxis[entry]; ++entry) { 473 if (!SDL_strcasecmp(pchString, map_StringForControllerAxis[entry])) 474 return (SDL_GameControllerAxis) entry; 475 } 476 return SDL_CONTROLLER_AXIS_INVALID; 477} 478 479/* 480 * convert an enum to its string equivalent 481 */ 482const char* SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis) 483{ 484 if (axis > SDL_CONTROLLER_AXIS_INVALID && axis < SDL_CONTROLLER_AXIS_MAX) { 485 return map_StringForControllerAxis[axis]; 486 } 487 return NULL; 488} 489 490static const char* map_StringForControllerButton[] = { 491 "a", 492 "b", 493 "x", 494 "y", 495 "back", 496 "guide", 497 "start", 498 "leftstick", 499 "rightstick", 500 "leftshoulder", 501 "rightshoulder", 502 "dpup", 503 "dpdown", 504 "dpleft", 505 "dpright", 506 NULL 507}; 508 509/* 510 * convert a string to its enum equivalent 511 */ 512SDL_GameControllerButton SDL_GameControllerGetButtonFromString(const char *pchString) 513{ 514 int entry; 515 if (!pchString || !pchString[0]) 516 return SDL_CONTROLLER_BUTTON_INVALID; 517 518 for (entry = 0; map_StringForControllerButton[entry]; ++entry) { 519 if (SDL_strcasecmp(pchString, map_StringForControllerButton[entry]) == 0) 520 return (SDL_GameControllerButton) entry; 521 } 522 return SDL_CONTROLLER_BUTTON_INVALID; 523} 524 525/* 526 * convert an enum to its string equivalent 527 */ 528const char* SDL_GameControllerGetStringForButton(SDL_GameControllerButton axis) 529{ 530 if (axis > SDL_CONTROLLER_BUTTON_INVALID && axis < SDL_CONTROLLER_BUTTON_MAX) { 531 return map_StringForControllerButton[axis]; 532 } 533 return NULL; 534} 535 536/* 537 * given a controller button name and a joystick name update our mapping structure with it 538 */ 539static void SDL_PrivateGameControllerParseElement(SDL_GameController *gamecontroller, const char *szGameButton, const char *szJoystickButton) 540{ 541 SDL_ExtendedGameControllerBind bind; 542 SDL_GameControllerButton button; 543 SDL_GameControllerAxis axis; 544 SDL_bool invert_input = SDL_FALSE; 545 char half_axis_input = 0; 546 char half_axis_output = 0; 547 548 if (*szGameButton == '+' || *szGameButton == '-') { 549 half_axis_output = *szGameButton++; 550 } 551 552 axis = SDL_GameControllerGetAxisFromString(szGameButton); 553 button = SDL_GameControllerGetButtonFromString(szGameButton); 554 if (axis != SDL_CONTROLLER_AXIS_INVALID) { 555 bind.outputType = SDL_CONTROLLER_BINDTYPE_AXIS; 556 bind.output.axis.axis = axis; 557 if (axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) { 558 bind.output.axis.axis_min = 0; 559 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX; 560 } else { 561 if (half_axis_output == '+') { 562 bind.output.axis.axis_min = 0; 563 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX; 564 } else if (half_axis_output == '-') { 565 bind.output.axis.axis_min = 0; 566 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MIN; 567 } else { 568 bind.output.axis.axis_min = SDL_JOYSTICK_AXIS_MIN; 569 bind.output.axis.axis_max = SDL_JOYSTICK_AXIS_MAX; 570 } 571 } 572 } else if (button != SDL_CONTROLLER_BUTTON_INVALID) { 573 bind.outputType = SDL_CONTROLLER_BINDTYPE_BUTTON; 574 bind.output.button = button; 575 } else { 576 SDL_SetError("Unexpected controller element %s", szGameButton); 577 return; 578 } 579 580 if (*szJoystickButton == '+' || *szJoystickButton == '-') { 581 half_axis_input = *szJoystickButton++; 582 } 583 if (szJoystickButton[SDL_strlen(szJoystickButton) - 1] == '~') { 584 invert_input = SDL_TRUE; 585 } 586 587 if (szJoystickButton[0] == 'a' && SDL_isdigit(szJoystickButton[1])) { 588 bind.inputType = SDL_CONTROLLER_BINDTYPE_AXIS; 589 bind.input.axis.axis = SDL_atoi(&szJoystickButton[1]); 590 if (half_axis_input == '+') { 591 bind.input.axis.axis_min = 0; 592 bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX; 593 } else if (half_axis_input == '-') { 594 bind.input.axis.axis_min = 0; 595 bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MIN; 596 } else { 597 bind.input.axis.axis_min = SDL_JOYSTICK_AXIS_MIN; 598 bind.input.axis.axis_max = SDL_JOYSTICK_AXIS_MAX; 599 } 600 if (invert_input) { 601 int tmp = bind.input.axis.axis_min; 602 bind.input.axis.axis_min = bind.input.axis.axis_max; 603 bind.input.axis.axis_max = tmp; 604 } 605 } else if (szJoystickButton[0] == 'b' && SDL_isdigit(szJoystickButton[1])) { 606 bind.inputType = SDL_CONTROLLER_BINDTYPE_BUTTON; 607 bind.input.button = SDL_atoi(&szJoystickButton[1]); 608 } else if (szJoystickButton[0] == 'h' && SDL_isdigit(szJoystickButton[1]) && 609 szJoystickButton[2] == '.' && SDL_isdigit(szJoystickButton[3])) { 610 int hat = SDL_atoi(&szJoystickButton[1]); 611 int mask = SDL_atoi(&szJoystickButton[3]); 612 bind.inputType = SDL_CONTROLLER_BINDTYPE_HAT; 613 bind.input.hat.hat = hat; 614 bind.input.hat.hat_mask = mask; 615 } else { 616 SDL_SetError("Unexpected joystick element: %s", szJoystickButton); 617 return; 618 } 619 620 ++gamecontroller->num_bindings; 621 gamecontroller->bindings = (SDL_ExtendedGameControllerBind *)SDL_realloc(gamecontroller->bindings, gamecontroller->num_bindings * sizeof(*gamecontroller->bindings)); 622 if (!gamecontroller->bindings) { 623 gamecontroller->num_bindings = 0; 624 SDL_OutOfMemory(); 625 return; 626 } 627 gamecontroller->bindings[gamecontroller->num_bindings - 1] = bind; 628} 629 630 631/* 632 * given a controller mapping string update our mapping object 633 */ 634static void 635SDL_PrivateGameControllerParseControllerConfigString(SDL_GameController *gamecontroller, const char *pchString) 636{ 637 char szGameButton[20]; 638 char szJoystickButton[20]; 639 SDL_bool bGameButton = SDL_TRUE; 640 int i = 0; 641 const char *pchPos = pchString; 642 643 SDL_zero(szGameButton); 644 SDL_zero(szJoystickButton); 645 646 while (pchPos && *pchPos) { 647 if (*pchPos == ':') { 648 i = 0; 649 bGameButton = SDL_FALSE; 650 } else if (*pchPos == ' ') { 651 652 } else if (*pchPos == ',') { 653 i = 0; 654 bGameButton = SDL_TRUE; 655 SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton); 656 SDL_zero(szGameButton); 657 SDL_zero(szJoystickButton); 658 659 } else if (bGameButton) { 660 if (i >= sizeof(szGameButton)) { 661 SDL_SetError("Button name too large: %s", szGameButton); 662 return; 663 } 664 szGameButton[i] = *pchPos; 665 i++; 666 } else { 667 if (i >= sizeof(szJoystickButton)) { 668 SDL_SetError("Joystick button name too large: %s", szJoystickButton); 669 return; 670 } 671 szJoystickButton[i] = *pchPos; 672 i++; 673 } 674 pchPos++; 675 } 676 677 SDL_PrivateGameControllerParseElement(gamecontroller, szGameButton, szJoystickButton); 678 679} 680 681/* 682 * Make a new button mapping struct 683 */ 684static void SDL_PrivateLoadButtonMapping(SDL_GameController *gamecontroller, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping) 685{ 686 int i; 687 688 gamecontroller->guid = guid; 689 gamecontroller->name = pchName; 690 gamecontroller->num_bindings = 0; 691 SDL_memset(gamecontroller->last_match_axis, 0, gamecontroller->joystick->naxes * sizeof(*gamecontroller->last_match_axis)); 692 693 SDL_PrivateGameControllerParseControllerConfigString(gamecontroller, pchMapping); 694 695 /* Set the zero point for triggers */ 696 for (i = 0; i < gamecontroller->num_bindings; ++i) { 697 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 698 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS && 699 binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && 700 (binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || 701 binding->output.axis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) { 702 if (binding->input.axis.axis < gamecontroller->joystick->naxes) { 703 gamecontroller->joystick->axes[binding->input.axis.axis].value = 704 gamecontroller->joystick->axes[binding->input.axis.axis].zero = (Sint16)binding->input.axis.axis_min; 705 } 706 } 707 } 708} 709 710 711/* 712 * grab the guid string from a mapping string 713 */ 714static char *SDL_PrivateGetControllerGUIDFromMappingString(const char *pMapping) 715{ 716 const char *pFirstComma = SDL_strchr(pMapping, ','); 717 if (pFirstComma) { 718 char *pchGUID = SDL_malloc(pFirstComma - pMapping + 1); 719 if (!pchGUID) { 720 SDL_OutOfMemory(); 721 return NULL; 722 } 723 SDL_memcpy(pchGUID, pMapping, pFirstComma - pMapping); 724 pchGUID[pFirstComma - pMapping] = '\0'; 725 726 /* Convert old style GUIDs to the new style in 2.0.5 */ 727#if __WIN32__ 728 if (SDL_strlen(pchGUID) == 32 && 729 SDL_memcmp(&pchGUID[20], "504944564944", 12) == 0) { 730 SDL_memcpy(&pchGUID[20], "000000000000", 12); 731 SDL_memcpy(&pchGUID[16], &pchGUID[4], 4); 732 SDL_memcpy(&pchGUID[8], &pchGUID[0], 4); 733 SDL_memcpy(&pchGUID[0], "03000000", 8); 734 } 735#elif __MACOSX__ 736 if (SDL_strlen(pchGUID) == 32 && 737 SDL_memcmp(&pchGUID[4], "000000000000", 12) == 0 && 738 SDL_memcmp(&pchGUID[20], "000000000000", 12) == 0) { 739 SDL_memcpy(&pchGUID[20], "000000000000", 12); 740 SDL_memcpy(&pchGUID[8], &pchGUID[0], 4); 741 SDL_memcpy(&pchGUID[0], "03000000", 8); 742 } 743#endif 744 return pchGUID; 745 } 746 return NULL; 747} 748 749 750/* 751 * grab the name string from a mapping string 752 */ 753static char *SDL_PrivateGetControllerNameFromMappingString(const char *pMapping) 754{ 755 const char *pFirstComma, *pSecondComma; 756 char *pchName; 757 758 pFirstComma = SDL_strchr(pMapping, ','); 759 if (!pFirstComma) 760 return NULL; 761 762 pSecondComma = SDL_strchr(pFirstComma + 1, ','); 763 if (!pSecondComma) 764 return NULL; 765 766 pchName = SDL_malloc(pSecondComma - pFirstComma); 767 if (!pchName) { 768 SDL_OutOfMemory(); 769 return NULL; 770 } 771 SDL_memcpy(pchName, pFirstComma + 1, pSecondComma - pFirstComma); 772 pchName[pSecondComma - pFirstComma - 1] = 0; 773 return pchName; 774} 775 776 777/* 778 * grab the button mapping string from a mapping string 779 */ 780static char *SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping) 781{ 782 const char *pFirstComma, *pSecondComma; 783 784 pFirstComma = SDL_strchr(pMapping, ','); 785 if (!pFirstComma) 786 return NULL; 787 788 pSecondComma = SDL_strchr(pFirstComma + 1, ','); 789 if (!pSecondComma) 790 return NULL; 791 792 return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */ 793} 794 795/* 796 * Helper function to refresh a mapping 797 */ 798static void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping) 799{ 800 SDL_GameController *gamecontrollerlist = SDL_gamecontrollers; 801 while (gamecontrollerlist) { 802 if (!SDL_memcmp(&gamecontrollerlist->guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid))) { 803 SDL_Event event; 804 event.type = SDL_CONTROLLERDEVICEREMAPPED; 805 event.cdevice.which = gamecontrollerlist->joystick->instance_id; 806 SDL_PushEvent(&event); 807 808 /* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */ 809 SDL_PrivateLoadButtonMapping(gamecontrollerlist, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping); 810 } 811 812 gamecontrollerlist = gamecontrollerlist->next; 813 } 814} 815 816/* 817 * Helper function to add a mapping for a guid 818 */ 819static ControllerMapping_t * 820SDL_PrivateAddMappingForGUID(SDL_JoystickGUID jGUID, const char *mappingString, SDL_bool *existing, SDL_ControllerMappingPriority priority) 821{ 822 char *pchName; 823 char *pchMapping; 824 ControllerMapping_t *pControllerMapping; 825 826 pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString); 827 if (!pchName) { 828 SDL_SetError("Couldn't parse name from %s", mappingString); 829 return NULL; 830 } 831 832 pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString); 833 if (!pchMapping) { 834 SDL_free(pchName); 835 SDL_SetError("Couldn't parse %s", mappingString); 836 return NULL; 837 } 838 839 pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID); 840 if (pControllerMapping) { 841 /* Only overwrite the mapping if the priority is the same or higher. */ 842 if (pControllerMapping->priority <= priority) { 843 /* Update existing mapping */ 844 SDL_free(pControllerMapping->name); 845 pControllerMapping->name = pchName; 846 SDL_free(pControllerMapping->mapping); 847 pControllerMapping->mapping = pchMapping; 848 pControllerMapping->priority = priority; 849 /* refresh open controllers */ 850 SDL_PrivateGameControllerRefreshMapping(pControllerMapping); 851 } else { 852 SDL_free(pchName); 853 SDL_free(pchMapping); 854 } 855 *existing = SDL_TRUE; 856 } else { 857 pControllerMapping = SDL_malloc(sizeof(*pControllerMapping)); 858 if (!pControllerMapping) { 859 SDL_free(pchName); 860 SDL_free(pchMapping); 861 SDL_OutOfMemory(); 862 return NULL; 863 } 864 pControllerMapping->guid = jGUID; 865 pControllerMapping->name = pchName; 866 pControllerMapping->mapping = pchMapping; 867 pControllerMapping->next = NULL; 868 pControllerMapping->priority = priority; 869 870 if (s_pSupportedControllers) { 871 /* Add the mapping to the end of the list */ 872 ControllerMapping_t *pCurrMapping, *pPrevMapping; 873 874 for ( pPrevMapping = s_pSupportedControllers, pCurrMapping = pPrevMapping->next; 875 pCurrMapping; 876 pPrevMapping = pCurrMapping, pCurrMapping = pCurrMapping->next ) { 877 continue; 878 } 879 pPrevMapping->next = pControllerMapping; 880 } else { 881 s_pSupportedControllers = pControllerMapping; 882 } 883 *existing = SDL_FALSE; 884 } 885 return pControllerMapping; 886} 887 888#ifdef __ANDROID__ 889/* 890 * Helper function to guess at a mapping based on the elements reported for this controller 891 */ 892static ControllerMapping_t *SDL_CreateMappingForAndroidController(const char *name, SDL_JoystickGUID guid) 893{ 894 SDL_bool existing; 895 char name_string[128]; 896 char mapping_string[1024]; 897 int button_mask; 898 int axis_mask; 899 900 button_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-4])); 901 axis_mask = SDL_SwapLE16(*(Uint16*)(&guid.data[sizeof(guid.data)-2])); 902 if (!button_mask && !axis_mask) { 903 /* Accelerometer, shouldn't have a game controller mapping */ 904 return NULL; 905 } 906 907 /* Remove any commas in the name */ 908 SDL_strlcpy(name_string, name, sizeof(name_string)); 909 { 910 char *spot; 911 for (spot = name_string; *spot; ++spot) { 912 if (*spot == ',') { 913 *spot = ' '; 914 } 915 } 916 } 917 SDL_snprintf(mapping_string, sizeof(mapping_string), "none,%s,", name_string); 918 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_A)) { 919 SDL_strlcat(mapping_string, "a:b0,", sizeof(mapping_string)); 920 } 921 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_B)) { 922 SDL_strlcat(mapping_string, "b:b1,", sizeof(mapping_string)); 923 } else if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) { 924 /* Use the back button as "B" for easy UI navigation with TV remotes */ 925 SDL_strlcat(mapping_string, "b:b4,", sizeof(mapping_string)); 926 button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_BACK); 927 } 928 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_X)) { 929 SDL_strlcat(mapping_string, "x:b2,", sizeof(mapping_string)); 930 } 931 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_Y)) { 932 SDL_strlcat(mapping_string, "y:b3,", sizeof(mapping_string)); 933 } 934 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_BACK)) { 935 SDL_strlcat(mapping_string, "back:b4,", sizeof(mapping_string)); 936 } 937#if 0 /* The guide button generally isn't functional (or acts as a home button) on most Android controllers */ 938 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_GUIDE)) { 939 SDL_strlcat(mapping_string, "guide:b5,", sizeof(mapping_string)); 940#if 0 /* Actually this will be done in Steam */ 941 } else if (button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) { 942 /* The guide button doesn't exist, use the start button instead, 943 so you can do Steam guide button chords and open the Steam overlay. 944 */ 945 SDL_strlcat(mapping_string, "guide:b6,", sizeof(mapping_string)); 946 button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_START); 947#endif 948 } 949#endif 950 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_START)) { 951 SDL_strlcat(mapping_string, "start:b6,", sizeof(mapping_string)); 952 } 953 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSTICK)) { 954 SDL_strlcat(mapping_string, "leftstick:b7,", sizeof(mapping_string)); 955 } 956 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSTICK)) { 957 SDL_strlcat(mapping_string, "rightstick:b8,", sizeof(mapping_string)); 958 } 959 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) { 960 SDL_strlcat(mapping_string, "leftshoulder:b9,", sizeof(mapping_string)); 961 } 962 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) { 963 SDL_strlcat(mapping_string, "rightshoulder:b10,", sizeof(mapping_string)); 964 } 965 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_UP)) { 966 SDL_strlcat(mapping_string, "dpup:b11,", sizeof(mapping_string)); 967 } 968 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN)) { 969 SDL_strlcat(mapping_string, "dpdown:b12,", sizeof(mapping_string)); 970 } 971 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT)) { 972 SDL_strlcat(mapping_string, "dpleft:b13,", sizeof(mapping_string)); 973 } 974 if (button_mask & (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) { 975 SDL_strlcat(mapping_string, "dpright:b14,", sizeof(mapping_string)); 976 } 977 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTX)) { 978 SDL_strlcat(mapping_string, "leftx:a0,", sizeof(mapping_string)); 979 } 980 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_LEFTY)) { 981 SDL_strlcat(mapping_string, "lefty:a1,", sizeof(mapping_string)); 982 } 983 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTX)) { 984 SDL_strlcat(mapping_string, "rightx:a2,", sizeof(mapping_string)); 985 } 986 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_RIGHTY)) { 987 SDL_strlcat(mapping_string, "righty:a3,", sizeof(mapping_string)); 988 } 989 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERLEFT)) { 990 SDL_strlcat(mapping_string, "lefttrigger:a4,", sizeof(mapping_string)); 991 } 992 if (axis_mask & (1 << SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) { 993 SDL_strlcat(mapping_string, "righttrigger:a5,", sizeof(mapping_string)); 994 } 995 return SDL_PrivateAddMappingForGUID(guid, mapping_string, 996 &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); 997} 998#endif /* __ANDROID__ */ 999 1000 1001/* 1002 * Helper function to determine pre-calculated offset to certain joystick mappings 1003 */ 1004static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const char *name, SDL_JoystickGUID guid) 1005{ 1006 ControllerMapping_t *mapping; 1007 1008 mapping = SDL_PrivateGetControllerMappingForGUID(&guid); 1009#ifdef __LINUX__ 1010 if (!mapping && name) { 1011 if (SDL_strstr(name, "Xbox 360 Wireless Receiver")) { 1012 /* The Linux driver xpad.c maps the wireless dpad to buttons */ 1013 SDL_bool existing; 1014 mapping = SDL_PrivateAddMappingForGUID(guid, 1015"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,", 1016 &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); 1017 } 1018 } 1019#endif /* __LINUX__ */ 1020 1021 if (!mapping && name) { 1022 if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box") || SDL_strstr(name, "XBOX")) { 1023 mapping = s_pXInputMapping; 1024 } 1025 } 1026#ifdef __ANDROID__ 1027 if (!mapping) { 1028 mapping = SDL_CreateMappingForAndroidController(name, guid); 1029 } 1030#endif 1031 if (!mapping) { 1032 mapping = s_pDefaultMapping; 1033 } 1034 return mapping; 1035} 1036 1037static ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index) 1038{ 1039 const char *name; 1040 SDL_JoystickGUID guid; 1041 ControllerMapping_t *mapping; 1042 1043 SDL_LockJoysticks(); 1044 1045 if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) { 1046 SDL_SetError("There are %d joysticks available", SDL_NumJoysticks()); 1047 SDL_UnlockJoysticks(); 1048 return (NULL); 1049 } 1050 1051 name = SDL_JoystickNameForIndex(device_index); 1052 guid = SDL_JoystickGetDeviceGUID(device_index); 1053 mapping = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid); 1054 SDL_UnlockJoysticks(); 1055 return mapping; 1056} 1057 1058/* 1059 * Add or update an entry into the Mappings Database 1060 */ 1061int 1062SDL_GameControllerAddMappingsFromRW(SDL_RWops * rw, int freerw) 1063{ 1064 const char *platform = SDL_GetPlatform(); 1065 int controllers = 0; 1066 char *buf, *line, *line_end, *tmp, *comma, line_platform[64]; 1067 size_t db_size, platform_len; 1068 1069 if (rw == NULL) { 1070 return SDL_SetError("Invalid RWops"); 1071 } 1072 db_size = (size_t)SDL_RWsize(rw); 1073 1074 buf = (char *)SDL_malloc(db_size + 1); 1075 if (buf == NULL) { 1076 if (freerw) { 1077 SDL_RWclose(rw); 1078 } 1079 return SDL_SetError("Could not allocate space to read DB into memory"); 1080 } 1081 1082 if (SDL_RWread(rw, buf, db_size, 1) != 1) { 1083 if (freerw) { 1084 SDL_RWclose(rw); 1085 } 1086 SDL_free(buf); 1087 return SDL_SetError("Could not read DB"); 1088 } 1089 1090 if (freerw) { 1091 SDL_RWclose(rw); 1092 } 1093 1094 buf[db_size] = '\0'; 1095 line = buf; 1096 1097 while (line < buf + db_size) { 1098 line_end = SDL_strchr(line, '\n'); 1099 if (line_end != NULL) { 1100 *line_end = '\0'; 1101 } else { 1102 line_end = buf + db_size; 1103 } 1104 1105 /* Extract and verify the platform */ 1106 tmp = SDL_strstr(line, SDL_CONTROLLER_PLATFORM_FIELD); 1107 if (tmp != NULL) { 1108 tmp += SDL_strlen(SDL_CONTROLLER_PLATFORM_FIELD); 1109 comma = SDL_strchr(tmp, ','); 1110 if (comma != NULL) { 1111 platform_len = comma - tmp + 1; 1112 if (platform_len + 1 < SDL_arraysize(line_platform)) { 1113 SDL_strlcpy(line_platform, tmp, platform_len); 1114 if (SDL_strncasecmp(line_platform, platform, platform_len) == 0 && 1115 SDL_GameControllerAddMapping(line) > 0) { 1116 controllers++; 1117 } 1118 } 1119 } 1120 } 1121 1122 line = line_end + 1; 1123 } 1124 1125 SDL_free(buf); 1126 return controllers; 1127} 1128 1129/* 1130 * Add or update an entry into the Mappings Database with a priority 1131 */ 1132static int 1133SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMappingPriority priority) 1134{ 1135 char *pchGUID; 1136 SDL_JoystickGUID jGUID; 1137 SDL_bool is_default_mapping = SDL_FALSE; 1138 SDL_bool is_hidapi_mapping = SDL_FALSE; 1139 SDL_bool is_xinput_mapping = SDL_FALSE; 1140 SDL_bool existing = SDL_FALSE; 1141 ControllerMapping_t *pControllerMapping; 1142 1143 if (!mappingString) { 1144 return SDL_InvalidParamError("mappingString"); 1145 } 1146 1147 pchGUID = SDL_PrivateGetControllerGUIDFromMappingString(mappingString); 1148 if (!pchGUID) { 1149 return SDL_SetError("Couldn't parse GUID from %s", mappingString); 1150 } 1151 if (!SDL_strcasecmp(pchGUID, "default")) { 1152 is_default_mapping = SDL_TRUE; 1153 } else if (!SDL_strcasecmp(pchGUID, "hidapi")) { 1154 is_hidapi_mapping = SDL_TRUE; 1155 } else if (!SDL_strcasecmp(pchGUID, "xinput")) { 1156 is_xinput_mapping = SDL_TRUE; 1157 } 1158 jGUID = SDL_JoystickGetGUIDFromString(pchGUID); 1159 SDL_free(pchGUID); 1160 1161 pControllerMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing, priority); 1162 if (!pControllerMapping) { 1163 return -1; 1164 } 1165 1166 if (existing) { 1167 return 0; 1168 } else { 1169 if (is_default_mapping) { 1170 s_pDefaultMapping = pControllerMapping; 1171 } else if (is_hidapi_mapping) { 1172 s_pHIDAPIMapping = pControllerMapping; 1173 } else if (is_xinput_mapping) { 1174 s_pXInputMapping = pControllerMapping; 1175 } 1176 return 1; 1177 } 1178} 1179 1180/* 1181 * Add or update an entry into the Mappings Database 1182 */ 1183int 1184SDL_GameControllerAddMapping(const char *mappingString) 1185{ 1186 return SDL_PrivateGameControllerAddMapping(mappingString, SDL_CONTROLLER_MAPPING_PRIORITY_API); 1187} 1188 1189/* 1190 * Get the number of mappings installed 1191 */ 1192int 1193SDL_GameControllerNumMappings(void) 1194{ 1195 int num_mappings = 0; 1196 ControllerMapping_t *mapping; 1197 1198 for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) { 1199 if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) { 1200 continue; 1201 } 1202 ++num_mappings; 1203 } 1204 return num_mappings; 1205} 1206 1207/* 1208 * Get the mapping at a particular index. 1209 */ 1210char * 1211SDL_GameControllerMappingForIndex(int mapping_index) 1212{ 1213 ControllerMapping_t *mapping; 1214 1215 for (mapping = s_pSupportedControllers; mapping; mapping = mapping->next) { 1216 if (SDL_memcmp(&mapping->guid, &s_zeroGUID, sizeof(mapping->guid)) == 0) { 1217 continue; 1218 } 1219 if (mapping_index == 0) { 1220 char *pMappingString; 1221 char pchGUID[33]; 1222 size_t needed; 1223 1224 SDL_JoystickGetGUIDString(mapping->guid, pchGUID, sizeof(pchGUID)); 1225 /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */ 1226 needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1; 1227 pMappingString = SDL_malloc(needed); 1228 if (!pMappingString) { 1229 SDL_OutOfMemory(); 1230 return NULL; 1231 } 1232 SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping); 1233 return pMappingString; 1234 } 1235 --mapping_index; 1236 } 1237 return NULL; 1238} 1239 1240/* 1241 * Get the mapping string for this GUID 1242 */ 1243char * 1244SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid) 1245{ 1246 char *pMappingString = NULL; 1247 ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(&guid); 1248 if (mapping) { 1249 char pchGUID[33]; 1250 size_t needed; 1251 SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID)); 1252 /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */ 1253 needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1; 1254 pMappingString = SDL_malloc(needed); 1255 if (!pMappingString) { 1256 SDL_OutOfMemory(); 1257 return NULL; 1258 } 1259 SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping); 1260 } 1261 return pMappingString; 1262} 1263 1264/* 1265 * Get the mapping string for this device 1266 */ 1267char * 1268SDL_GameControllerMapping(SDL_GameController * gamecontroller) 1269{ 1270 if (!gamecontroller) { 1271 return NULL; 1272 } 1273 1274 return SDL_GameControllerMappingForGUID(gamecontroller->guid); 1275} 1276 1277static void 1278SDL_GameControllerLoadHints() 1279{ 1280 const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG); 1281 if (hint && hint[0]) { 1282 size_t nchHints = SDL_strlen(hint); 1283 char *pUserMappings = SDL_malloc(nchHints + 1); 1284 char *pTempMappings = pUserMappings; 1285 SDL_memcpy(pUserMappings, hint, nchHints); 1286 pUserMappings[nchHints] = '\0'; 1287 while (pUserMappings) { 1288 char *pchNewLine = NULL; 1289 1290 pchNewLine = SDL_strchr(pUserMappings, '\n'); 1291 if (pchNewLine) 1292 *pchNewLine = '\0'; 1293 1294 SDL_PrivateGameControllerAddMapping(pUserMappings, SDL_CONTROLLER_MAPPING_PRIORITY_USER); 1295 1296 if (pchNewLine) { 1297 pUserMappings = pchNewLine + 1; 1298 } else { 1299 pUserMappings = NULL; 1300 } 1301 } 1302 SDL_free(pTempMappings); 1303 } 1304} 1305 1306/* 1307 * Fill the given buffer with the expected controller mapping filepath. 1308 * Usually this will just be CONTROLLER_MAPPING_FILE, but for Android, 1309 * we want to get the internal storage path. 1310 */ 1311static SDL_bool SDL_GetControllerMappingFilePath(char *path, size_t size) 1312{ 1313#ifdef CONTROLLER_MAPPING_FILE 1314#define STRING(X) SDL_STRINGIFY_ARG(X) 1315 return SDL_strlcpy(path, STRING(CONTROLLER_MAPPING_FILE), size) < size; 1316#elif defined(__ANDROID__) 1317 return SDL_snprintf(path, size, "%s/controller_map.txt", SDL_AndroidGetInternalStoragePath()) < size; 1318#else 1319 return SDL_FALSE; 1320#endif 1321} 1322 1323/* 1324 * Initialize the game controller system, mostly load our DB of controller config mappings 1325 */ 1326int 1327SDL_GameControllerInitMappings(void) 1328{ 1329 char szControllerMapPath[1024]; 1330 int i = 0; 1331 const char *pMappingString = NULL; 1332 pMappingString = s_ControllerMappings[i]; 1333 while (pMappingString) { 1334 SDL_PrivateGameControllerAddMapping(pMappingString, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); 1335 1336 i++; 1337 pMappingString = s_ControllerMappings[i]; 1338 } 1339 1340 if (SDL_GetControllerMappingFilePath(szControllerMapPath, sizeof(szControllerMapPath))) { 1341 SDL_GameControllerAddMappingsFromFile(szControllerMapPath); 1342 } 1343 1344 /* load in any user supplied config */ 1345 SDL_GameControllerLoadHints(); 1346 1347 SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES, 1348 SDL_GameControllerIgnoreDevicesChanged, NULL); 1349 SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT, 1350 SDL_GameControllerIgnoreDevicesExceptChanged, NULL); 1351 1352 return (0); 1353} 1354 1355int 1356SDL_GameControllerInit(void) 1357{ 1358 int i; 1359 1360 /* watch for joy events and fire controller ones if needed */ 1361 SDL_AddEventWatch(SDL_GameControllerEventWatcher, NULL); 1362 1363 /* Send added events for controllers currently attached */ 1364 for (i = 0; i < SDL_NumJoysticks(); ++i) { 1365 if (SDL_IsGameController(i)) { 1366 SDL_Event deviceevent; 1367 deviceevent.type = SDL_CONTROLLERDEVICEADDED; 1368 deviceevent.cdevice.which = i; 1369 SDL_PushEvent(&deviceevent); 1370 } 1371 } 1372 1373 return (0); 1374} 1375 1376 1377/* 1378 * Get the implementation dependent name of a controller 1379 */ 1380const char * 1381SDL_GameControllerNameForIndex(int device_index) 1382{ 1383 ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index); 1384 if (pSupportedController) { 1385 if (SDL_strcmp(pSupportedController->name, "*") == 0) { 1386 return SDL_JoystickNameForIndex(device_index); 1387 } else { 1388 return pSupportedController->name; 1389 } 1390 } 1391 return NULL; 1392} 1393 1394 1395/** 1396 * Get the mapping of a game controller. 1397 * This can be called before any controllers are opened. 1398 * If no mapping can be found, this function returns NULL. 1399 */ 1400char * 1401SDL_GameControllerMappingForDeviceIndex(int joystick_index) 1402{ 1403 char *pMappingString = NULL; 1404 ControllerMapping_t *mapping; 1405 1406 SDL_LockJoysticks(); 1407 mapping = SDL_PrivateGetControllerMapping(joystick_index); 1408 if (mapping) { 1409 SDL_JoystickGUID guid; 1410 char pchGUID[33]; 1411 size_t needed; 1412 guid = SDL_JoystickGetDeviceGUID(joystick_index); 1413 SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID)); 1414 /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */ 1415 needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1; 1416 pMappingString = SDL_malloc(needed); 1417 if (!pMappingString) { 1418 SDL_OutOfMemory(); 1419 SDL_UnlockJoysticks(); 1420 return NULL; 1421 } 1422 SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping); 1423 } 1424 SDL_UnlockJoysticks(); 1425 return pMappingString; 1426} 1427 1428 1429/* 1430 * Return 1 if the joystick with this name and GUID is a supported controller 1431 */ 1432SDL_bool 1433SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid) 1434{ 1435 ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid); 1436 if (pSupportedController) { 1437 return SDL_TRUE; 1438 } 1439 return SDL_FALSE; 1440} 1441 1442/* 1443 * Return 1 if the joystick at this device index is a supported controller 1444 */ 1445SDL_bool 1446SDL_IsGameController(int device_index) 1447{ 1448 ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index); 1449 if (pSupportedController) { 1450 return SDL_TRUE; 1451 } 1452 return SDL_FALSE; 1453} 1454 1455/* 1456 * Return 1 if the game controller should be ignored by SDL 1457 */ 1458SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid) 1459{ 1460 int i; 1461 Uint16 vendor; 1462 Uint16 product; 1463 Uint32 vidpid; 1464 1465 if (SDL_allowed_controllers.num_entries == 0 && 1466 SDL_ignored_controllers.num_entries == 0) { 1467 return SDL_FALSE; 1468 } 1469 1470 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL); 1471 1472 if (SDL_GetHintBoolean("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD", SDL_FALSE)) { 1473 /* 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 */ 1474 SDL_bool bSteamVirtualGamepad = SDL_FALSE; 1475#if defined(__LINUX__) 1476 bSteamVirtualGamepad = (vendor == 0x28DE && product == 0x11FF); 1477#elif defined(__MACOSX__) 1478 bSteamVirtualGamepad = (SDL_strncmp(name, "GamePad-", 8) == 0); 1479#elif defined(__WIN32__) 1480 /* We can't tell on Windows, but Steam will block others in input hooks */ 1481 bSteamVirtualGamepad = SDL_TRUE; 1482#endif 1483 if (bSteamVirtualGamepad) { 1484 return SDL_FALSE; 1485 } 1486 } 1487 1488 vidpid = MAKE_VIDPID(vendor, product); 1489 1490 if (SDL_allowed_controllers.num_entries > 0) { 1491 for (i = 0; i < SDL_allowed_controllers.num_entries; ++i) { 1492 if (vidpid == SDL_allowed_controllers.entries[i]) { 1493 return SDL_FALSE; 1494 } 1495 } 1496 return SDL_TRUE; 1497 } else { 1498 for (i = 0; i < SDL_ignored_controllers.num_entries; ++i) { 1499 if (vidpid == SDL_ignored_controllers.entries[i]) { 1500 return SDL_TRUE; 1501 } 1502 } 1503 return SDL_FALSE; 1504 } 1505} 1506 1507/* 1508 * Open a controller for use - the index passed as an argument refers to 1509 * the N'th controller on the system. This index is the value which will 1510 * identify this controller in future controller events. 1511 * 1512 * This function returns a controller identifier, or NULL if an error occurred. 1513 */ 1514SDL_GameController * 1515SDL_GameControllerOpen(int device_index) 1516{ 1517 SDL_JoystickID instance_id; 1518 SDL_GameController *gamecontroller; 1519 SDL_GameController *gamecontrollerlist; 1520 ControllerMapping_t *pSupportedController = NULL; 1521 1522 SDL_LockJoysticks(); 1523 1524 gamecontrollerlist = SDL_gamecontrollers; 1525 /* If the controller is already open, return it */ 1526 instance_id = SDL_JoystickGetDeviceInstanceID(device_index); 1527 while (gamecontrollerlist) { 1528 if (instance_id == gamecontrollerlist->joystick->instance_id) { 1529 gamecontroller = gamecontrollerlist; 1530 ++gamecontroller->ref_count; 1531 SDL_UnlockJoysticks(); 1532 return (gamecontroller); 1533 } 1534 gamecontrollerlist = gamecontrollerlist->next; 1535 } 1536 1537 /* Find a controller mapping */ 1538 pSupportedController = SDL_PrivateGetControllerMapping(device_index); 1539 if (!pSupportedController) { 1540 SDL_SetError("Couldn't find mapping for device (%d)", device_index); 1541 SDL_UnlockJoysticks(); 1542 return NULL; 1543 } 1544 1545 /* Create and initialize the controller */ 1546 gamecontroller = (SDL_GameController *) SDL_calloc(1, sizeof(*gamecontroller)); 1547 if (gamecontroller == NULL) { 1548 SDL_OutOfMemory(); 1549 SDL_UnlockJoysticks(); 1550 return NULL; 1551 } 1552 1553 gamecontroller->joystick = SDL_JoystickOpen(device_index); 1554 if (!gamecontroller->joystick) { 1555 SDL_free(gamecontroller); 1556 SDL_UnlockJoysticks(); 1557 return NULL; 1558 } 1559 1560 if (gamecontroller->joystick->naxes) { 1561 gamecontroller->last_match_axis = (SDL_ExtendedGameControllerBind **)SDL_calloc(gamecontroller->joystick->naxes, sizeof(*gamecontroller->last_match_axis)); 1562 if (!gamecontroller->last_match_axis) { 1563 SDL_OutOfMemory(); 1564 SDL_JoystickClose(gamecontroller->joystick); 1565 SDL_free(gamecontroller); 1566 SDL_UnlockJoysticks(); 1567 return NULL; 1568 } 1569 } 1570 if (gamecontroller->joystick->nhats) { 1571 gamecontroller->last_hat_mask = (Uint8 *)SDL_calloc(gamecontroller->joystick->nhats, sizeof(*gamecontroller->last_hat_mask)); 1572 if (!gamecontroller->last_hat_mask) { 1573 SDL_OutOfMemory(); 1574 SDL_JoystickClose(gamecontroller->joystick); 1575 SDL_free(gamecontroller->last_match_axis); 1576 SDL_free(gamecontroller); 1577 SDL_UnlockJoysticks(); 1578 return NULL; 1579 } 1580 } 1581 1582 SDL_PrivateLoadButtonMapping(gamecontroller, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping); 1583 1584 /* Add the controller to list */ 1585 ++gamecontroller->ref_count; 1586 /* Link the controller in the list */ 1587 gamecontroller->next = SDL_gamecontrollers; 1588 SDL_gamecontrollers = gamecontroller; 1589 1590 SDL_UnlockJoysticks(); 1591 1592 return (gamecontroller); 1593} 1594 1595/* 1596 * Manually pump for controller updates. 1597 */ 1598void 1599SDL_GameControllerUpdate(void) 1600{ 1601 /* Just for API completeness; the joystick API does all the work. */ 1602 SDL_JoystickUpdate(); 1603} 1604 1605/* 1606 * Get the current state of an axis control on a controller 1607 */ 1608Sint16 1609SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis) 1610{ 1611 int i; 1612 1613 if (!gamecontroller) 1614 return 0; 1615 1616 for (i = 0; i < gamecontroller->num_bindings; ++i) { 1617 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 1618 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) { 1619 int value = 0; 1620 SDL_bool valid_input_range; 1621 SDL_bool valid_output_range; 1622 1623 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 1624 value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis); 1625 if (binding->input.axis.axis_min < binding->input.axis.axis_max) { 1626 valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max); 1627 } else { 1628 valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min); 1629 } 1630 if (valid_input_range) { 1631 if (binding->input.axis.axis_min != binding->output.axis.axis_min || binding->input.axis.axis_max != binding->output.axis.axis_max) { 1632 float normalized_value = (float)(value - binding->input.axis.axis_min) / (binding->input.axis.axis_max - binding->input.axis.axis_min); 1633 value = binding->output.axis.axis_min + (int)(normalized_value * (binding->output.axis.axis_max - binding->output.axis.axis_min)); 1634 } 1635 } 1636 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) { 1637 value = SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button); 1638 if (value == SDL_PRESSED) { 1639 value = binding->output.axis.axis_max; 1640 } 1641 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) { 1642 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat); 1643 if (hat_mask & binding->input.hat.hat_mask) { 1644 value = binding->output.axis.axis_max; 1645 } 1646 } 1647 1648 if (binding->output.axis.axis_min < binding->output.axis.axis_max) { 1649 valid_output_range = (value >= binding->output.axis.axis_min && value <= binding->output.axis.axis_max); 1650 } else { 1651 valid_output_range = (value >= binding->output.axis.axis_max && value <= binding->output.axis.axis_min); 1652 } 1653 /* If the value is zero, there might be another binding that makes it non-zero */ 1654 if (value != 0 && valid_output_range) { 1655 return (Sint16)value; 1656 } 1657 } 1658 } 1659 return 0; 1660} 1661 1662/* 1663 * Get the current state of a button on a controller 1664 */ 1665Uint8 1666SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button) 1667{ 1668 int i; 1669 1670 if (!gamecontroller) 1671 return 0; 1672 1673 for (i = 0; i < gamecontroller->num_bindings; ++i) { 1674 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 1675 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) { 1676 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 1677 SDL_bool valid_input_range; 1678 1679 int value = SDL_JoystickGetAxis(gamecontroller->joystick, binding->input.axis.axis); 1680 int threshold = binding->input.axis.axis_min + (binding->input.axis.axis_max - binding->input.axis.axis_min) / 2; 1681 if (binding->input.axis.axis_min < binding->input.axis.axis_max) { 1682 valid_input_range = (value >= binding->input.axis.axis_min && value <= binding->input.axis.axis_max); 1683 if (valid_input_range) { 1684 return (value >= threshold) ? SDL_PRESSED : SDL_RELEASED; 1685 } 1686 } else { 1687 valid_input_range = (value >= binding->input.axis.axis_max && value <= binding->input.axis.axis_min); 1688 if (valid_input_range) { 1689 return (value <= threshold) ? SDL_PRESSED : SDL_RELEASED; 1690 } 1691 } 1692 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) { 1693 return SDL_JoystickGetButton(gamecontroller->joystick, binding->input.button); 1694 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) { 1695 int hat_mask = SDL_JoystickGetHat(gamecontroller->joystick, binding->input.hat.hat); 1696 return (hat_mask & binding->input.hat.hat_mask) ? SDL_PRESSED : SDL_RELEASED; 1697 } 1698 } 1699 } 1700 return SDL_RELEASED; 1701} 1702 1703const char * 1704SDL_GameControllerName(SDL_GameController * gamecontroller) 1705{ 1706 if (!gamecontroller) 1707 return NULL; 1708 1709 if (SDL_strcmp(gamecontroller->name, "*") == 0) { 1710 return SDL_JoystickName(SDL_GameControllerGetJoystick(gamecontroller)); 1711 } else { 1712 return gamecontroller->name; 1713 } 1714} 1715 1716Uint16 1717SDL_GameControllerGetVendor(SDL_GameController * gamecontroller) 1718{ 1719 return SDL_JoystickGetVendor(SDL_GameControllerGetJoystick(gamecontroller)); 1720} 1721 1722Uint16 1723SDL_GameControllerGetProduct(SDL_GameController * gamecontroller) 1724{ 1725 return SDL_JoystickGetProduct(SDL_GameControllerGetJoystick(gamecontroller)); 1726} 1727 1728Uint16 1729SDL_GameControllerGetProductVersion(SDL_GameController * gamecontroller) 1730{ 1731 return SDL_JoystickGetProductVersion(SDL_GameControllerGetJoystick(gamecontroller)); 1732} 1733 1734/* 1735 * Return if the controller in question is currently attached to the system, 1736 * \return 0 if not plugged in, 1 if still present. 1737 */ 1738SDL_bool 1739SDL_GameControllerGetAttached(SDL_GameController * gamecontroller) 1740{ 1741 if (!gamecontroller) 1742 return SDL_FALSE; 1743 1744 return SDL_JoystickGetAttached(gamecontroller->joystick); 1745} 1746 1747/* 1748 * Get the joystick for this controller 1749 */ 1750SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller) 1751{ 1752 if (!gamecontroller) 1753 return NULL; 1754 1755 return gamecontroller->joystick; 1756} 1757 1758 1759/* 1760 * Find the SDL_GameController that owns this instance id 1761 */ 1762SDL_GameController * 1763SDL_GameControllerFromInstanceID(SDL_JoystickID joyid) 1764{ 1765 SDL_GameController *gamecontroller; 1766 1767 SDL_LockJoysticks(); 1768 gamecontroller = SDL_gamecontrollers; 1769 while (gamecontroller) { 1770 if (gamecontroller->joystick->instance_id == joyid) { 1771 SDL_UnlockJoysticks(); 1772 return gamecontroller; 1773 } 1774 gamecontroller = gamecontroller->next; 1775 } 1776 SDL_UnlockJoysticks(); 1777 return NULL; 1778} 1779 1780 1781/* 1782 * Get the SDL joystick layer binding for this controller axis mapping 1783 */ 1784SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis) 1785{ 1786 int i; 1787 SDL_GameControllerButtonBind bind; 1788 SDL_zero(bind); 1789 1790 if (!gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID) 1791 return bind; 1792 1793 for (i = 0; i < gamecontroller->num_bindings; ++i) { 1794 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 1795 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_AXIS && binding->output.axis.axis == axis) { 1796 bind.bindType = binding->inputType; 1797 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 1798 /* FIXME: There might be multiple axes bound now that we have axis ranges... */ 1799 bind.value.axis = binding->input.axis.axis; 1800 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) { 1801 bind.value.button = binding->input.button; 1802 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) { 1803 bind.value.hat.hat = binding->input.hat.hat; 1804 bind.value.hat.hat_mask = binding->input.hat.hat_mask; 1805 } 1806 break; 1807 } 1808 } 1809 return bind; 1810} 1811 1812 1813/* 1814 * Get the SDL joystick layer binding for this controller button mapping 1815 */ 1816SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button) 1817{ 1818 int i; 1819 SDL_GameControllerButtonBind bind; 1820 SDL_zero(bind); 1821 1822 if (!gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID) 1823 return bind; 1824 1825 for (i = 0; i < gamecontroller->num_bindings; ++i) { 1826 SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i]; 1827 if (binding->outputType == SDL_CONTROLLER_BINDTYPE_BUTTON && binding->output.button == button) { 1828 bind.bindType = binding->inputType; 1829 if (binding->inputType == SDL_CONTROLLER_BINDTYPE_AXIS) { 1830 bind.value.axis = binding->input.axis.axis; 1831 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_BUTTON) { 1832 bind.value.button = binding->input.button; 1833 } else if (binding->inputType == SDL_CONTROLLER_BINDTYPE_HAT) { 1834 bind.value.hat.hat = binding->input.hat.hat; 1835 bind.value.hat.hat_mask = binding->input.hat.hat_mask; 1836 } 1837 break; 1838 } 1839 } 1840 return bind; 1841} 1842 1843 1844int 1845SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) 1846{ 1847 return SDL_JoystickRumble(SDL_GameControllerGetJoystick(gamecontroller), low_frequency_rumble, high_frequency_rumble, duration_ms); 1848} 1849 1850void 1851SDL_GameControllerClose(SDL_GameController * gamecontroller) 1852{ 1853 SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev; 1854 1855 if (!gamecontroller) 1856 return; 1857 1858 SDL_LockJoysticks(); 1859 1860 /* First decrement ref count */ 1861 if (--gamecontroller->ref_count > 0) { 1862 SDL_UnlockJoysticks(); 1863 return; 1864 } 1865 1866 SDL_JoystickClose(gamecontroller->joystick); 1867 1868 gamecontrollerlist = SDL_gamecontrollers; 1869 gamecontrollerlistprev = NULL; 1870 while (gamecontrollerlist) { 1871 if (gamecontroller == gamecontrollerlist) { 1872 if (gamecontrollerlistprev) { 1873 /* unlink this entry */ 1874 gamecontrollerlistprev->next = gamecontrollerlist->next; 1875 } else { 1876 SDL_gamecontrollers = gamecontroller->next; 1877 } 1878 break; 1879 } 1880 gamecontrollerlistprev = gamecontrollerlist; 1881 gamecontrollerlist = gamecontrollerlist->next; 1882 } 1883 1884 SDL_free(gamecontroller->bindings); 1885 SDL_free(gamecontroller->last_match_axis); 1886 SDL_free(gamecontroller->last_hat_mask); 1887 SDL_free(gamecontroller); 1888 1889 SDL_UnlockJoysticks(); 1890} 1891 1892 1893/* 1894 * Quit the controller subsystem 1895 */ 1896void 1897SDL_GameControllerQuit(void) 1898{ 1899 SDL_LockJoysticks(); 1900 while (SDL_gamecontrollers) { 1901 SDL_gamecontrollers->ref_count = 1; 1902 SDL_GameControllerClose(SDL_gamecontrollers); 1903 } 1904 SDL_UnlockJoysticks(); 1905} 1906 1907void 1908SDL_GameControllerQuitMappings(void) 1909{ 1910 ControllerMapping_t *pControllerMap; 1911 1912 while (s_pSupportedControllers) { 1913 pControllerMap = s_pSupportedControllers; 1914 s_pSupportedControllers = s_pSupportedControllers->next; 1915 SDL_free(pControllerMap->name); 1916 SDL_free(pControllerMap->mapping); 1917 SDL_free(pControllerMap); 1918 } 1919 1920 SDL_DelEventWatch(SDL_GameControllerEventWatcher, NULL); 1921 1922 SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES, 1923 SDL_GameControllerIgnoreDevicesChanged, NULL); 1924 SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT, 1925 SDL_GameControllerIgnoreDevicesExceptChanged, NULL); 1926 1927 if (SDL_allowed_controllers.entries) { 1928 SDL_free(SDL_allowed_controllers.entries); 1929 SDL_zero(SDL_allowed_controllers); 1930 } 1931 if (SDL_ignored_controllers.entries) { 1932 SDL_free(SDL_ignored_controllers.entries); 1933 SDL_zero(SDL_ignored_controllers); 1934 } 1935} 1936 1937/* 1938 * Event filter to transform joystick events into appropriate game controller ones 1939 */ 1940static int 1941SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value) 1942{ 1943 int posted; 1944 1945 /* translate the event, if desired */ 1946 posted = 0; 1947#if !SDL_EVENTS_DISABLED 1948 if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) { 1949 SDL_Event event; 1950 event.type = SDL_CONTROLLERAXISMOTION; 1951 event.caxis.which = gamecontroller->joystick->instance_id; 1952 event.caxis.axis = axis; 1953 event.caxis.value = value; 1954 posted = SDL_PushEvent(&event) == 1; 1955 } 1956#endif /* !SDL_EVENTS_DISABLED */ 1957 return (posted); 1958} 1959 1960 1961/* 1962 * Event filter to transform joystick events into appropriate game controller ones 1963 */ 1964static int 1965SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state) 1966{ 1967 int posted; 1968#if !SDL_EVENTS_DISABLED 1969 SDL_Event event; 1970 1971 if (button == SDL_CONTROLLER_BUTTON_INVALID) 1972 return (0); 1973 1974 switch (state) { 1975 case SDL_PRESSED: 1976 event.type = SDL_CONTROLLERBUTTONDOWN; 1977 break; 1978 case SDL_RELEASED: 1979 event.type = SDL_CONTROLLERBUTTONUP; 1980 break; 1981 default: 1982 /* Invalid state -- bail */ 1983 return (0); 1984 } 1985#endif /* !SDL_EVENTS_DISABLED */ 1986 1987 if (button == SDL_CONTROLLER_BUTTON_GUIDE) { 1988 Uint32 now = SDL_GetTicks(); 1989 if (state == SDL_PRESSED) { 1990 gamecontroller->guide_button_down = now; 1991 1992 if (gamecontroller->joystick->delayed_guide_button) { 1993 /* Skip duplicate press */ 1994 return (0); 1995 } 1996 } else { 1997 if (!SDL_TICKS_PASSED(now, gamecontroller->guide_button_down+SDL_MINIMUM_GUIDE_BUTTON_DELAY_MS) && !gamecontroller->joystick->force_recentering) { 1998 gamecontroller->joystick->delayed_guide_button = SDL_TRUE; 1999 return (0); 2000 } 2001 gamecontroller->joystick->delayed_guide_button = SDL_FALSE; 2002 } 2003 } 2004 2005 /* translate the event, if desired */ 2006 posted = 0; 2007#if !SDL_EVENTS_DISABLED 2008 if (SDL_GetEventState(event.type) == SDL_ENABLE) { 2009 event.cbutton.which = gamecontroller->joystick->instance_id; 2010 event.cbutton.button = button; 2011 event.cbutton.state = state; 2012 posted = SDL_PushEvent(&event) == 1; 2013 } 2014#endif /* !SDL_EVENTS_DISABLED */ 2015 return (posted); 2016} 2017 2018/* 2019 * Turn off controller events 2020 */ 2021int 2022SDL_GameControllerEventState(int state) 2023{ 2024#if SDL_EVENTS_DISABLED 2025 return SDL_IGNORE; 2026#else 2027 const Uint32 event_list[] = { 2028 SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP, 2029 SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED, 2030 }; 2031 unsigned int i; 2032 2033 switch (state) { 2034 case SDL_QUERY: 2035 state = SDL_IGNORE; 2036 for (i = 0; i < SDL_arraysize(event_list); ++i) { 2037 state = SDL_EventState(event_list[i], SDL_QUERY); 2038 if (state == SDL_ENABLE) { 2039 break; 2040 } 2041 } 2042 break; 2043 default: 2044 for (i = 0; i < SDL_arraysize(event_list); ++i) { 2045 SDL_EventState(event_list[i], state); 2046 } 2047 break; 2048 } 2049 return (state); 2050#endif /* SDL_EVENTS_DISABLED */ 2051} 2052 2053void 2054SDL_GameControllerHandleDelayedGuideButton(SDL_Joystick *joystick) 2055{ 2056 SDL_GameController *controllerlist = SDL_gamecontrollers; 2057 while (controllerlist) { 2058 if (controllerlist->joystick == joystick) { 2059 SDL_PrivateGameControllerButton(controllerlist, SDL_CONTROLLER_BUTTON_GUIDE, SDL_RELEASED); 2060 break; 2061 } 2062 controllerlist = controllerlist->next; 2063 } 2064} 2065 2066/* vi: set ts=4 sw=4 expandtab: */ 2067[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.