Atlas - SDL_joystick.c

Home / ext / SDL2 / src / joystick Lines: 2 | Size: 41829 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 joystick API for Simple DirectMedia Layer */ 24 25#include "SDL.h" 26#include "SDL_atomic.h" 27#include "SDL_events.h" 28#include "SDL_sysjoystick.h" 29#include "SDL_assert.h" 30#include "SDL_hints.h" 31 32#if !SDL_EVENTS_DISABLED 33#include "../events/SDL_events_c.h" 34#endif 35#include "../video/SDL_sysvideo.h" 36 37/* This is included in only one place because it has a large static list of controllers */ 38#include "controller_type.h" 39 40#ifdef __WIN32__ 41/* Needed for checking for input remapping programs */ 42#include "../core/windows/SDL_windows.h" 43 44#undef UNICODE /* We want ASCII functions */ 45#include <tlhelp32.h> 46#endif 47 48static SDL_JoystickDriver *SDL_joystick_drivers[] = { 49#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) 50 &SDL_WINDOWS_JoystickDriver, 51#endif 52#ifdef SDL_JOYSTICK_LINUX 53 &SDL_LINUX_JoystickDriver, 54#endif 55#ifdef SDL_JOYSTICK_IOKIT 56 &SDL_DARWIN_JoystickDriver, 57#endif 58#if defined(__IPHONEOS__) || defined(__TVOS__) 59 &SDL_IOS_JoystickDriver, 60#endif 61#ifdef SDL_JOYSTICK_ANDROID 62 &SDL_ANDROID_JoystickDriver, 63#endif 64#ifdef SDL_JOYSTICK_EMSCRIPTEN 65 &SDL_EMSCRIPTEN_JoystickDriver, 66#endif 67#ifdef SDL_JOYSTICK_HAIKU 68 &SDL_HAIKU_JoystickDriver, 69#endif 70#ifdef SDL_JOYSTICK_USBHID /* !!! FIXME: "USBHID" is a generic name, and doubly-confusing with HIDAPI next to it. This is the *BSD interface, rename this. */ 71 &SDL_BSD_JoystickDriver, 72#endif 73#ifdef SDL_JOYSTICK_HIDAPI 74 &SDL_HIDAPI_JoystickDriver, 75#endif 76#if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED) 77 &SDL_DUMMY_JoystickDriver 78#endif 79}; 80static SDL_bool SDL_joystick_allows_background_events = SDL_FALSE; 81static SDL_Joystick *SDL_joysticks = NULL; 82static SDL_bool SDL_updating_joystick = SDL_FALSE; 83static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */ 84static SDL_atomic_t SDL_next_joystick_instance_id; 85 86void 87SDL_LockJoysticks(void) 88{ 89 if (SDL_joystick_lock) { 90 SDL_LockMutex(SDL_joystick_lock); 91 } 92} 93 94void 95SDL_UnlockJoysticks(void) 96{ 97 if (SDL_joystick_lock) { 98 SDL_UnlockMutex(SDL_joystick_lock); 99 } 100} 101 102 103static void SDLCALL 104SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 105{ 106 if (hint && *hint == '1') { 107 SDL_joystick_allows_background_events = SDL_TRUE; 108 } else { 109 SDL_joystick_allows_background_events = SDL_FALSE; 110 } 111} 112 113int 114SDL_JoystickInit(void) 115{ 116 int i, status; 117 118 SDL_GameControllerInitMappings(); 119 120 /* Create the joystick list lock */ 121 if (!SDL_joystick_lock) { 122 SDL_joystick_lock = SDL_CreateMutex(); 123 } 124 125 /* See if we should allow joystick events while in the background */ 126 SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, 127 SDL_JoystickAllowBackgroundEventsChanged, NULL); 128 129#if !SDL_EVENTS_DISABLED 130 if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) { 131 return -1; 132 } 133#endif /* !SDL_EVENTS_DISABLED */ 134 135 status = -1; 136 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { 137 if (SDL_joystick_drivers[i]->Init() >= 0) { 138 status = 0; 139 } 140 } 141 return status; 142} 143 144/* 145 * Count the number of joysticks attached to the system 146 */ 147int 148SDL_NumJoysticks(void) 149{ 150 int i, total_joysticks = 0; 151 SDL_LockJoysticks(); 152 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { 153 total_joysticks += SDL_joystick_drivers[i]->GetCount(); 154 } 155 SDL_UnlockJoysticks(); 156 return total_joysticks; 157} 158 159/* 160 * Return the next available joystick instance ID 161 * This may be called by drivers from multiple threads, unprotected by any locks 162 */ 163SDL_JoystickID SDL_GetNextJoystickInstanceID() 164{ 165 return SDL_AtomicIncRef(&SDL_next_joystick_instance_id); 166} 167 168/* 169 * Get the driver and device index for an API device index 170 * This should be called while the joystick lock is held, to prevent another thread from updating the list 171 */ 172SDL_bool 173SDL_GetDriverAndJoystickIndex(int device_index, SDL_JoystickDriver **driver, int *driver_index) 174{ 175 int i, num_joysticks, total_joysticks = 0; 176 177 if (device_index >= 0) { 178 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { 179 num_joysticks = SDL_joystick_drivers[i]->GetCount(); 180 if (device_index < num_joysticks) { 181 *driver = SDL_joystick_drivers[i]; 182 *driver_index = device_index; 183 return SDL_TRUE; 184 } 185 device_index -= num_joysticks; 186 total_joysticks += num_joysticks; 187 } 188 } 189 190 SDL_SetError("There are %d joysticks available", total_joysticks); 191 return SDL_FALSE; 192} 193 194/* 195 * Perform any needed fixups for joystick names 196 */ 197static const char * 198SDL_FixupJoystickName(const char *name) 199{ 200 if (name) { 201 const char *skip_prefix = "NVIDIA Corporation "; 202 203 if (SDL_strncmp(name, skip_prefix, SDL_strlen(skip_prefix)) == 0) { 204 name += SDL_strlen(skip_prefix); 205 } 206 } 207 return name; 208} 209 210 211/* 212 * Get the implementation dependent name of a joystick 213 */ 214const char * 215SDL_JoystickNameForIndex(int device_index) 216{ 217 SDL_JoystickDriver *driver; 218 const char *name = NULL; 219 220 SDL_LockJoysticks(); 221 if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) { 222 name = SDL_FixupJoystickName(driver->GetDeviceName(device_index)); 223 } 224 SDL_UnlockJoysticks(); 225 226 /* FIXME: Really we should reference count this name so it doesn't go away after unlock */ 227 return name; 228} 229 230/* 231 * Return true if this joystick is known to have all axes centered at zero 232 * This isn't generally needed unless the joystick never generates an initial axis value near zero, 233 * e.g. it's emulating axes with digital buttons 234 */ 235static SDL_bool 236SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick) 237{ 238 static Uint32 zero_centered_joysticks[] = { 239 MAKE_VIDPID(0x0e8f, 0x3013), /* HuiJia SNES USB adapter */ 240 MAKE_VIDPID(0x05a0, 0x3232), /* 8Bitdo Zero Gamepad */ 241 }; 242 243 int i; 244 Uint32 id = MAKE_VIDPID(SDL_JoystickGetVendor(joystick), 245 SDL_JoystickGetProduct(joystick)); 246 247/*printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);*/ 248 249 if (joystick->naxes == 2) { 250 /* Assume D-pad or thumbstick style axes are centered at 0 */ 251 return SDL_TRUE; 252 } 253 254 for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) { 255 if (id == zero_centered_joysticks[i]) { 256 return SDL_TRUE; 257 } 258 } 259 return SDL_FALSE; 260} 261 262/* 263 * Open a joystick for use - the index passed as an argument refers to 264 * the N'th joystick on the system. This index is the value which will 265 * identify this joystick in future joystick events. 266 * 267 * This function returns a joystick identifier, or NULL if an error occurred. 268 */ 269SDL_Joystick * 270SDL_JoystickOpen(int device_index) 271{ 272 SDL_JoystickDriver *driver; 273 SDL_JoystickID instance_id; 274 SDL_Joystick *joystick; 275 SDL_Joystick *joysticklist; 276 const char *joystickname = NULL; 277 278 SDL_LockJoysticks(); 279 280 if (!SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) { 281 SDL_UnlockJoysticks(); 282 return NULL; 283 } 284 285 joysticklist = SDL_joysticks; 286 /* If the joystick is already open, return it 287 * it is important that we have a single joystick * for each instance id 288 */ 289 instance_id = driver->GetDeviceInstanceID(device_index); 290 while (joysticklist) { 291 if (instance_id == joysticklist->instance_id) { 292 joystick = joysticklist; 293 ++joystick->ref_count; 294 SDL_UnlockJoysticks(); 295 return joystick; 296 } 297 joysticklist = joysticklist->next; 298 } 299 300 /* Create and initialize the joystick */ 301 joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1); 302 if (joystick == NULL) { 303 SDL_OutOfMemory(); 304 SDL_UnlockJoysticks(); 305 return NULL; 306 } 307 joystick->driver = driver; 308 joystick->instance_id = instance_id; 309 joystick->attached = SDL_TRUE; 310 311 if (driver->Open(joystick, device_index) < 0) { 312 SDL_free(joystick); 313 SDL_UnlockJoysticks(); 314 return NULL; 315 } 316 317 joystickname = driver->GetDeviceName(device_index); 318 if (joystickname) { 319 joystick->name = SDL_strdup(joystickname); 320 } else { 321 joystick->name = NULL; 322 } 323 324 joystick->guid = driver->GetDeviceGUID(device_index); 325 326 if (joystick->naxes > 0) { 327 joystick->axes = (SDL_JoystickAxisInfo *) SDL_calloc(joystick->naxes, sizeof(SDL_JoystickAxisInfo)); 328 } 329 if (joystick->nhats > 0) { 330 joystick->hats = (Uint8 *) SDL_calloc(joystick->nhats, sizeof(Uint8)); 331 } 332 if (joystick->nballs > 0) { 333 joystick->balls = (struct balldelta *) SDL_calloc(joystick->nballs, sizeof(*joystick->balls)); 334 } 335 if (joystick->nbuttons > 0) { 336 joystick->buttons = (Uint8 *) SDL_calloc(joystick->nbuttons, sizeof(Uint8)); 337 } 338 if (((joystick->naxes > 0) && !joystick->axes) 339 || ((joystick->nhats > 0) && !joystick->hats) 340 || ((joystick->nballs > 0) && !joystick->balls) 341 || ((joystick->nbuttons > 0) && !joystick->buttons)) { 342 SDL_OutOfMemory(); 343 SDL_JoystickClose(joystick); 344 SDL_UnlockJoysticks(); 345 return NULL; 346 } 347 joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN; 348 349 /* If this joystick is known to have all zero centered axes, skip the auto-centering code */ 350 if (SDL_JoystickAxesCenteredAtZero(joystick)) { 351 int i; 352 353 for (i = 0; i < joystick->naxes; ++i) { 354 joystick->axes[i].has_initial_value = SDL_TRUE; 355 } 356 } 357 358 joystick->is_game_controller = SDL_IsGameController(device_index); 359 360 /* Add joystick to list */ 361 ++joystick->ref_count; 362 /* Link the joystick in the list */ 363 joystick->next = SDL_joysticks; 364 SDL_joysticks = joystick; 365 366 SDL_UnlockJoysticks(); 367 368 driver->Update(joystick); 369 370 return joystick; 371} 372 373 374/* 375 * Checks to make sure the joystick is valid. 376 */ 377int 378SDL_PrivateJoystickValid(SDL_Joystick * joystick) 379{ 380 int valid; 381 382 if (joystick == NULL) { 383 SDL_SetError("Joystick hasn't been opened yet"); 384 valid = 0; 385 } else { 386 valid = 1; 387 } 388 389 return valid; 390} 391 392/* 393 * Get the number of multi-dimensional axis controls on a joystick 394 */ 395int 396SDL_JoystickNumAxes(SDL_Joystick * joystick) 397{ 398 if (!SDL_PrivateJoystickValid(joystick)) { 399 return -1; 400 } 401 return joystick->naxes; 402} 403 404/* 405 * Get the number of hats on a joystick 406 */ 407int 408SDL_JoystickNumHats(SDL_Joystick * joystick) 409{ 410 if (!SDL_PrivateJoystickValid(joystick)) { 411 return -1; 412 } 413 return joystick->nhats; 414} 415 416/* 417 * Get the number of trackballs on a joystick 418 */ 419int 420SDL_JoystickNumBalls(SDL_Joystick * joystick) 421{ 422 if (!SDL_PrivateJoystickValid(joystick)) { 423 return -1; 424 } 425 return joystick->nballs; 426} 427 428/* 429 * Get the number of buttons on a joystick 430 */ 431int 432SDL_JoystickNumButtons(SDL_Joystick * joystick) 433{ 434 if (!SDL_PrivateJoystickValid(joystick)) { 435 return -1; 436 } 437 return joystick->nbuttons; 438} 439 440/* 441 * Get the current state of an axis control on a joystick 442 */ 443Sint16 444SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis) 445{ 446 Sint16 state; 447 448 if (!SDL_PrivateJoystickValid(joystick)) { 449 return 0; 450 } 451 if (axis < joystick->naxes) { 452 state = joystick->axes[axis].value; 453 } else { 454 SDL_SetError("Joystick only has %d axes", joystick->naxes); 455 state = 0; 456 } 457 return state; 458} 459 460/* 461 * Get the initial state of an axis control on a joystick 462 */ 463SDL_bool 464SDL_JoystickGetAxisInitialState(SDL_Joystick * joystick, int axis, Sint16 *state) 465{ 466 if (!SDL_PrivateJoystickValid(joystick)) { 467 return SDL_FALSE; 468 } 469 if (axis >= joystick->naxes) { 470 SDL_SetError("Joystick only has %d axes", joystick->naxes); 471 return SDL_FALSE; 472 } 473 if (state) { 474 *state = joystick->axes[axis].initial_value; 475 } 476 return joystick->axes[axis].has_initial_value; 477} 478 479/* 480 * Get the current state of a hat on a joystick 481 */ 482Uint8 483SDL_JoystickGetHat(SDL_Joystick * joystick, int hat) 484{ 485 Uint8 state; 486 487 if (!SDL_PrivateJoystickValid(joystick)) { 488 return 0; 489 } 490 if (hat < joystick->nhats) { 491 state = joystick->hats[hat]; 492 } else { 493 SDL_SetError("Joystick only has %d hats", joystick->nhats); 494 state = 0; 495 } 496 return state; 497} 498 499/* 500 * Get the ball axis change since the last poll 501 */ 502int 503SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy) 504{ 505 int retval; 506 507 if (!SDL_PrivateJoystickValid(joystick)) { 508 return -1; 509 } 510 511 retval = 0; 512 if (ball < joystick->nballs) { 513 if (dx) { 514 *dx = joystick->balls[ball].dx; 515 } 516 if (dy) { 517 *dy = joystick->balls[ball].dy; 518 } 519 joystick->balls[ball].dx = 0; 520 joystick->balls[ball].dy = 0; 521 } else { 522 return SDL_SetError("Joystick only has %d balls", joystick->nballs); 523 } 524 return retval; 525} 526 527/* 528 * Get the current state of a button on a joystick 529 */ 530Uint8 531SDL_JoystickGetButton(SDL_Joystick * joystick, int button) 532{ 533 Uint8 state; 534 535 if (!SDL_PrivateJoystickValid(joystick)) { 536 return 0; 537 } 538 if (button < joystick->nbuttons) { 539 state = joystick->buttons[button]; 540 } else { 541 SDL_SetError("Joystick only has %d buttons", joystick->nbuttons); 542 state = 0; 543 } 544 return state; 545} 546 547/* 548 * Return if the joystick in question is currently attached to the system, 549 * \return SDL_FALSE if not plugged in, SDL_TRUE if still present. 550 */ 551SDL_bool 552SDL_JoystickGetAttached(SDL_Joystick * joystick) 553{ 554 if (!SDL_PrivateJoystickValid(joystick)) { 555 return SDL_FALSE; 556 } 557 558 return joystick->attached; 559} 560 561/* 562 * Get the instance id for this opened joystick 563 */ 564SDL_JoystickID 565SDL_JoystickInstanceID(SDL_Joystick * joystick) 566{ 567 if (!SDL_PrivateJoystickValid(joystick)) { 568 return -1; 569 } 570 571 return joystick->instance_id; 572} 573 574/* 575 * Find the SDL_Joystick that owns this instance id 576 */ 577SDL_Joystick * 578SDL_JoystickFromInstanceID(SDL_JoystickID joyid) 579{ 580 SDL_Joystick *joystick; 581 582 SDL_LockJoysticks(); 583 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { 584 if (joystick->instance_id == joyid) { 585 break; 586 } 587 } 588 SDL_UnlockJoysticks(); 589 return joystick; 590} 591 592/* 593 * Get the friendly name of this joystick 594 */ 595const char * 596SDL_JoystickName(SDL_Joystick * joystick) 597{ 598 if (!SDL_PrivateJoystickValid(joystick)) { 599 return NULL; 600 } 601 602 return SDL_FixupJoystickName(joystick->name); 603} 604 605int 606SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) 607{ 608 if (!SDL_PrivateJoystickValid(joystick)) { 609 return -1; 610 } 611 return joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms); 612} 613 614/* 615 * Close a joystick previously opened with SDL_JoystickOpen() 616 */ 617void 618SDL_JoystickClose(SDL_Joystick * joystick) 619{ 620 SDL_Joystick *joysticklist; 621 SDL_Joystick *joysticklistprev; 622 623 if (!SDL_PrivateJoystickValid(joystick)) { 624 return; 625 } 626 627 SDL_LockJoysticks(); 628 629 /* First decrement ref count */ 630 if (--joystick->ref_count > 0) { 631 SDL_UnlockJoysticks(); 632 return; 633 } 634 635 if (SDL_updating_joystick) { 636 SDL_UnlockJoysticks(); 637 return; 638 } 639 640 joystick->driver->Close(joystick); 641 joystick->hwdata = NULL; 642 643 joysticklist = SDL_joysticks; 644 joysticklistprev = NULL; 645 while (joysticklist) { 646 if (joystick == joysticklist) { 647 if (joysticklistprev) { 648 /* unlink this entry */ 649 joysticklistprev->next = joysticklist->next; 650 } else { 651 SDL_joysticks = joystick->next; 652 } 653 break; 654 } 655 joysticklistprev = joysticklist; 656 joysticklist = joysticklist->next; 657 } 658 659 SDL_free(joystick->name); 660 661 /* Free the data associated with this joystick */ 662 SDL_free(joystick->axes); 663 SDL_free(joystick->hats); 664 SDL_free(joystick->balls); 665 SDL_free(joystick->buttons); 666 SDL_free(joystick); 667 668 SDL_UnlockJoysticks(); 669} 670 671void 672SDL_JoystickQuit(void) 673{ 674 int i; 675 676 /* Make sure we're not getting called in the middle of updating joysticks */ 677 SDL_assert(!SDL_updating_joystick); 678 679 SDL_LockJoysticks(); 680 681 /* Stop the event polling */ 682 while (SDL_joysticks) { 683 SDL_joysticks->ref_count = 1; 684 SDL_JoystickClose(SDL_joysticks); 685 } 686 687 /* Quit the joystick setup */ 688 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { 689 SDL_joystick_drivers[i]->Quit(); 690 } 691 692 SDL_UnlockJoysticks(); 693 694#if !SDL_EVENTS_DISABLED 695 SDL_QuitSubSystem(SDL_INIT_EVENTS); 696#endif 697 698 SDL_DelHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, 699 SDL_JoystickAllowBackgroundEventsChanged, NULL); 700 701 if (SDL_joystick_lock) { 702 SDL_DestroyMutex(SDL_joystick_lock); 703 SDL_joystick_lock = NULL; 704 } 705 706 SDL_GameControllerQuitMappings(); 707} 708 709 710static SDL_bool 711SDL_PrivateJoystickShouldIgnoreEvent() 712{ 713 if (SDL_joystick_allows_background_events) { 714 return SDL_FALSE; 715 } 716 717 if (SDL_HasWindows() && SDL_GetKeyboardFocus() == NULL) { 718 /* We have windows but we don't have focus, ignore the event. */ 719 return SDL_TRUE; 720 } 721 return SDL_FALSE; 722} 723 724/* These are global for SDL_sysjoystick.c and SDL_events.c */ 725 726void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance) 727{ 728#if !SDL_EVENTS_DISABLED 729 SDL_Event event; 730 int device_index; 731 732 device_index = SDL_JoystickGetDeviceIndexFromInstanceID(device_instance); 733 if (device_index < 0) { 734 return; 735 } 736 737 event.type = SDL_JOYDEVICEADDED; 738 739 if (SDL_GetEventState(event.type) == SDL_ENABLE) { 740 event.jdevice.which = device_index; 741 SDL_PushEvent(&event); 742 } 743#endif /* !SDL_EVENTS_DISABLED */ 744} 745 746/* 747 * If there is an existing add event in the queue, it needs to be modified 748 * to have the right value for which, because the number of controllers in 749 * the system is now one less. 750 */ 751static void UpdateEventsForDeviceRemoval() 752{ 753 int i, num_events; 754 SDL_Event *events; 755 756 num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED); 757 if (num_events <= 0) { 758 return; 759 } 760 761 events = SDL_stack_alloc(SDL_Event, num_events); 762 if (!events) { 763 return; 764 } 765 766 num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED); 767 for (i = 0; i < num_events; ++i) { 768 --events[i].jdevice.which; 769 } 770 SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0); 771 772 SDL_stack_free(events); 773} 774 775void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance) 776{ 777 SDL_Joystick *joystick; 778 779#if !SDL_EVENTS_DISABLED 780 SDL_Event event; 781 782 event.type = SDL_JOYDEVICEREMOVED; 783 784 if (SDL_GetEventState(event.type) == SDL_ENABLE) { 785 event.jdevice.which = device_instance; 786 SDL_PushEvent(&event); 787 } 788 789 UpdateEventsForDeviceRemoval(); 790#endif /* !SDL_EVENTS_DISABLED */ 791 792 /* Mark this joystick as no longer attached */ 793 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { 794 if (joystick->instance_id == device_instance) { 795 joystick->attached = SDL_FALSE; 796 joystick->force_recentering = SDL_TRUE; 797 break; 798 } 799 } 800} 801 802int 803SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value) 804{ 805 int posted; 806 807 /* Make sure we're not getting garbage or duplicate events */ 808 if (axis >= joystick->naxes) { 809 return 0; 810 } 811 if (!joystick->axes[axis].has_initial_value) { 812 joystick->axes[axis].initial_value = value; 813 joystick->axes[axis].value = value; 814 joystick->axes[axis].zero = value; 815 joystick->axes[axis].has_initial_value = SDL_TRUE; 816 } 817 if (value == joystick->axes[axis].value) { 818 return 0; 819 } 820 if (!joystick->axes[axis].sent_initial_value) { 821 /* Make sure we don't send motion until there's real activity on this axis */ 822 const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80; /* ShanWan PS3 controller needed 96 */ 823 if (SDL_abs(value - joystick->axes[axis].value) <= MAX_ALLOWED_JITTER) { 824 return 0; 825 } 826 joystick->axes[axis].sent_initial_value = SDL_TRUE; 827 joystick->axes[axis].value = value; /* Just so we pass the check above */ 828 SDL_PrivateJoystickAxis(joystick, axis, joystick->axes[axis].initial_value); 829 } 830 831 /* We ignore events if we don't have keyboard focus, except for centering 832 * events. 833 */ 834 if (SDL_PrivateJoystickShouldIgnoreEvent()) { 835 if ((value > joystick->axes[axis].zero && value >= joystick->axes[axis].value) || 836 (value < joystick->axes[axis].zero && value <= joystick->axes[axis].value)) { 837 return 0; 838 } 839 } 840 841 /* Update internal joystick state */ 842 joystick->axes[axis].value = value; 843 844 /* Post the event, if desired */ 845 posted = 0; 846#if !SDL_EVENTS_DISABLED 847 if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) { 848 SDL_Event event; 849 event.type = SDL_JOYAXISMOTION; 850 event.jaxis.which = joystick->instance_id; 851 event.jaxis.axis = axis; 852 event.jaxis.value = value; 853 posted = SDL_PushEvent(&event) == 1; 854 } 855#endif /* !SDL_EVENTS_DISABLED */ 856 return posted; 857} 858 859int 860SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value) 861{ 862 int posted; 863 864 /* Make sure we're not getting garbage or duplicate events */ 865 if (hat >= joystick->nhats) { 866 return 0; 867 } 868 if (value == joystick->hats[hat]) { 869 return 0; 870 } 871 872 /* We ignore events if we don't have keyboard focus, except for centering 873 * events. 874 */ 875 if (SDL_PrivateJoystickShouldIgnoreEvent()) { 876 if (value != SDL_HAT_CENTERED) { 877 return 0; 878 } 879 } 880 881 /* Update internal joystick state */ 882 joystick->hats[hat] = value; 883 884 /* Post the event, if desired */ 885 posted = 0; 886#if !SDL_EVENTS_DISABLED 887 if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) { 888 SDL_Event event; 889 event.jhat.type = SDL_JOYHATMOTION; 890 event.jhat.which = joystick->instance_id; 891 event.jhat.hat = hat; 892 event.jhat.value = value; 893 posted = SDL_PushEvent(&event) == 1; 894 } 895#endif /* !SDL_EVENTS_DISABLED */ 896 return posted; 897} 898 899int 900SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball, 901 Sint16 xrel, Sint16 yrel) 902{ 903 int posted; 904 905 /* Make sure we're not getting garbage events */ 906 if (ball >= joystick->nballs) { 907 return 0; 908 } 909 910 /* We ignore events if we don't have keyboard focus. */ 911 if (SDL_PrivateJoystickShouldIgnoreEvent()) { 912 return 0; 913 } 914 915 /* Update internal mouse state */ 916 joystick->balls[ball].dx += xrel; 917 joystick->balls[ball].dy += yrel; 918 919 /* Post the event, if desired */ 920 posted = 0; 921#if !SDL_EVENTS_DISABLED 922 if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) { 923 SDL_Event event; 924 event.jball.type = SDL_JOYBALLMOTION; 925 event.jball.which = joystick->instance_id; 926 event.jball.ball = ball; 927 event.jball.xrel = xrel; 928 event.jball.yrel = yrel; 929 posted = SDL_PushEvent(&event) == 1; 930 } 931#endif /* !SDL_EVENTS_DISABLED */ 932 return posted; 933} 934 935int 936SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state) 937{ 938 int posted; 939#if !SDL_EVENTS_DISABLED 940 SDL_Event event; 941 942 switch (state) { 943 case SDL_PRESSED: 944 event.type = SDL_JOYBUTTONDOWN; 945 break; 946 case SDL_RELEASED: 947 event.type = SDL_JOYBUTTONUP; 948 break; 949 default: 950 /* Invalid state -- bail */ 951 return 0; 952 } 953#endif /* !SDL_EVENTS_DISABLED */ 954 955 /* Make sure we're not getting garbage or duplicate events */ 956 if (button >= joystick->nbuttons) { 957 return 0; 958 } 959 if (state == joystick->buttons[button]) { 960 return 0; 961 } 962 963 /* We ignore events if we don't have keyboard focus, except for button 964 * release. */ 965 if (SDL_PrivateJoystickShouldIgnoreEvent()) { 966 if (state == SDL_PRESSED) { 967 return 0; 968 } 969 } 970 971 /* Update internal joystick state */ 972 joystick->buttons[button] = state; 973 974 /* Post the event, if desired */ 975 posted = 0; 976#if !SDL_EVENTS_DISABLED 977 if (SDL_GetEventState(event.type) == SDL_ENABLE) { 978 event.jbutton.which = joystick->instance_id; 979 event.jbutton.button = button; 980 event.jbutton.state = state; 981 posted = SDL_PushEvent(&event) == 1; 982 } 983#endif /* !SDL_EVENTS_DISABLED */ 984 return posted; 985} 986 987void 988SDL_JoystickUpdate(void) 989{ 990 int i; 991 SDL_Joystick *joystick; 992 993 SDL_LockJoysticks(); 994 995 if (SDL_updating_joystick) { 996 /* The joysticks are already being updated */ 997 SDL_UnlockJoysticks(); 998 return; 999 } 1000 1001 SDL_updating_joystick = SDL_TRUE; 1002 1003 /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */ 1004 SDL_UnlockJoysticks(); 1005 1006 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { 1007 if (joystick->attached) { 1008 joystick->driver->Update(joystick); 1009 1010 if (joystick->delayed_guide_button) { 1011 SDL_GameControllerHandleDelayedGuideButton(joystick); 1012 } 1013 } 1014 1015 if (joystick->force_recentering) { 1016 /* Tell the app that everything is centered/unpressed... */ 1017 for (i = 0; i < joystick->naxes; i++) { 1018 if (joystick->axes[i].has_initial_value) { 1019 SDL_PrivateJoystickAxis(joystick, i, joystick->axes[i].zero); 1020 } 1021 } 1022 1023 for (i = 0; i < joystick->nbuttons; i++) { 1024 SDL_PrivateJoystickButton(joystick, i, 0); 1025 } 1026 1027 for (i = 0; i < joystick->nhats; i++) { 1028 SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED); 1029 } 1030 1031 joystick->force_recentering = SDL_FALSE; 1032 } 1033 } 1034 1035 SDL_LockJoysticks(); 1036 1037 SDL_updating_joystick = SDL_FALSE; 1038 1039 /* If any joysticks were closed while updating, free them here */ 1040 for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { 1041 if (joystick->ref_count <= 0) { 1042 SDL_JoystickClose(joystick); 1043 } 1044 } 1045 1046 /* this needs to happen AFTER walking the joystick list above, so that any 1047 dangling hardware data from removed devices can be free'd 1048 */ 1049 for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) { 1050 SDL_joystick_drivers[i]->Detect(); 1051 } 1052 1053 SDL_UnlockJoysticks(); 1054} 1055 1056int 1057SDL_JoystickEventState(int state) 1058{ 1059#if SDL_EVENTS_DISABLED 1060 return SDL_DISABLE; 1061#else 1062 const Uint32 event_list[] = { 1063 SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION, 1064 SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED 1065 }; 1066 unsigned int i; 1067 1068 switch (state) { 1069 case SDL_QUERY: 1070 state = SDL_DISABLE; 1071 for (i = 0; i < SDL_arraysize(event_list); ++i) { 1072 state = SDL_EventState(event_list[i], SDL_QUERY); 1073 if (state == SDL_ENABLE) { 1074 break; 1075 } 1076 } 1077 break; 1078 default: 1079 for (i = 0; i < SDL_arraysize(event_list); ++i) { 1080 SDL_EventState(event_list[i], state); 1081 } 1082 break; 1083 } 1084 return state; 1085#endif /* SDL_EVENTS_DISABLED */ 1086} 1087 1088void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version) 1089{ 1090 Uint16 *guid16 = (Uint16 *)guid.data; 1091 1092 /* If the GUID fits the form of BUS 0000 VENDOR 0000 PRODUCT 0000, return the data */ 1093 if (/* guid16[0] is device bus type */ 1094 guid16[1] == 0x0000 && 1095 /* guid16[2] is vendor ID */ 1096 guid16[3] == 0x0000 && 1097 /* guid16[4] is product ID */ 1098 guid16[5] == 0x0000 1099 /* guid16[6] is product version */ 1100 ) { 1101 if (vendor) { 1102 *vendor = guid16[2]; 1103 } 1104 if (product) { 1105 *product = guid16[4]; 1106 } 1107 if (version) { 1108 *version = guid16[6]; 1109 } 1110 } else { 1111 if (vendor) { 1112 *vendor = 0; 1113 } 1114 if (product) { 1115 *product = 0; 1116 } 1117 if (version) { 1118 *version = 0; 1119 } 1120 } 1121} 1122 1123SDL_bool 1124SDL_IsJoystickPS4(Uint16 vendor, Uint16 product) 1125{ 1126 return (GuessControllerType(vendor, product) == k_eControllerType_PS4Controller); 1127} 1128 1129SDL_bool 1130SDL_IsJoystickNintendoSwitchPro(Uint16 vendor, Uint16 product) 1131{ 1132 return (GuessControllerType(vendor, product) == k_eControllerType_SwitchProController); 1133} 1134 1135SDL_bool 1136SDL_IsJoystickSteamController(Uint16 vendor, Uint16 product) 1137{ 1138 return BIsSteamController(GuessControllerType(vendor, product)) ? SDL_TRUE : SDL_FALSE; 1139} 1140 1141SDL_bool 1142SDL_IsJoystickXbox360(Uint16 vendor, Uint16 product) 1143{ 1144 /* Filter out some bogus values here */ 1145 if (vendor == 0x0000 && product == 0x0000) { 1146 return SDL_FALSE; 1147 } 1148 if (vendor == 0x0001 && product == 0x0001) { 1149 return SDL_FALSE; 1150 } 1151 return (GuessControllerType(vendor, product) == k_eControllerType_XBox360Controller); 1152} 1153 1154SDL_bool 1155SDL_IsJoystickXboxOne(Uint16 vendor, Uint16 product) 1156{ 1157 return (GuessControllerType(vendor, product) == k_eControllerType_XBoxOneController); 1158} 1159 1160static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid) 1161{ 1162 static Uint32 wheel_joysticks[] = { 1163 MAKE_VIDPID(0x046d, 0xc294), /* Logitech generic wheel */ 1164 MAKE_VIDPID(0x046d, 0xc295), /* Logitech Momo Force */ 1165 MAKE_VIDPID(0x046d, 0xc298), /* Logitech Driving Force Pro */ 1166 MAKE_VIDPID(0x046d, 0xc299), /* Logitech G25 */ 1167 MAKE_VIDPID(0x046d, 0xc29a), /* Logitech Driving Force GT */ 1168 MAKE_VIDPID(0x046d, 0xc29b), /* Logitech G27 */ 1169 MAKE_VIDPID(0x046d, 0xc261), /* Logitech G920 (initial mode) */ 1170 MAKE_VIDPID(0x046d, 0xc262), /* Logitech G920 (active mode) */ 1171 MAKE_VIDPID(0x044f, 0xb65d), /* Thrustmaster Wheel FFB */ 1172 MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster Wheel FFB */ 1173 MAKE_VIDPID(0x044f, 0xb677), /* Thrustmaster T150 */ 1174 MAKE_VIDPID(0x044f, 0xb664), /* Thrustmaster TX (initial mode) */ 1175 MAKE_VIDPID(0x044f, 0xb669), /* Thrustmaster TX (active mode) */ 1176 }; 1177 int i; 1178 1179 for (i = 0; i < SDL_arraysize(wheel_joysticks); ++i) { 1180 if (vidpid == wheel_joysticks[i]) { 1181 return SDL_TRUE; 1182 } 1183 } 1184 return SDL_FALSE; 1185} 1186 1187static SDL_bool SDL_IsJoystickProductFlightStick(Uint32 vidpid) 1188{ 1189 static Uint32 flightstick_joysticks[] = { 1190 MAKE_VIDPID(0x044f, 0x0402), /* HOTAS Warthog Joystick */ 1191 MAKE_VIDPID(0x0738, 0x2221), /* Saitek Pro Flight X-56 Rhino Stick */ 1192 }; 1193 int i; 1194 1195 for (i = 0; i < SDL_arraysize(flightstick_joysticks); ++i) { 1196 if (vidpid == flightstick_joysticks[i]) { 1197 return SDL_TRUE; 1198 } 1199 } 1200 return SDL_FALSE; 1201} 1202 1203static SDL_bool SDL_IsJoystickProductThrottle(Uint32 vidpid) 1204{ 1205 static Uint32 throttle_joysticks[] = { 1206 MAKE_VIDPID(0x044f, 0x0404), /* HOTAS Warthog Throttle */ 1207 MAKE_VIDPID(0x0738, 0xa221), /* Saitek Pro Flight X-56 Rhino Throttle */ 1208 }; 1209 int i; 1210 1211 for (i = 0; i < SDL_arraysize(throttle_joysticks); ++i) { 1212 if (vidpid == throttle_joysticks[i]) { 1213 return SDL_TRUE; 1214 } 1215 } 1216 return SDL_FALSE; 1217} 1218 1219static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid) 1220{ 1221 Uint16 vendor; 1222 Uint16 product; 1223 Uint32 vidpid; 1224 1225 if (guid.data[14] == 'x') { 1226 /* XInput GUID, get the type based on the XInput device subtype */ 1227 switch (guid.data[15]) { 1228 case 0x01: /* XINPUT_DEVSUBTYPE_GAMEPAD */ 1229 return SDL_JOYSTICK_TYPE_GAMECONTROLLER; 1230 case 0x02: /* XINPUT_DEVSUBTYPE_WHEEL */ 1231 return SDL_JOYSTICK_TYPE_WHEEL; 1232 case 0x03: /* XINPUT_DEVSUBTYPE_ARCADE_STICK */ 1233 return SDL_JOYSTICK_TYPE_ARCADE_STICK; 1234 case 0x04: /* XINPUT_DEVSUBTYPE_FLIGHT_STICK */ 1235 return SDL_JOYSTICK_TYPE_FLIGHT_STICK; 1236 case 0x05: /* XINPUT_DEVSUBTYPE_DANCE_PAD */ 1237 return SDL_JOYSTICK_TYPE_DANCE_PAD; 1238 case 0x06: /* XINPUT_DEVSUBTYPE_GUITAR */ 1239 case 0x07: /* XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE */ 1240 case 0x0B: /* XINPUT_DEVSUBTYPE_GUITAR_BASS */ 1241 return SDL_JOYSTICK_TYPE_GUITAR; 1242 case 0x08: /* XINPUT_DEVSUBTYPE_DRUM_KIT */ 1243 return SDL_JOYSTICK_TYPE_DRUM_KIT; 1244 case 0x13: /* XINPUT_DEVSUBTYPE_ARCADE_PAD */ 1245 return SDL_JOYSTICK_TYPE_ARCADE_PAD; 1246 default: 1247 return SDL_JOYSTICK_TYPE_UNKNOWN; 1248 } 1249 } 1250 1251 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL); 1252 vidpid = MAKE_VIDPID(vendor, product); 1253 1254 if (SDL_IsJoystickProductWheel(vidpid)) { 1255 return SDL_JOYSTICK_TYPE_WHEEL; 1256 } 1257 1258 if (SDL_IsJoystickProductFlightStick(vidpid)) { 1259 return SDL_JOYSTICK_TYPE_FLIGHT_STICK; 1260 } 1261 1262 if (SDL_IsJoystickProductThrottle(vidpid)) { 1263 return SDL_JOYSTICK_TYPE_THROTTLE; 1264 } 1265 1266 if (GuessControllerType(vendor, product) != k_eControllerType_UnknownNonSteamController) { 1267 return SDL_JOYSTICK_TYPE_GAMECONTROLLER; 1268 } 1269 1270 return SDL_JOYSTICK_TYPE_UNKNOWN; 1271} 1272 1273static SDL_bool SDL_IsPS4RemapperRunning(void) 1274{ 1275#ifdef __WIN32__ 1276 const char *mapper_processes[] = { 1277 "DS4Windows.exe", 1278 "InputMapper.exe", 1279 }; 1280 int i; 1281 PROCESSENTRY32 pe32; 1282 SDL_bool found = SDL_FALSE; 1283 1284 /* Take a snapshot of all processes in the system */ 1285 HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 1286 if (hProcessSnap != INVALID_HANDLE_VALUE) { 1287 pe32.dwSize = sizeof(PROCESSENTRY32); 1288 if (Process32First(hProcessSnap, &pe32)) { 1289 do 1290 { 1291 for (i = 0; i < SDL_arraysize(mapper_processes); ++i) { 1292 if (SDL_strcasecmp(pe32.szExeFile, mapper_processes[i]) == 0) { 1293 found = SDL_TRUE; 1294 } 1295 } 1296 } while (Process32Next(hProcessSnap, &pe32) && !found); 1297 } 1298 CloseHandle(hProcessSnap); 1299 } 1300 return found; 1301#else 1302 return SDL_FALSE; 1303#endif 1304} 1305 1306SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid) 1307{ 1308 Uint16 vendor; 1309 Uint16 product; 1310 1311 SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL); 1312 1313 if (SDL_IsJoystickPS4(vendor, product) && SDL_IsPS4RemapperRunning()) { 1314 return SDL_TRUE; 1315 } 1316 1317 if (SDL_IsGameControllerNameAndGUID(name, guid) && 1318 SDL_ShouldIgnoreGameController(name, guid)) { 1319 return SDL_TRUE; 1320 } 1321 1322 return SDL_FALSE; 1323} 1324 1325/* return the guid for this index */ 1326SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index) 1327{ 1328 SDL_JoystickDriver *driver; 1329 SDL_JoystickGUID guid; 1330 1331 SDL_LockJoysticks(); 1332 if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) { 1333 guid = driver->GetDeviceGUID(device_index); 1334 } else { 1335 SDL_zero(guid); 1336 } 1337 SDL_UnlockJoysticks(); 1338 1339 return guid; 1340} 1341 1342Uint16 SDL_JoystickGetDeviceVendor(int device_index) 1343{ 1344 Uint16 vendor; 1345 SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index); 1346 1347 SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL); 1348 return vendor; 1349} 1350 1351Uint16 SDL_JoystickGetDeviceProduct(int device_index) 1352{ 1353 Uint16 product; 1354 SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index); 1355 1356 SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL); 1357 return product; 1358} 1359 1360Uint16 SDL_JoystickGetDeviceProductVersion(int device_index) 1361{ 1362 Uint16 version; 1363 SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index); 1364 1365 SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version); 1366 return version; 1367} 1368 1369SDL_JoystickType SDL_JoystickGetDeviceType(int device_index) 1370{ 1371 SDL_JoystickType type; 1372 SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index); 1373 1374 type = SDL_GetJoystickGUIDType(guid); 1375 if (type == SDL_JOYSTICK_TYPE_UNKNOWN) { 1376 if (SDL_IsGameController(device_index)) { 1377 type = SDL_JOYSTICK_TYPE_GAMECONTROLLER; 1378 } 1379 } 1380 return type; 1381} 1382 1383SDL_JoystickID SDL_JoystickGetDeviceInstanceID(int device_index) 1384{ 1385 SDL_JoystickDriver *driver; 1386 SDL_JoystickID instance_id = -1; 1387 1388 SDL_LockJoysticks(); 1389 if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) { 1390 instance_id = driver->GetDeviceInstanceID(device_index); 1391 } 1392 SDL_UnlockJoysticks(); 1393 1394 return instance_id; 1395} 1396 1397int SDL_JoystickGetDeviceIndexFromInstanceID(SDL_JoystickID instance_id) 1398{ 1399 int i, num_joysticks, device_index = -1; 1400 1401 SDL_LockJoysticks(); 1402 num_joysticks = SDL_NumJoysticks(); 1403 for (i = 0; i < num_joysticks; ++i) { 1404 if (SDL_JoystickGetDeviceInstanceID(i) == instance_id) { 1405 device_index = i; 1406 break; 1407 } 1408 } 1409 SDL_UnlockJoysticks(); 1410 1411 return device_index; 1412} 1413 1414SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick) 1415{ 1416 if (!SDL_PrivateJoystickValid(joystick)) { 1417 SDL_JoystickGUID emptyGUID; 1418 SDL_zero(emptyGUID); 1419 return emptyGUID; 1420 } 1421 return joystick->guid; 1422} 1423 1424Uint16 SDL_JoystickGetVendor(SDL_Joystick * joystick) 1425{ 1426 Uint16 vendor; 1427 SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); 1428 1429 SDL_GetJoystickGUIDInfo(guid, &vendor, NULL, NULL); 1430 return vendor; 1431} 1432 1433Uint16 SDL_JoystickGetProduct(SDL_Joystick * joystick) 1434{ 1435 Uint16 product; 1436 SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); 1437 1438 SDL_GetJoystickGUIDInfo(guid, NULL, &product, NULL); 1439 return product; 1440} 1441 1442Uint16 SDL_JoystickGetProductVersion(SDL_Joystick * joystick) 1443{ 1444 Uint16 version; 1445 SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); 1446 1447 SDL_GetJoystickGUIDInfo(guid, NULL, NULL, &version); 1448 return version; 1449} 1450 1451SDL_JoystickType SDL_JoystickGetType(SDL_Joystick * joystick) 1452{ 1453 SDL_JoystickType type; 1454 SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); 1455 1456 type = SDL_GetJoystickGUIDType(guid); 1457 if (type == SDL_JOYSTICK_TYPE_UNKNOWN) { 1458 if (joystick && joystick->is_game_controller) { 1459 type = SDL_JOYSTICK_TYPE_GAMECONTROLLER; 1460 } 1461 } 1462 return type; 1463} 1464 1465/* convert the guid to a printable string */ 1466void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID) 1467{ 1468 static const char k_rgchHexToASCII[] = "0123456789abcdef"; 1469 int i; 1470 1471 if ((pszGUID == NULL) || (cbGUID <= 0)) { 1472 return; 1473 } 1474 1475 for (i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++) { 1476 /* each input byte writes 2 ascii chars, and might write a null byte. */ 1477 /* If we don't have room for next input byte, stop */ 1478 unsigned char c = guid.data[i]; 1479 1480 *pszGUID++ = k_rgchHexToASCII[c >> 4]; 1481 *pszGUID++ = k_rgchHexToASCII[c & 0x0F]; 1482 } 1483 *pszGUID = '\0'; 1484} 1485 1486/*----------------------------------------------------------------------------- 1487 * Purpose: Returns the 4 bit nibble for a hex character 1488 * Input : c - 1489 * Output : unsigned char 1490 *-----------------------------------------------------------------------------*/ 1491static unsigned char nibble(char c) 1492{ 1493 if ((c >= '0') && (c <= '9')) { 1494 return (unsigned char)(c - '0'); 1495 } 1496 1497 if ((c >= 'A') && (c <= 'F')) { 1498 return (unsigned char)(c - 'A' + 0x0a); 1499 } 1500 1501 if ((c >= 'a') && (c <= 'f')) { 1502 return (unsigned char)(c - 'a' + 0x0a); 1503 } 1504 1505 /* received an invalid character, and no real way to return an error */ 1506 /* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */ 1507 return 0; 1508} 1509 1510/* convert the string version of a joystick guid to the struct */ 1511SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID) 1512{ 1513 SDL_JoystickGUID guid; 1514 int maxoutputbytes= sizeof(guid); 1515 size_t len = SDL_strlen(pchGUID); 1516 Uint8 *p; 1517 size_t i; 1518 1519 /* Make sure it's even */ 1520 len = (len) & ~0x1; 1521 1522 SDL_memset(&guid, 0x00, sizeof(guid)); 1523 1524 p = (Uint8 *)&guid; 1525 for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) { 1526 *p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]); 1527 } 1528 1529 return guid; 1530} 1531 1532/* update the power level for this joystick */ 1533void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel) 1534{ 1535 joystick->epowerlevel = ePowerLevel; 1536} 1537 1538/* return its power level */ 1539SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick) 1540{ 1541 if (!SDL_PrivateJoystickValid(joystick)) { 1542 return SDL_JOYSTICK_POWER_UNKNOWN; 1543 } 1544 return joystick->epowerlevel; 1545} 1546 1547/* vi: set ts=4 sw=4 expandtab: */ 1548
[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.