SDL_xinputjoystick.c (20677B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20 */ 21 #include "../../SDL_internal.h" 22 23 #include "../SDL_sysjoystick.h" 24 25 #if SDL_JOYSTICK_XINPUT 26 27 #include "SDL_hints.h" 28 #include "SDL_timer.h" 29 #include "SDL_windowsjoystick_c.h" 30 #include "SDL_xinputjoystick_c.h" 31 #include "SDL_rawinputjoystick_c.h" 32 #include "../hidapi/SDL_hidapijoystick_c.h" 33 34 /* 35 * Internal stuff. 36 */ 37 static SDL_bool s_bXInputEnabled = SDL_TRUE; 38 static char *s_arrXInputDevicePath[XUSER_MAX_COUNT]; 39 40 41 static SDL_bool 42 SDL_XInputUseOldJoystickMapping() 43 { 44 #ifdef __WINRT__ 45 /* TODO: remove this __WINRT__ block, but only after integrating with UWP/WinRT's HID API */ 46 /* FIXME: Why are Win8/10 different here? -flibit */ 47 return (NTDDI_VERSION < NTDDI_WIN10); 48 #else 49 static int s_XInputUseOldJoystickMapping = -1; 50 if (s_XInputUseOldJoystickMapping < 0) { 51 s_XInputUseOldJoystickMapping = SDL_GetHintBoolean(SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING, SDL_FALSE); 52 } 53 return (s_XInputUseOldJoystickMapping > 0); 54 #endif 55 } 56 57 SDL_bool SDL_XINPUT_Enabled(void) 58 { 59 return s_bXInputEnabled; 60 } 61 62 int 63 SDL_XINPUT_JoystickInit(void) 64 { 65 s_bXInputEnabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE); 66 67 #ifdef SDL_JOYSTICK_RAWINPUT 68 if (RAWINPUT_IsEnabled()) { 69 /* The raw input driver handles more than 4 controllers, so prefer that when available */ 70 s_bXInputEnabled = SDL_FALSE; 71 } 72 #endif 73 74 if (s_bXInputEnabled && WIN_LoadXInputDLL() < 0) { 75 s_bXInputEnabled = SDL_FALSE; /* oh well. */ 76 } 77 return 0; 78 } 79 80 static const char * 81 GetXInputName(const Uint8 userid, BYTE SubType) 82 { 83 static char name[32]; 84 85 if (SDL_XInputUseOldJoystickMapping()) { 86 SDL_snprintf(name, sizeof(name), "X360 Controller #%u", 1 + userid); 87 } else { 88 switch (SubType) { 89 case XINPUT_DEVSUBTYPE_GAMEPAD: 90 SDL_snprintf(name, sizeof(name), "XInput Controller #%u", 1 + userid); 91 break; 92 case XINPUT_DEVSUBTYPE_WHEEL: 93 SDL_snprintf(name, sizeof(name), "XInput Wheel #%u", 1 + userid); 94 break; 95 case XINPUT_DEVSUBTYPE_ARCADE_STICK: 96 SDL_snprintf(name, sizeof(name), "XInput ArcadeStick #%u", 1 + userid); 97 break; 98 case XINPUT_DEVSUBTYPE_FLIGHT_STICK: 99 SDL_snprintf(name, sizeof(name), "XInput FlightStick #%u", 1 + userid); 100 break; 101 case XINPUT_DEVSUBTYPE_DANCE_PAD: 102 SDL_snprintf(name, sizeof(name), "XInput DancePad #%u", 1 + userid); 103 break; 104 case XINPUT_DEVSUBTYPE_GUITAR: 105 case XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE: 106 case XINPUT_DEVSUBTYPE_GUITAR_BASS: 107 SDL_snprintf(name, sizeof(name), "XInput Guitar #%u", 1 + userid); 108 break; 109 case XINPUT_DEVSUBTYPE_DRUM_KIT: 110 SDL_snprintf(name, sizeof(name), "XInput DrumKit #%u", 1 + userid); 111 break; 112 case XINPUT_DEVSUBTYPE_ARCADE_PAD: 113 SDL_snprintf(name, sizeof(name), "XInput ArcadePad #%u", 1 + userid); 114 break; 115 default: 116 SDL_snprintf(name, sizeof(name), "XInput Device #%u", 1 + userid); 117 break; 118 } 119 } 120 return name; 121 } 122 123 /* We can't really tell what device is being used for XInput, but we can guess 124 and we'll be correct for the case where only one device is connected. 125 */ 126 static void 127 GuessXInputDevice(Uint8 userid, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersion) 128 { 129 #ifndef __WINRT__ /* TODO: remove this ifndef __WINRT__ block, but only after integrating with UWP/WinRT's HID API */ 130 131 PRAWINPUTDEVICELIST devices = NULL; 132 UINT i, j, device_count = 0; 133 134 if ((GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) || (!device_count)) { 135 return; /* oh well. */ 136 } 137 138 devices = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * device_count); 139 if (devices == NULL) { 140 return; 141 } 142 143 if (GetRawInputDeviceList(devices, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) { 144 SDL_free(devices); 145 return; /* oh well. */ 146 } 147 148 /* First see if we have a cached entry for this index */ 149 if (s_arrXInputDevicePath[userid]) { 150 for (i = 0; i < device_count; i++) { 151 RID_DEVICE_INFO rdi; 152 char devName[128]; 153 UINT rdiSize = sizeof(rdi); 154 UINT nameSize = SDL_arraysize(devName); 155 156 rdi.cbSize = sizeof(rdi); 157 if (devices[i].dwType == RIM_TYPEHID && 158 GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != (UINT)-1 && 159 GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != (UINT)-1) { 160 if (SDL_strcmp(devName, s_arrXInputDevicePath[userid]) == 0) { 161 *pVID = (Uint16)rdi.hid.dwVendorId; 162 *pPID = (Uint16)rdi.hid.dwProductId; 163 *pVersion = (Uint16)rdi.hid.dwVersionNumber; 164 SDL_free(devices); 165 return; 166 } 167 } 168 } 169 } 170 171 for (i = 0; i < device_count; i++) { 172 RID_DEVICE_INFO rdi; 173 char devName[MAX_PATH]; 174 UINT rdiSize = sizeof(rdi); 175 UINT nameSize = SDL_arraysize(devName); 176 177 rdi.cbSize = sizeof(rdi); 178 if (devices[i].dwType == RIM_TYPEHID && 179 GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != (UINT)-1 && 180 GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != (UINT)-1) { 181 #ifdef DEBUG_JOYSTICK 182 SDL_Log("Raw input device: VID = 0x%x, PID = 0x%x, %s\n", rdi.hid.dwVendorId, rdi.hid.dwProductId, devName); 183 #endif 184 if (SDL_strstr(devName, "IG_") != NULL) { 185 SDL_bool found = SDL_FALSE; 186 for (j = 0; j < SDL_arraysize(s_arrXInputDevicePath); ++j) { 187 if (!s_arrXInputDevicePath[j]) { 188 continue; 189 } 190 if (SDL_strcmp(devName, s_arrXInputDevicePath[j]) == 0) { 191 found = SDL_TRUE; 192 break; 193 } 194 } 195 if (found) { 196 /* We already have this device in our XInput device list */ 197 continue; 198 } 199 200 /* We don't actually know if this is the right device for this 201 * userid, but we'll record it so we'll at least be consistent 202 * when the raw device list changes. 203 */ 204 *pVID = (Uint16)rdi.hid.dwVendorId; 205 *pPID = (Uint16)rdi.hid.dwProductId; 206 *pVersion = (Uint16)rdi.hid.dwVersionNumber; 207 if (s_arrXInputDevicePath[userid]) { 208 SDL_free(s_arrXInputDevicePath[userid]); 209 } 210 s_arrXInputDevicePath[userid] = SDL_strdup(devName); 211 SDL_free(devices); 212 return; 213 } 214 } 215 } 216 SDL_free(devices); 217 #endif /* !__WINRT__ */ 218 219 /* The device wasn't in the raw HID device list, it's probably Bluetooth */ 220 *pVID = 0x045e; /* Microsoft */ 221 *pPID = 0x02fd; /* XBox One S Bluetooth */ 222 *pVersion = 0; 223 } 224 225 static void 226 AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pContext) 227 { 228 Uint16 vendor = 0; 229 Uint16 product = 0; 230 Uint16 version = 0; 231 JoyStick_DeviceData *pPrevJoystick = NULL; 232 JoyStick_DeviceData *pNewJoystick = *pContext; 233 234 if (SDL_XInputUseOldJoystickMapping() && SubType != XINPUT_DEVSUBTYPE_GAMEPAD) 235 return; 236 237 if (SubType == XINPUT_DEVSUBTYPE_UNKNOWN) 238 return; 239 240 while (pNewJoystick) { 241 if (pNewJoystick->bXInputDevice && (pNewJoystick->XInputUserId == userid) && (pNewJoystick->SubType == SubType)) { 242 /* if we are replacing the front of the list then update it */ 243 if (pNewJoystick == *pContext) { 244 *pContext = pNewJoystick->pNext; 245 } else if (pPrevJoystick) { 246 pPrevJoystick->pNext = pNewJoystick->pNext; 247 } 248 249 pNewJoystick->pNext = SYS_Joystick; 250 SYS_Joystick = pNewJoystick; 251 return; /* already in the list. */ 252 } 253 254 pPrevJoystick = pNewJoystick; 255 pNewJoystick = pNewJoystick->pNext; 256 } 257 258 pNewJoystick = (JoyStick_DeviceData *)SDL_calloc(1, sizeof(JoyStick_DeviceData)); 259 if (!pNewJoystick) { 260 return; /* better luck next time? */ 261 } 262 263 pNewJoystick->bXInputDevice = SDL_TRUE; 264 if (!SDL_XInputUseOldJoystickMapping()) { 265 Uint16 *guid16 = (Uint16 *)pNewJoystick->guid.data; 266 267 GuessXInputDevice(userid, &vendor, &product, &version); 268 269 *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB); 270 *guid16++ = 0; 271 *guid16++ = SDL_SwapLE16(vendor); 272 *guid16++ = 0; 273 *guid16++ = SDL_SwapLE16(product); 274 *guid16++ = 0; 275 *guid16++ = SDL_SwapLE16(version); 276 *guid16++ = 0; 277 278 /* Note that this is an XInput device and what subtype it is */ 279 pNewJoystick->guid.data[14] = 'x'; 280 pNewJoystick->guid.data[15] = SubType; 281 } 282 pNewJoystick->SubType = SubType; 283 pNewJoystick->XInputUserId = userid; 284 pNewJoystick->joystickname = SDL_CreateJoystickName(vendor, product, NULL, GetXInputName(userid, SubType)); 285 if (!pNewJoystick->joystickname) { 286 SDL_free(pNewJoystick); 287 return; /* better luck next time? */ 288 } 289 290 if (SDL_ShouldIgnoreJoystick(pNewJoystick->joystickname, pNewJoystick->guid)) { 291 SDL_free(pNewJoystick); 292 return; 293 } 294 295 #ifdef SDL_JOYSTICK_HIDAPI 296 /* Since we're guessing about the VID/PID, use a hard-coded VID/PID to represent XInput */ 297 if (HIDAPI_IsDevicePresent(USB_VENDOR_MICROSOFT, USB_PRODUCT_XBOX_ONE_XINPUT_CONTROLLER, version, pNewJoystick->joystickname)) { 298 /* The HIDAPI driver is taking care of this device */ 299 SDL_free(pNewJoystick); 300 return; 301 } 302 #endif 303 304 #ifdef SDL_JOYSTICK_RAWINPUT 305 if (RAWINPUT_IsDevicePresent(vendor, product, version, pNewJoystick->joystickname)) { 306 /* The RAWINPUT driver is taking care of this device */ 307 SDL_free(pNewJoystick); 308 return; 309 } 310 #endif 311 312 WINDOWS_AddJoystickDevice(pNewJoystick); 313 } 314 315 static void 316 DelXInputDevice(Uint8 userid) 317 { 318 if (s_arrXInputDevicePath[userid]) { 319 SDL_free(s_arrXInputDevicePath[userid]); 320 s_arrXInputDevicePath[userid] = NULL; 321 } 322 } 323 324 void 325 SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext) 326 { 327 int iuserid; 328 329 if (!s_bXInputEnabled) { 330 return; 331 } 332 333 /* iterate in reverse, so these are in the final list in ascending numeric order. */ 334 for (iuserid = XUSER_MAX_COUNT - 1; iuserid >= 0; iuserid--) { 335 const Uint8 userid = (Uint8)iuserid; 336 XINPUT_CAPABILITIES capabilities; 337 if (XINPUTGETCAPABILITIES(userid, XINPUT_FLAG_GAMEPAD, &capabilities) == ERROR_SUCCESS) { 338 /* Adding a new device, must handle all removes first, or GuessXInputDevice goes terribly wrong (returns 339 a product/vendor ID that is not even attached to the system) when we get a remove and add on the same tick 340 (e.g. when disconnecting a device and the OS reassigns which userid an already-attached controller is) 341 */ 342 int iuserid2; 343 for (iuserid2 = iuserid - 1; iuserid2 >= 0; iuserid2--) { 344 const Uint8 userid2 = (Uint8)iuserid2; 345 XINPUT_CAPABILITIES capabilities2; 346 if (XINPUTGETCAPABILITIES(userid2, XINPUT_FLAG_GAMEPAD, &capabilities2) != ERROR_SUCCESS) { 347 DelXInputDevice(userid2); 348 } 349 } 350 AddXInputDevice(userid, capabilities.SubType, pContext); 351 } else { 352 DelXInputDevice(userid); 353 } 354 } 355 } 356 357 int 358 SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice) 359 { 360 const Uint8 userId = joystickdevice->XInputUserId; 361 XINPUT_CAPABILITIES capabilities; 362 XINPUT_VIBRATION state; 363 364 SDL_assert(s_bXInputEnabled); 365 SDL_assert(XINPUTGETCAPABILITIES); 366 SDL_assert(XINPUTSETSTATE); 367 SDL_assert(userId < XUSER_MAX_COUNT); 368 369 joystick->hwdata->bXInputDevice = SDL_TRUE; 370 371 if (XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities) != ERROR_SUCCESS) { 372 SDL_free(joystick->hwdata); 373 joystick->hwdata = NULL; 374 return SDL_SetError("Failed to obtain XInput device capabilities. Device disconnected?"); 375 } 376 SDL_zero(state); 377 joystick->hwdata->bXInputHaptic = (XINPUTSETSTATE(userId, &state) == ERROR_SUCCESS); 378 joystick->hwdata->userid = userId; 379 380 /* The XInput API has a hard coded button/axis mapping, so we just match it */ 381 if (SDL_XInputUseOldJoystickMapping()) { 382 joystick->naxes = 6; 383 joystick->nbuttons = 15; 384 } else { 385 joystick->naxes = 6; 386 joystick->nbuttons = 11; 387 joystick->nhats = 1; 388 } 389 return 0; 390 } 391 392 static void 393 UpdateXInputJoystickBatteryInformation(SDL_Joystick * joystick, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation) 394 { 395 if (pBatteryInformation->BatteryType != BATTERY_TYPE_UNKNOWN) { 396 SDL_JoystickPowerLevel ePowerLevel = SDL_JOYSTICK_POWER_UNKNOWN; 397 if (pBatteryInformation->BatteryType == BATTERY_TYPE_WIRED) { 398 ePowerLevel = SDL_JOYSTICK_POWER_WIRED; 399 } else { 400 switch (pBatteryInformation->BatteryLevel) { 401 case BATTERY_LEVEL_EMPTY: 402 ePowerLevel = SDL_JOYSTICK_POWER_EMPTY; 403 break; 404 case BATTERY_LEVEL_LOW: 405 ePowerLevel = SDL_JOYSTICK_POWER_LOW; 406 break; 407 case BATTERY_LEVEL_MEDIUM: 408 ePowerLevel = SDL_JOYSTICK_POWER_MEDIUM; 409 break; 410 default: 411 case BATTERY_LEVEL_FULL: 412 ePowerLevel = SDL_JOYSTICK_POWER_FULL; 413 break; 414 } 415 } 416 417 SDL_PrivateJoystickBatteryLevel(joystick, ePowerLevel); 418 } 419 } 420 421 static void 422 UpdateXInputJoystickState_OLD(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation) 423 { 424 static WORD s_XInputButtons[] = { 425 XINPUT_GAMEPAD_DPAD_UP, XINPUT_GAMEPAD_DPAD_DOWN, XINPUT_GAMEPAD_DPAD_LEFT, XINPUT_GAMEPAD_DPAD_RIGHT, 426 XINPUT_GAMEPAD_START, XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_LEFT_THUMB, XINPUT_GAMEPAD_RIGHT_THUMB, 427 XINPUT_GAMEPAD_LEFT_SHOULDER, XINPUT_GAMEPAD_RIGHT_SHOULDER, 428 XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, XINPUT_GAMEPAD_X, XINPUT_GAMEPAD_Y, 429 XINPUT_GAMEPAD_GUIDE 430 }; 431 WORD wButtons = pXInputState->Gamepad.wButtons; 432 Uint8 button; 433 434 SDL_PrivateJoystickAxis(joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX); 435 SDL_PrivateJoystickAxis(joystick, 1, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbLY))); 436 SDL_PrivateJoystickAxis(joystick, 2, (Sint16)pXInputState->Gamepad.sThumbRX); 437 SDL_PrivateJoystickAxis(joystick, 3, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbRY))); 438 SDL_PrivateJoystickAxis(joystick, 4, (Sint16)(((int)pXInputState->Gamepad.bLeftTrigger * 65535 / 255) - 32768)); 439 SDL_PrivateJoystickAxis(joystick, 5, (Sint16)(((int)pXInputState->Gamepad.bRightTrigger * 65535 / 255) - 32768)); 440 441 for (button = 0; button < SDL_arraysize(s_XInputButtons); ++button) { 442 SDL_PrivateJoystickButton(joystick, button, (wButtons & s_XInputButtons[button]) ? SDL_PRESSED : SDL_RELEASED); 443 } 444 445 UpdateXInputJoystickBatteryInformation(joystick, pBatteryInformation); 446 } 447 448 static void 449 UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation) 450 { 451 static WORD s_XInputButtons[] = { 452 XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, XINPUT_GAMEPAD_X, XINPUT_GAMEPAD_Y, 453 XINPUT_GAMEPAD_LEFT_SHOULDER, XINPUT_GAMEPAD_RIGHT_SHOULDER, XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_START, 454 XINPUT_GAMEPAD_LEFT_THUMB, XINPUT_GAMEPAD_RIGHT_THUMB, 455 XINPUT_GAMEPAD_GUIDE 456 }; 457 WORD wButtons = pXInputState->Gamepad.wButtons; 458 Uint8 button; 459 Uint8 hat = SDL_HAT_CENTERED; 460 461 SDL_PrivateJoystickAxis(joystick, 0, pXInputState->Gamepad.sThumbLX); 462 SDL_PrivateJoystickAxis(joystick, 1, ~pXInputState->Gamepad.sThumbLY); 463 SDL_PrivateJoystickAxis(joystick, 2, ((int)pXInputState->Gamepad.bLeftTrigger * 257) - 32768); 464 SDL_PrivateJoystickAxis(joystick, 3, pXInputState->Gamepad.sThumbRX); 465 SDL_PrivateJoystickAxis(joystick, 4, ~pXInputState->Gamepad.sThumbRY); 466 SDL_PrivateJoystickAxis(joystick, 5, ((int)pXInputState->Gamepad.bRightTrigger * 257) - 32768); 467 468 for (button = 0; button < SDL_arraysize(s_XInputButtons); ++button) { 469 SDL_PrivateJoystickButton(joystick, button, (wButtons & s_XInputButtons[button]) ? SDL_PRESSED : SDL_RELEASED); 470 } 471 472 if (wButtons & XINPUT_GAMEPAD_DPAD_UP) { 473 hat |= SDL_HAT_UP; 474 } 475 if (wButtons & XINPUT_GAMEPAD_DPAD_DOWN) { 476 hat |= SDL_HAT_DOWN; 477 } 478 if (wButtons & XINPUT_GAMEPAD_DPAD_LEFT) { 479 hat |= SDL_HAT_LEFT; 480 } 481 if (wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) { 482 hat |= SDL_HAT_RIGHT; 483 } 484 SDL_PrivateJoystickHat(joystick, 0, hat); 485 486 UpdateXInputJoystickBatteryInformation(joystick, pBatteryInformation); 487 } 488 489 int 490 SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 491 { 492 XINPUT_VIBRATION XVibration; 493 494 if (!XINPUTSETSTATE) { 495 return SDL_Unsupported(); 496 } 497 498 XVibration.wLeftMotorSpeed = low_frequency_rumble; 499 XVibration.wRightMotorSpeed = high_frequency_rumble; 500 if (XINPUTSETSTATE(joystick->hwdata->userid, &XVibration) != ERROR_SUCCESS) { 501 return SDL_SetError("XInputSetState() failed"); 502 } 503 return 0; 504 } 505 506 void 507 SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick) 508 { 509 HRESULT result; 510 XINPUT_STATE_EX XInputState; 511 XINPUT_BATTERY_INFORMATION_EX XBatteryInformation; 512 513 if (!XINPUTGETSTATE) 514 return; 515 516 result = XINPUTGETSTATE(joystick->hwdata->userid, &XInputState); 517 if (result == ERROR_DEVICE_NOT_CONNECTED) { 518 return; 519 } 520 521 SDL_zero(XBatteryInformation); 522 if (XINPUTGETBATTERYINFORMATION) { 523 result = XINPUTGETBATTERYINFORMATION(joystick->hwdata->userid, BATTERY_DEVTYPE_GAMEPAD, &XBatteryInformation); 524 } 525 526 /* only fire events if the data changed from last time */ 527 if (XInputState.dwPacketNumber && XInputState.dwPacketNumber != joystick->hwdata->dwPacketNumber) { 528 if (SDL_XInputUseOldJoystickMapping()) { 529 UpdateXInputJoystickState_OLD(joystick, &XInputState, &XBatteryInformation); 530 } else { 531 UpdateXInputJoystickState(joystick, &XInputState, &XBatteryInformation); 532 } 533 joystick->hwdata->dwPacketNumber = XInputState.dwPacketNumber; 534 } 535 } 536 537 void 538 SDL_XINPUT_JoystickClose(SDL_Joystick * joystick) 539 { 540 } 541 542 void 543 SDL_XINPUT_JoystickQuit(void) 544 { 545 if (s_bXInputEnabled) { 546 WIN_UnloadXInputDLL(); 547 } 548 } 549 550 #else /* !SDL_JOYSTICK_XINPUT */ 551 552 typedef struct JoyStick_DeviceData JoyStick_DeviceData; 553 554 SDL_bool SDL_XINPUT_Enabled(void) 555 { 556 return SDL_FALSE; 557 } 558 559 int 560 SDL_XINPUT_JoystickInit(void) 561 { 562 return 0; 563 } 564 565 void 566 SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext) 567 { 568 } 569 570 int 571 SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice) 572 { 573 return SDL_Unsupported(); 574 } 575 576 int 577 SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 578 { 579 return SDL_Unsupported(); 580 } 581 582 void 583 SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick) 584 { 585 } 586 587 void 588 SDL_XINPUT_JoystickClose(SDL_Joystick * joystick) 589 { 590 } 591 592 void 593 SDL_XINPUT_JoystickQuit(void) 594 { 595 } 596 597 #endif /* SDL_JOYSTICK_XINPUT */ 598 599 /* vi: set ts=4 sw=4 expandtab: */