SDL_gamecontroller.c (39290B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 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_assert.h" 27#include "SDL_sysjoystick.h" 28#include "SDL_hints.h" 29#include "SDL_gamecontrollerdb.h" 30 31#if !SDL_EVENTS_DISABLED 32#include "../events/SDL_events_c.h" 33#endif 34#define ABS(_x) ((_x) < 0 ? -(_x) : (_x)) 35 36#define SDL_CONTROLLER_PLATFORM_FIELD "platform:" 37 38/* a list of currently opened game controllers */ 39static SDL_GameController *SDL_gamecontrollers = NULL; 40 41/* keep track of the hat and mask value that transforms this hat movement into a button/axis press */ 42struct _SDL_HatMapping 43{ 44 int hat; 45 Uint8 mask; 46}; 47 48#define k_nMaxReverseEntries 20 49 50/** 51 * We are encoding the "HAT" as 0xhm. where h == hat ID and m == mask 52 * MAX 4 hats supported 53 */ 54#define k_nMaxHatEntries 0x3f + 1 55 56/* our in memory mapping db between joystick objects and controller mappings */ 57struct _SDL_ControllerMapping 58{ 59 SDL_JoystickGUID guid; 60 const char *name; 61 62 /* mapping of axis/button id to controller version */ 63 int axes[SDL_CONTROLLER_AXIS_MAX]; 64 int buttonasaxis[SDL_CONTROLLER_AXIS_MAX]; 65 66 int buttons[SDL_CONTROLLER_BUTTON_MAX]; 67 int axesasbutton[SDL_CONTROLLER_BUTTON_MAX]; 68 struct _SDL_HatMapping hatasbutton[SDL_CONTROLLER_BUTTON_MAX]; 69 70 /* reverse mapping, joystick indices to buttons */ 71 SDL_GameControllerAxis raxes[k_nMaxReverseEntries]; 72 SDL_GameControllerAxis rbuttonasaxis[k_nMaxReverseEntries]; 73 74 SDL_GameControllerButton rbuttons[k_nMaxReverseEntries]; 75 SDL_GameControllerButton raxesasbutton[k_nMaxReverseEntries]; 76 SDL_GameControllerButton rhatasbutton[k_nMaxHatEntries]; 77 78}; 79 80 81/* our hard coded list of mapping support */ 82typedef struct _ControllerMapping_t 83{ 84 SDL_JoystickGUID guid; 85 char *name; 86 char *mapping; 87 struct _ControllerMapping_t *next; 88} ControllerMapping_t; 89 90static ControllerMapping_t *s_pSupportedControllers = NULL; 91static ControllerMapping_t *s_pXInputMapping = NULL; 92 93/* The SDL game controller structure */ 94struct _SDL_GameController 95{ 96 SDL_Joystick *joystick; /* underlying joystick device */ 97 int ref_count; 98 Uint8 hatState[4]; /* the current hat state for this controller */ 99 struct _SDL_ControllerMapping mapping; /* the mapping object for this controller */ 100 struct _SDL_GameController *next; /* pointer to next game controller we have allocated */ 101}; 102 103 104int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value); 105int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state); 106 107/* 108 * Event filter to fire controller events from joystick ones 109 */ 110int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event) 111{ 112 switch(event->type) { 113 case SDL_JOYAXISMOTION: 114 { 115 SDL_GameController *controllerlist; 116 117 if (event->jaxis.axis >= k_nMaxReverseEntries) break; 118 119 controllerlist = SDL_gamecontrollers; 120 while (controllerlist) { 121 if (controllerlist->joystick->instance_id == event->jaxis.which) { 122 if (controllerlist->mapping.raxes[event->jaxis.axis] >= 0) /* simple axis to axis, send it through */ { 123 SDL_GameControllerAxis axis = controllerlist->mapping.raxes[event->jaxis.axis]; 124 Sint16 value = event->jaxis.value; 125 switch (axis) { 126 case SDL_CONTROLLER_AXIS_TRIGGERLEFT: 127 case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: 128 /* Shift it to be 0 - 32767. */ 129 value = value / 2 + 16384; 130 default: 131 break; 132 } 133 SDL_PrivateGameControllerAxis(controllerlist, axis, value); 134 } else if (controllerlist->mapping.raxesasbutton[event->jaxis.axis] >= 0) { /* simulate an axis as a button */ 135 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.raxesasbutton[event->jaxis.axis], ABS(event->jaxis.value) > 32768/2 ? SDL_PRESSED : SDL_RELEASED); 136 } 137 break; 138 } 139 controllerlist = controllerlist->next; 140 } 141 } 142 break; 143 case SDL_JOYBUTTONDOWN: 144 case SDL_JOYBUTTONUP: 145 { 146 SDL_GameController *controllerlist; 147 148 if (event->jbutton.button >= k_nMaxReverseEntries) break; 149 150 controllerlist = SDL_gamecontrollers; 151 while (controllerlist) { 152 if (controllerlist->joystick->instance_id == event->jbutton.which) { 153 if (controllerlist->mapping.rbuttons[event->jbutton.button] >= 0) { /* simple button as button */ 154 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rbuttons[event->jbutton.button], event->jbutton.state); 155 } else if (controllerlist->mapping.rbuttonasaxis[event->jbutton.button] >= 0) { /* an button pretending to be an axis */ 156 SDL_PrivateGameControllerAxis(controllerlist, controllerlist->mapping.rbuttonasaxis[event->jbutton.button], event->jbutton.state > 0 ? 32767 : 0); 157 } 158 break; 159 } 160 controllerlist = controllerlist->next; 161 } 162 } 163 break; 164 case SDL_JOYHATMOTION: 165 { 166 SDL_GameController *controllerlist; 167 168 if (event->jhat.hat >= 4) break; 169 170 controllerlist = SDL_gamecontrollers; 171 while (controllerlist) { 172 if (controllerlist->joystick->instance_id == event->jhat.which) { 173 Uint8 bSame = controllerlist->hatState[event->jhat.hat] & event->jhat.value; 174 /* Get list of removed bits (button release) */ 175 Uint8 bChanged = controllerlist->hatState[event->jhat.hat] ^ bSame; 176 /* the hat idx in the high nibble */ 177 int bHighHat = event->jhat.hat << 4; 178 179 if (bChanged & SDL_HAT_DOWN) 180 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_RELEASED); 181 if (bChanged & SDL_HAT_UP) 182 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_RELEASED); 183 if (bChanged & SDL_HAT_LEFT) 184 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_RELEASED); 185 if (bChanged & SDL_HAT_RIGHT) 186 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_RELEASED); 187 188 /* Get list of added bits (button press) */ 189 bChanged = event->jhat.value ^ bSame; 190 191 if (bChanged & SDL_HAT_DOWN) 192 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_PRESSED); 193 if (bChanged & SDL_HAT_UP) 194 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_PRESSED); 195 if (bChanged & SDL_HAT_LEFT) 196 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_PRESSED); 197 if (bChanged & SDL_HAT_RIGHT) 198 SDL_PrivateGameControllerButton(controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_PRESSED); 199 200 /* update our state cache */ 201 controllerlist->hatState[event->jhat.hat] = event->jhat.value; 202 203 break; 204 } 205 controllerlist = controllerlist->next; 206 } 207 } 208 break; 209 case SDL_JOYDEVICEADDED: 210 { 211 if (SDL_IsGameController(event->jdevice.which)) { 212 SDL_Event deviceevent; 213 deviceevent.type = SDL_CONTROLLERDEVICEADDED; 214 deviceevent.cdevice.which = event->jdevice.which; 215 SDL_PushEvent(&deviceevent); 216 } 217 } 218 break; 219 case SDL_JOYDEVICEREMOVED: 220 { 221 SDL_GameController *controllerlist = SDL_gamecontrollers; 222 while (controllerlist) { 223 if (controllerlist->joystick->instance_id == event->jdevice.which) { 224 SDL_Event deviceevent; 225 deviceevent.type = SDL_CONTROLLERDEVICEREMOVED; 226 deviceevent.cdevice.which = event->jdevice.which; 227 SDL_PushEvent(&deviceevent); 228 break; 229 } 230 controllerlist = controllerlist->next; 231 } 232 } 233 break; 234 default: 235 break; 236 } 237 238 return 1; 239} 240 241/* 242 * Helper function to scan the mappings database for a controller with the specified GUID 243 */ 244ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid) 245{ 246 ControllerMapping_t *pSupportedController = s_pSupportedControllers; 247 while (pSupportedController) { 248 if (SDL_memcmp(guid, &pSupportedController->guid, sizeof(*guid)) == 0) { 249 return pSupportedController; 250 } 251 pSupportedController = pSupportedController->next; 252 } 253 return NULL; 254} 255 256/* 257 * Helper function to determine pre-calculated offset to certain joystick mappings 258 */ 259ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index) 260{ 261#if SDL_JOYSTICK_XINPUT 262 if (SDL_SYS_IsXInputGamepad_DeviceIndex(device_index) && s_pXInputMapping) { 263 return s_pXInputMapping; 264 } 265 else 266#endif /* SDL_JOYSTICK_XINPUT */ 267 { 268 SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index); 269 return SDL_PrivateGetControllerMappingForGUID(&jGUID); 270 } 271} 272 273static const char* map_StringForControllerAxis[] = { 274 "leftx", 275 "lefty", 276 "rightx", 277 "righty", 278 "lefttrigger", 279 "righttrigger", 280 NULL 281}; 282 283/* 284 * convert a string to its enum equivalent 285 */ 286SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *pchString) 287{ 288 int entry; 289 if (!pchString || !pchString[0]) 290 return SDL_CONTROLLER_AXIS_INVALID; 291 292 for (entry = 0; map_StringForControllerAxis[entry]; ++entry) { 293 if (!SDL_strcasecmp(pchString, map_StringForControllerAxis[entry])) 294 return entry; 295 } 296 return SDL_CONTROLLER_AXIS_INVALID; 297} 298 299/* 300 * convert an enum to its string equivalent 301 */ 302const char* SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis) 303{ 304 if (axis > SDL_CONTROLLER_AXIS_INVALID && axis < SDL_CONTROLLER_AXIS_MAX) { 305 return map_StringForControllerAxis[axis]; 306 } 307 return NULL; 308} 309 310static const char* map_StringForControllerButton[] = { 311 "a", 312 "b", 313 "x", 314 "y", 315 "back", 316 "guide", 317 "start", 318 "leftstick", 319 "rightstick", 320 "leftshoulder", 321 "rightshoulder", 322 "dpup", 323 "dpdown", 324 "dpleft", 325 "dpright", 326 NULL 327}; 328 329/* 330 * convert a string to its enum equivalent 331 */ 332SDL_GameControllerButton SDL_GameControllerGetButtonFromString(const char *pchString) 333{ 334 int entry; 335 if (!pchString || !pchString[0]) 336 return SDL_CONTROLLER_BUTTON_INVALID; 337 338 for (entry = 0; map_StringForControllerButton[entry]; ++entry) { 339 if (SDL_strcasecmp(pchString, map_StringForControllerButton[entry]) == 0) 340 return entry; 341 } 342 return SDL_CONTROLLER_BUTTON_INVALID; 343} 344 345/* 346 * convert an enum to its string equivalent 347 */ 348const char* SDL_GameControllerGetStringForButton(SDL_GameControllerButton axis) 349{ 350 if (axis > SDL_CONTROLLER_BUTTON_INVALID && axis < SDL_CONTROLLER_BUTTON_MAX) { 351 return map_StringForControllerButton[axis]; 352 } 353 return NULL; 354} 355 356/* 357 * given a controller button name and a joystick name update our mapping structure with it 358 */ 359void SDL_PrivateGameControllerParseButton(const char *szGameButton, const char *szJoystickButton, struct _SDL_ControllerMapping *pMapping) 360{ 361 int iSDLButton = 0; 362 SDL_GameControllerButton button; 363 SDL_GameControllerAxis axis; 364 button = SDL_GameControllerGetButtonFromString(szGameButton); 365 axis = SDL_GameControllerGetAxisFromString(szGameButton); 366 iSDLButton = SDL_atoi(&szJoystickButton[1]); 367 368 if (szJoystickButton[0] == 'a') { 369 if (iSDLButton >= k_nMaxReverseEntries) { 370 SDL_SetError("Axis index too large: %d", iSDLButton); 371 return; 372 } 373 if (axis != SDL_CONTROLLER_AXIS_INVALID) { 374 pMapping->axes[ axis ] = iSDLButton; 375 pMapping->raxes[ iSDLButton ] = axis; 376 } else if (button != SDL_CONTROLLER_BUTTON_INVALID) { 377 pMapping->axesasbutton[ button ] = iSDLButton; 378 pMapping->raxesasbutton[ iSDLButton ] = button; 379 } else { 380 SDL_assert(!"How did we get here?"); 381 } 382 383 } else if (szJoystickButton[0] == 'b') { 384 if (iSDLButton >= k_nMaxReverseEntries) { 385 SDL_SetError("Button index too large: %d", iSDLButton); 386 return; 387 } 388 if (button != SDL_CONTROLLER_BUTTON_INVALID) { 389 pMapping->buttons[ button ] = iSDLButton; 390 pMapping->rbuttons[ iSDLButton ] = button; 391 } else if (axis != SDL_CONTROLLER_AXIS_INVALID) { 392 pMapping->buttonasaxis[ axis ] = iSDLButton; 393 pMapping->rbuttonasaxis[ iSDLButton ] = axis; 394 } else { 395 SDL_assert(!"How did we get here?"); 396 } 397 } else if (szJoystickButton[0] == 'h') { 398 int hat = SDL_atoi(&szJoystickButton[1]); 399 int mask = SDL_atoi(&szJoystickButton[3]); 400 if (hat >= 4) { 401 SDL_SetError("Hat index too large: %d", iSDLButton); 402 } 403 404 if (button != SDL_CONTROLLER_BUTTON_INVALID) { 405 int ridx; 406 pMapping->hatasbutton[ button ].hat = hat; 407 pMapping->hatasbutton[ button ].mask = mask; 408 ridx = (hat << 4) | mask; 409 pMapping->rhatasbutton[ ridx ] = button; 410 } else if (axis != SDL_CONTROLLER_AXIS_INVALID) { 411 SDL_assert(!"Support hat as axis"); 412 } else { 413 SDL_assert(!"How did we get here?"); 414 } 415 } 416} 417 418 419/* 420 * given a controller mapping string update our mapping object 421 */ 422static void 423SDL_PrivateGameControllerParseControllerConfigString(struct _SDL_ControllerMapping *pMapping, const char *pchString) 424{ 425 char szGameButton[20]; 426 char szJoystickButton[20]; 427 SDL_bool bGameButton = SDL_TRUE; 428 int i = 0; 429 const char *pchPos = pchString; 430 431 SDL_memset(szGameButton, 0x0, sizeof(szGameButton)); 432 SDL_memset(szJoystickButton, 0x0, sizeof(szJoystickButton)); 433 434 while (pchPos && *pchPos) { 435 if (*pchPos == ':') { 436 i = 0; 437 bGameButton = SDL_FALSE; 438 } else if (*pchPos == ' ') { 439 440 } else if (*pchPos == ',') { 441 i = 0; 442 bGameButton = SDL_TRUE; 443 SDL_PrivateGameControllerParseButton(szGameButton, szJoystickButton, pMapping); 444 SDL_memset(szGameButton, 0x0, sizeof(szGameButton)); 445 SDL_memset(szJoystickButton, 0x0, sizeof(szJoystickButton)); 446 447 } else if (bGameButton) { 448 if (i >= sizeof(szGameButton)) { 449 SDL_SetError("Button name too large: %s", szGameButton); 450 return; 451 } 452 szGameButton[i] = *pchPos; 453 i++; 454 } else { 455 if (i >= sizeof(szJoystickButton)) { 456 SDL_SetError("Joystick button name too large: %s", szJoystickButton); 457 return; 458 } 459 szJoystickButton[i] = *pchPos; 460 i++; 461 } 462 pchPos++; 463 } 464 465 SDL_PrivateGameControllerParseButton(szGameButton, szJoystickButton, pMapping); 466 467} 468 469/* 470 * Make a new button mapping struct 471 */ 472void SDL_PrivateLoadButtonMapping(struct _SDL_ControllerMapping *pMapping, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping) 473{ 474 int j; 475 476 pMapping->guid = guid; 477 pMapping->name = pchName; 478 479 /* set all the button mappings to non defaults */ 480 for (j = 0; j < SDL_CONTROLLER_AXIS_MAX; j++) { 481 pMapping->axes[j] = -1; 482 pMapping->buttonasaxis[j] = -1; 483 } 484 for (j = 0; j < SDL_CONTROLLER_BUTTON_MAX; j++) { 485 pMapping->buttons[j] = -1; 486 pMapping->axesasbutton[j] = -1; 487 pMapping->hatasbutton[j].hat = -1; 488 } 489 490 for (j = 0; j < k_nMaxReverseEntries; j++) { 491 pMapping->raxes[j] = SDL_CONTROLLER_AXIS_INVALID; 492 pMapping->rbuttonasaxis[j] = SDL_CONTROLLER_AXIS_INVALID; 493 pMapping->rbuttons[j] = SDL_CONTROLLER_BUTTON_INVALID; 494 pMapping->raxesasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID; 495 } 496 497 for (j = 0; j < k_nMaxHatEntries; j++) { 498 pMapping->rhatasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID; 499 } 500 501 SDL_PrivateGameControllerParseControllerConfigString(pMapping, pchMapping); 502} 503 504 505/* 506 * grab the guid string from a mapping string 507 */ 508char *SDL_PrivateGetControllerGUIDFromMappingString(const char *pMapping) 509{ 510 const char *pFirstComma = SDL_strchr(pMapping, ','); 511 if (pFirstComma) { 512 char *pchGUID = SDL_malloc(pFirstComma - pMapping + 1); 513 if (!pchGUID) { 514 SDL_OutOfMemory(); 515 return NULL; 516 } 517 SDL_memcpy(pchGUID, pMapping, pFirstComma - pMapping); 518 pchGUID[ pFirstComma - pMapping ] = 0; 519 return pchGUID; 520 } 521 return NULL; 522} 523 524 525/* 526 * grab the name string from a mapping string 527 */ 528char *SDL_PrivateGetControllerNameFromMappingString(const char *pMapping) 529{ 530 const char *pFirstComma, *pSecondComma; 531 char *pchName; 532 533 pFirstComma = SDL_strchr(pMapping, ','); 534 if (!pFirstComma) 535 return NULL; 536 537 pSecondComma = SDL_strchr(pFirstComma + 1, ','); 538 if (!pSecondComma) 539 return NULL; 540 541 pchName = SDL_malloc(pSecondComma - pFirstComma); 542 if (!pchName) { 543 SDL_OutOfMemory(); 544 return NULL; 545 } 546 SDL_memcpy(pchName, pFirstComma + 1, pSecondComma - pFirstComma); 547 pchName[ pSecondComma - pFirstComma - 1 ] = 0; 548 return pchName; 549} 550 551 552/* 553 * grab the button mapping string from a mapping string 554 */ 555char *SDL_PrivateGetControllerMappingFromMappingString(const char *pMapping) 556{ 557 const char *pFirstComma, *pSecondComma; 558 559 pFirstComma = SDL_strchr(pMapping, ','); 560 if (!pFirstComma) 561 return NULL; 562 563 pSecondComma = SDL_strchr(pFirstComma + 1, ','); 564 if (!pSecondComma) 565 return NULL; 566 567 return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */ 568} 569 570void SDL_PrivateGameControllerRefreshMapping(ControllerMapping_t *pControllerMapping) 571{ 572 SDL_GameController *gamecontrollerlist = SDL_gamecontrollers; 573 while (gamecontrollerlist) { 574 if (!SDL_memcmp(&gamecontrollerlist->mapping.guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid))) { 575 SDL_Event event; 576 event.type = SDL_CONTROLLERDEVICEREMAPPED; 577 event.cdevice.which = gamecontrollerlist->joystick->instance_id; 578 SDL_PushEvent(&event); 579 580 /* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */ 581 SDL_PrivateLoadButtonMapping(&gamecontrollerlist->mapping, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping); 582 } 583 584 gamecontrollerlist = gamecontrollerlist->next; 585 } 586} 587 588/* 589 * Add or update an entry into the Mappings Database 590 */ 591int 592SDL_GameControllerAddMappingsFromRW(SDL_RWops * rw, int freerw) 593{ 594 const char *platform = SDL_GetPlatform(); 595 int controllers = 0; 596 char *buf, *line, *line_end, *tmp, *comma, line_platform[64]; 597 size_t db_size, platform_len; 598 599 if (rw == NULL) { 600 return SDL_SetError("Invalid RWops"); 601 } 602 db_size = (size_t)SDL_RWsize(rw); 603 604 buf = (char *)SDL_malloc(db_size + 1); 605 if (buf == NULL) { 606 if (freerw) { 607 SDL_RWclose(rw); 608 } 609 return SDL_SetError("Could allocate space to not read DB into memory"); 610 } 611 612 if (SDL_RWread(rw, buf, db_size, 1) != 1) { 613 if (freerw) { 614 SDL_RWclose(rw); 615 } 616 SDL_free(buf); 617 return SDL_SetError("Could not read DB"); 618 } 619 620 if (freerw) { 621 SDL_RWclose(rw); 622 } 623 624 buf[db_size] = '\0'; 625 line = buf; 626 627 while (line < buf + db_size) { 628 line_end = SDL_strchr(line, '\n'); 629 if (line_end != NULL) { 630 *line_end = '\0'; 631 } else { 632 line_end = buf + db_size; 633 } 634 635 /* Extract and verify the platform */ 636 tmp = SDL_strstr(line, SDL_CONTROLLER_PLATFORM_FIELD); 637 if (tmp != NULL) { 638 tmp += SDL_strlen(SDL_CONTROLLER_PLATFORM_FIELD); 639 comma = SDL_strchr(tmp, ','); 640 if (comma != NULL) { 641 platform_len = comma - tmp + 1; 642 if (platform_len + 1 < SDL_arraysize(line_platform)) { 643 SDL_strlcpy(line_platform, tmp, platform_len); 644 if (SDL_strncasecmp(line_platform, platform, platform_len) == 0 && 645 SDL_GameControllerAddMapping(line) > 0) { 646 controllers++; 647 } 648 } 649 } 650 } 651 652 line = line_end + 1; 653 } 654 655 SDL_free(buf); 656 return controllers; 657} 658 659/* 660 * Add or update an entry into the Mappings Database 661 */ 662int 663SDL_GameControllerAddMapping(const char *mappingString) 664{ 665 char *pchGUID; 666 char *pchName; 667 char *pchMapping; 668 SDL_JoystickGUID jGUID; 669 ControllerMapping_t *pControllerMapping; 670 SDL_bool is_xinput_mapping = SDL_FALSE; 671 672 pchGUID = SDL_PrivateGetControllerGUIDFromMappingString(mappingString); 673 if (!pchGUID) { 674 return SDL_SetError("Couldn't parse GUID from %s", mappingString); 675 } 676 if (!SDL_strcasecmp(pchGUID, "xinput")) { 677 is_xinput_mapping = SDL_TRUE; 678 } 679 jGUID = SDL_JoystickGetGUIDFromString(pchGUID); 680 SDL_free(pchGUID); 681 682 pchName = SDL_PrivateGetControllerNameFromMappingString(mappingString); 683 if (!pchName) { 684 return SDL_SetError("Couldn't parse name from %s", mappingString); 685 } 686 687 pchMapping = SDL_PrivateGetControllerMappingFromMappingString(mappingString); 688 if (!pchMapping) { 689 SDL_free(pchName); 690 return SDL_SetError("Couldn't parse %s", mappingString); 691 } 692 693 pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID); 694 695 if (pControllerMapping) { 696 /* Update existing mapping */ 697 SDL_free(pControllerMapping->name); 698 pControllerMapping->name = pchName; 699 SDL_free(pControllerMapping->mapping); 700 pControllerMapping->mapping = pchMapping; 701 /* refresh open controllers */ 702 SDL_PrivateGameControllerRefreshMapping(pControllerMapping); 703 return 0; 704 } else { 705 pControllerMapping = SDL_malloc(sizeof(*pControllerMapping)); 706 if (!pControllerMapping) { 707 SDL_free(pchName); 708 SDL_free(pchMapping); 709 return SDL_OutOfMemory(); 710 } 711 if (is_xinput_mapping) { 712 s_pXInputMapping = pControllerMapping; 713 } 714 pControllerMapping->guid = jGUID; 715 pControllerMapping->name = pchName; 716 pControllerMapping->mapping = pchMapping; 717 pControllerMapping->next = s_pSupportedControllers; 718 s_pSupportedControllers = pControllerMapping; 719 return 1; 720 } 721} 722 723/* 724 * Get the mapping string for this GUID 725 */ 726char * 727SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid) 728{ 729 char *pMappingString = NULL; 730 ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(&guid); 731 if (mapping) { 732 char pchGUID[33]; 733 size_t needed; 734 SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID)); 735 /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */ 736 needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1; 737 pMappingString = SDL_malloc(needed); 738 SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping); 739 } 740 return pMappingString; 741} 742 743/* 744 * Get the mapping string for this device 745 */ 746char * 747SDL_GameControllerMapping(SDL_GameController * gamecontroller) 748{ 749 return SDL_GameControllerMappingForGUID(gamecontroller->mapping.guid); 750} 751 752static void 753SDL_GameControllerLoadHints() 754{ 755 const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG); 756 if (hint && hint[0]) { 757 size_t nchHints = SDL_strlen(hint); 758 char *pUserMappings = SDL_malloc(nchHints + 1); 759 char *pTempMappings = pUserMappings; 760 SDL_memcpy(pUserMappings, hint, nchHints); 761 pUserMappings[nchHints] = '\0'; 762 while (pUserMappings) { 763 char *pchNewLine = NULL; 764 765 pchNewLine = SDL_strchr(pUserMappings, '\n'); 766 if (pchNewLine) 767 *pchNewLine = '\0'; 768 769 SDL_GameControllerAddMapping(pUserMappings); 770 771 if (pchNewLine) { 772 pUserMappings = pchNewLine + 1; 773 } else { 774 pUserMappings = NULL; 775 } 776 } 777 SDL_free(pTempMappings); 778 } 779} 780 781/* 782 * Initialize the game controller system, mostly load our DB of controller config mappings 783 */ 784int 785SDL_GameControllerInit(void) 786{ 787 int i = 0; 788 const char *pMappingString = NULL; 789 s_pSupportedControllers = NULL; 790 pMappingString = s_ControllerMappings[i]; 791 while (pMappingString) { 792 SDL_GameControllerAddMapping(pMappingString); 793 794 i++; 795 pMappingString = s_ControllerMappings[i]; 796 } 797 798 /* load in any user supplied config */ 799 SDL_GameControllerLoadHints(); 800 801 /* watch for joy events and fire controller ones if needed */ 802 SDL_AddEventWatch(SDL_GameControllerEventWatcher, NULL); 803 804 /* Send added events for controllers currently attached */ 805 for (i = 0; i < SDL_NumJoysticks(); ++i) { 806 if (SDL_IsGameController(i)) { 807 SDL_Event deviceevent; 808 deviceevent.type = SDL_CONTROLLERDEVICEADDED; 809 deviceevent.cdevice.which = i; 810 SDL_PushEvent(&deviceevent); 811 } 812 } 813 814 return (0); 815} 816 817 818/* 819 * Get the implementation dependent name of a controller 820 */ 821const char * 822SDL_GameControllerNameForIndex(int device_index) 823{ 824 ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index); 825 if (pSupportedController) { 826 return pSupportedController->name; 827 } 828 return NULL; 829} 830 831 832/* 833 * Return 1 if the joystick at this device index is a supported controller 834 */ 835SDL_bool 836SDL_IsGameController(int device_index) 837{ 838 ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index); 839 if (pSupportedController) { 840 return SDL_TRUE; 841 } 842 843 return SDL_FALSE; 844} 845 846/* 847 * Open a controller for use - the index passed as an argument refers to 848 * the N'th controller on the system. This index is the value which will 849 * identify this controller in future controller events. 850 * 851 * This function returns a controller identifier, or NULL if an error occurred. 852 */ 853SDL_GameController * 854SDL_GameControllerOpen(int device_index) 855{ 856 SDL_GameController *gamecontroller; 857 SDL_GameController *gamecontrollerlist; 858 ControllerMapping_t *pSupportedController = NULL; 859 860 if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) { 861 SDL_SetError("There are %d joysticks available", SDL_NumJoysticks()); 862 return (NULL); 863 } 864 865 gamecontrollerlist = SDL_gamecontrollers; 866 /* If the controller is already open, return it */ 867 while (gamecontrollerlist) { 868 if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id) { 869 gamecontroller = gamecontrollerlist; 870 ++gamecontroller->ref_count; 871 return (gamecontroller); 872 } 873 gamecontrollerlist = gamecontrollerlist->next; 874 } 875 876 /* Find a controller mapping */ 877 pSupportedController = SDL_PrivateGetControllerMapping(device_index); 878 if (!pSupportedController) { 879 SDL_SetError("Couldn't find mapping for device (%d)", device_index); 880 return (NULL); 881 } 882 883 /* Create and initialize the joystick */ 884 gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller)); 885 if (gamecontroller == NULL) { 886 SDL_OutOfMemory(); 887 return NULL; 888 } 889 890 SDL_memset(gamecontroller, 0, (sizeof *gamecontroller)); 891 gamecontroller->joystick = SDL_JoystickOpen(device_index); 892 if (!gamecontroller->joystick) { 893 SDL_free(gamecontroller); 894 return NULL; 895 } 896 897 SDL_PrivateLoadButtonMapping(&gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping); 898 899 /* Add joystick to list */ 900 ++gamecontroller->ref_count; 901 /* Link the joystick in the list */ 902 gamecontroller->next = SDL_gamecontrollers; 903 SDL_gamecontrollers = gamecontroller; 904 905 SDL_SYS_JoystickUpdate(gamecontroller->joystick); 906 907 return (gamecontroller); 908} 909 910/* 911 * Manually pump for controller updates. 912 */ 913void 914SDL_GameControllerUpdate(void) 915{ 916 /* Just for API completeness; the joystick API does all the work. */ 917 SDL_JoystickUpdate(); 918} 919 920 921/* 922 * Get the current state of an axis control on a controller 923 */ 924Sint16 925SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis) 926{ 927 if (!gamecontroller) 928 return 0; 929 930 if (gamecontroller->mapping.axes[axis] >= 0) { 931 Sint16 value = (SDL_JoystickGetAxis(gamecontroller->joystick, gamecontroller->mapping.axes[axis])); 932 switch (axis) { 933 case SDL_CONTROLLER_AXIS_TRIGGERLEFT: 934 case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: 935 /* Shift it to be 0 - 32767. */ 936 value = value / 2 + 16384; 937 default: 938 break; 939 } 940 return value; 941 } else if (gamecontroller->mapping.buttonasaxis[axis] >= 0) { 942 Uint8 value; 943 value = SDL_JoystickGetButton(gamecontroller->joystick, gamecontroller->mapping.buttonasaxis[axis]); 944 if (value > 0) 945 return 32767; 946 return 0; 947 } 948 return 0; 949} 950 951 952/* 953 * Get the current state of a button on a controller 954 */ 955Uint8 956SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button) 957{ 958 if (!gamecontroller) 959 return 0; 960 961 if (gamecontroller->mapping.buttons[button] >= 0) { 962 return (SDL_JoystickGetButton(gamecontroller->joystick, gamecontroller->mapping.buttons[button])); 963 } else if (gamecontroller->mapping.axesasbutton[button] >= 0) { 964 Sint16 value; 965 value = SDL_JoystickGetAxis(gamecontroller->joystick, gamecontroller->mapping.axesasbutton[button]); 966 if (ABS(value) > 32768/2) 967 return 1; 968 return 0; 969 } else if (gamecontroller->mapping.hatasbutton[button].hat >= 0) { 970 Uint8 value; 971 value = SDL_JoystickGetHat(gamecontroller->joystick, gamecontroller->mapping.hatasbutton[button].hat); 972 973 if (value & gamecontroller->mapping.hatasbutton[button].mask) 974 return 1; 975 return 0; 976 } 977 978 return 0; 979} 980 981/* 982 * Return if the joystick in question is currently attached to the system, 983 * \return 0 if not plugged in, 1 if still present. 984 */ 985SDL_bool 986SDL_GameControllerGetAttached(SDL_GameController * gamecontroller) 987{ 988 if (!gamecontroller) 989 return SDL_FALSE; 990 991 return SDL_JoystickGetAttached(gamecontroller->joystick); 992} 993 994 995/* 996 * Get the number of multi-dimensional axis controls on a joystick 997 */ 998const char * 999SDL_GameControllerName(SDL_GameController * gamecontroller) 1000{ 1001 if (!gamecontroller) 1002 return NULL; 1003 1004 return (gamecontroller->mapping.name); 1005} 1006 1007 1008/* 1009 * Get the joystick for this controller 1010 */ 1011SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller) 1012{ 1013 if (!gamecontroller) 1014 return NULL; 1015 1016 return gamecontroller->joystick; 1017} 1018 1019/** 1020 * Get the SDL joystick layer binding for this controller axis mapping 1021 */ 1022SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis) 1023{ 1024 SDL_GameControllerButtonBind bind; 1025 SDL_memset(&bind, 0x0, sizeof(bind)); 1026 1027 if (!gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID) 1028 return bind; 1029 1030 if (gamecontroller->mapping.axes[axis] >= 0) { 1031 bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS; 1032 bind.value.button = gamecontroller->mapping.axes[axis]; 1033 } else if (gamecontroller->mapping.buttonasaxis[axis] >= 0) { 1034 bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON; 1035 bind.value.button = gamecontroller->mapping.buttonasaxis[axis]; 1036 } 1037 1038 return bind; 1039} 1040 1041 1042/** 1043 * Get the SDL joystick layer binding for this controller button mapping 1044 */ 1045SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button) 1046{ 1047 SDL_GameControllerButtonBind bind; 1048 SDL_memset(&bind, 0x0, sizeof(bind)); 1049 1050 if (!gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID) 1051 return bind; 1052 1053 if (gamecontroller->mapping.buttons[button] >= 0) { 1054 bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON; 1055 bind.value.button = gamecontroller->mapping.buttons[button]; 1056 } else if (gamecontroller->mapping.axesasbutton[button] >= 0) { 1057 bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS; 1058 bind.value.axis = gamecontroller->mapping.axesasbutton[button]; 1059 } else if (gamecontroller->mapping.hatasbutton[button].hat >= 0) { 1060 bind.bindType = SDL_CONTROLLER_BINDTYPE_HAT; 1061 bind.value.hat.hat = gamecontroller->mapping.hatasbutton[button].hat; 1062 bind.value.hat.hat_mask = gamecontroller->mapping.hatasbutton[button].mask; 1063 } 1064 1065 return bind; 1066} 1067 1068 1069/* 1070 * Close a joystick previously opened with SDL_JoystickOpen() 1071 */ 1072void 1073SDL_GameControllerClose(SDL_GameController * gamecontroller) 1074{ 1075 SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev; 1076 1077 if (!gamecontroller) 1078 return; 1079 1080 /* First decrement ref count */ 1081 if (--gamecontroller->ref_count > 0) { 1082 return; 1083 } 1084 1085 SDL_JoystickClose(gamecontroller->joystick); 1086 1087 gamecontrollerlist = SDL_gamecontrollers; 1088 gamecontrollerlistprev = NULL; 1089 while (gamecontrollerlist) { 1090 if (gamecontroller == gamecontrollerlist) { 1091 if (gamecontrollerlistprev) { 1092 /* unlink this entry */ 1093 gamecontrollerlistprev->next = gamecontrollerlist->next; 1094 } else { 1095 SDL_gamecontrollers = gamecontroller->next; 1096 } 1097 1098 break; 1099 } 1100 gamecontrollerlistprev = gamecontrollerlist; 1101 gamecontrollerlist = gamecontrollerlist->next; 1102 } 1103 1104 SDL_free(gamecontroller); 1105} 1106 1107 1108/* 1109 * Quit the controller subsystem 1110 */ 1111void 1112SDL_GameControllerQuit(void) 1113{ 1114 ControllerMapping_t *pControllerMap; 1115 while (SDL_gamecontrollers) { 1116 SDL_gamecontrollers->ref_count = 1; 1117 SDL_GameControllerClose(SDL_gamecontrollers); 1118 } 1119 1120 while (s_pSupportedControllers) { 1121 pControllerMap = s_pSupportedControllers; 1122 s_pSupportedControllers = s_pSupportedControllers->next; 1123 SDL_free(pControllerMap->name); 1124 SDL_free(pControllerMap->mapping); 1125 SDL_free(pControllerMap); 1126 } 1127 1128 SDL_DelEventWatch(SDL_GameControllerEventWatcher, NULL); 1129 1130} 1131 1132/* 1133 * Event filter to transform joystick events into appropriate game controller ones 1134 */ 1135int 1136SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value) 1137{ 1138 int posted; 1139 1140 /* translate the event, if desired */ 1141 posted = 0; 1142#if !SDL_EVENTS_DISABLED 1143 if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) { 1144 SDL_Event event; 1145 event.type = SDL_CONTROLLERAXISMOTION; 1146 event.caxis.which = gamecontroller->joystick->instance_id; 1147 event.caxis.axis = axis; 1148 event.caxis.value = value; 1149 posted = SDL_PushEvent(&event) == 1; 1150 } 1151#endif /* !SDL_EVENTS_DISABLED */ 1152 return (posted); 1153} 1154 1155 1156/* 1157 * Event filter to transform joystick events into appropriate game controller ones 1158 */ 1159int 1160SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state) 1161{ 1162 int posted; 1163#if !SDL_EVENTS_DISABLED 1164 SDL_Event event; 1165 1166 if (button == SDL_CONTROLLER_BUTTON_INVALID) 1167 return (0); 1168 1169 switch (state) { 1170 case SDL_PRESSED: 1171 event.type = SDL_CONTROLLERBUTTONDOWN; 1172 break; 1173 case SDL_RELEASED: 1174 event.type = SDL_CONTROLLERBUTTONUP; 1175 break; 1176 default: 1177 /* Invalid state -- bail */ 1178 return (0); 1179 } 1180#endif /* !SDL_EVENTS_DISABLED */ 1181 1182 /* translate the event, if desired */ 1183 posted = 0; 1184#if !SDL_EVENTS_DISABLED 1185 if (SDL_GetEventState(event.type) == SDL_ENABLE) { 1186 event.cbutton.which = gamecontroller->joystick->instance_id; 1187 event.cbutton.button = button; 1188 event.cbutton.state = state; 1189 posted = SDL_PushEvent(&event) == 1; 1190 } 1191#endif /* !SDL_EVENTS_DISABLED */ 1192 return (posted); 1193} 1194 1195/* 1196 * Turn off controller events 1197 */ 1198int 1199SDL_GameControllerEventState(int state) 1200{ 1201#if SDL_EVENTS_DISABLED 1202 return SDL_IGNORE; 1203#else 1204 const Uint32 event_list[] = { 1205 SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP, 1206 SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED, 1207 }; 1208 unsigned int i; 1209 1210 switch (state) { 1211 case SDL_QUERY: 1212 state = SDL_IGNORE; 1213 for (i = 0; i < SDL_arraysize(event_list); ++i) { 1214 state = SDL_EventState(event_list[i], SDL_QUERY); 1215 if (state == SDL_ENABLE) { 1216 break; 1217 } 1218 } 1219 break; 1220 default: 1221 for (i = 0; i < SDL_arraysize(event_list); ++i) { 1222 SDL_EventState(event_list[i], state); 1223 } 1224 break; 1225 } 1226 return (state); 1227#endif /* SDL_EVENTS_DISABLED */ 1228} 1229 1230/* vi: set ts=4 sw=4 expandtab: */