Atlas - SDL_hidapi_xbox360.c

Home / ext / SDL / src / joystick / hidapi Lines: 1 | Size: 20776 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 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#ifdef SDL_JOYSTICK_HIDAPI 24 25#include "../../SDL_hints_c.h" 26#include "../../misc/SDL_libusb.h" 27#include "../SDL_sysjoystick.h" 28#include "SDL_hidapijoystick_c.h" 29#include "SDL_hidapi_rumble.h" 30#include "SDL_hidapi_xbox360.h" 31 32#ifdef SDL_JOYSTICK_HIDAPI_XBOX360 33 34// Define this if you want to log all packets from the controller 35// #define DEBUG_XBOX_PROTOCOL 36 37#ifdef SDL_PLATFORM_MACOS 38#include <IOKit/IOKitLib.h> 39#endif 40 41typedef struct 42{ 43 SDL_HIDAPI_Device *device; 44 SDL_Joystick *joystick; 45 int player_index; 46 bool player_lights; 47 SDL_xinput_capabilities capabilities; 48 Uint8 last_state[USB_PACKET_LENGTH]; 49#ifdef SDL_PLATFORM_MACOS 50 bool controlled_by_360controller; 51#endif 52} SDL_DriverXbox360_Context; 53 54static void HIDAPI_DriverXbox360_RegisterHints(SDL_HintCallback callback, void *userdata) 55{ 56 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata); 57 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, callback, userdata); 58} 59 60static void HIDAPI_DriverXbox360_UnregisterHints(SDL_HintCallback callback, void *userdata) 61{ 62 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata); 63 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, callback, userdata); 64} 65 66static bool HIDAPI_DriverXbox360_IsEnabled(void) 67{ 68 return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, 69 SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT))); 70} 71 72#ifdef SDL_PLATFORM_MACOS 73static bool IsControlledBy360ControllerDriverMacOS(SDL_HIDAPI_Device *device) 74{ 75 bool controlled_by_360controller = false; 76 if (device && device->path && SDL_strncmp("DevSrvsID:", device->path, 10) == 0) { 77 uint64_t entry_id = SDL_strtoull(device->path + 10, NULL, 10); 78 io_service_t service = IOServiceGetMatchingService(0, IORegistryEntryIDMatching(entry_id)); 79 if (service != MACH_PORT_NULL) { 80 controlled_by_360controller = IOObjectConformsTo(service, "Xbox360ControllerClass"); 81 IOObjectRelease(service); 82 } 83 } 84 return controlled_by_360controller; 85} 86#endif 87 88#ifdef HAVE_LIBUSB 89static void FetchXInputCapabilities(SDL_HIDAPI_Device *device) 90{ 91 SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context; 92 SDL_LibUSBContext *libusb_ctx; 93 if (SDL_InitLibUSB(&libusb_ctx)) { 94 libusb_device_handle *handle = (libusb_device_handle *)SDL_GetPointerProperty(SDL_hid_get_properties(device->dev), SDL_PROP_HIDAPI_LIBUSB_DEVICE_HANDLE_POINTER, NULL); 95 if (handle == NULL) { 96 SDL_QuitLibUSB(); 97 return; 98 } 99 libusb_device *dev = libusb_ctx->get_device(handle); 100 if (dev == NULL) { 101 SDL_QuitLibUSB(); 102 return; 103 } 104 struct libusb_config_descriptor *conf_desc = NULL; 105 const struct libusb_interface_descriptor *intf_desc; 106 libusb_ctx->get_active_config_descriptor(dev, &conf_desc); 107 if (conf_desc == NULL || conf_desc->bNumInterfaces < device->interface_number) { 108 SDL_QuitLibUSB(); 109 return; 110 } 111 const struct libusb_interface *intf = &conf_desc->interface[device->interface_number]; 112 intf_desc = &intf->altsetting[0]; 113 if (intf_desc->extra_length == 17 && intf_desc->extra[1] == 0x21) { 114 ctx->capabilities.type = intf_desc->extra[3]; 115 ctx->capabilities.subType = intf_desc->extra[4]; 116 switch (ctx->capabilities.subType) { 117 case 0x01: // XINPUT_DEVSUBTYPE_GAMEPAD 118 device->joystick_type = SDL_JOYSTICK_TYPE_GAMEPAD; 119 break; 120 case 0x02: // XINPUT_DEVSUBTYPE_WHEEL 121 device->joystick_type = SDL_JOYSTICK_TYPE_WHEEL; 122 break; 123 case 0x03: // XINPUT_DEVSUBTYPE_ARCADE_STICK 124 device->joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK; 125 break; 126 case 0x04: // XINPUT_DEVSUBTYPE_FLIGHT_STICK 127 device->joystick_type = SDL_JOYSTICK_TYPE_FLIGHT_STICK; 128 break; 129 case 0x05: // XINPUT_DEVSUBTYPE_DANCE_PAD 130 device->joystick_type = SDL_JOYSTICK_TYPE_DANCE_PAD; 131 break; 132 case 0x06: // XINPUT_DEVSUBTYPE_GUITAR 133 case 0x07: // XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE 134 case 0x0B: // XINPUT_DEVSUBTYPE_GUITAR_BASS 135 device->joystick_type = SDL_JOYSTICK_TYPE_GUITAR; 136 break; 137 case 0x08: // XINPUT_DEVSUBTYPE_DRUM_KIT 138 device->joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT; 139 break; 140 case 0x13: // XINPUT_DEVSUBTYPE_ARCADE_PAD 141 device->joystick_type = SDL_JOYSTICK_TYPE_ARCADE_PAD; 142 break; 143 default: 144 break; 145 } 146 device->guid.data[15] = ctx->capabilities.subType; 147 unsigned char buf[20]; 148 int ret = libusb_ctx->control_transfer(handle, 0xC1, 0x01, 0x100, 0x0, buf, sizeof(buf), 100); 149 if (ret == sizeof(buf)) { 150 ctx->capabilities.flags = LOAD16(buf[18], buf[19]); 151 ctx->capabilities.gamepad.wButtons = LOAD16(buf[2], buf[3]); 152 ctx->capabilities.gamepad.bLeftTrigger = buf[4]; 153 ctx->capabilities.gamepad.bRightTrigger = buf[5]; 154 ctx->capabilities.gamepad.sThumbLX = LOAD16(buf[6], buf[7]); 155 ctx->capabilities.gamepad.sThumbLY = LOAD16(buf[8], buf[9]); 156 ctx->capabilities.gamepad.sThumbRX = LOAD16(buf[10], buf[11]); 157 ctx->capabilities.gamepad.sThumbRY = LOAD16(buf[12], buf[13]); 158 } 159 ret = libusb_ctx->control_transfer(handle, 0xC1, 0x01, 0x00, 0x0, buf, 8, 100); 160 if (ret == 8) { 161 ctx->capabilities.vibration.wLeftMotorSpeed = buf[3] << 8; 162 ctx->capabilities.vibration.wRightMotorSpeed = buf[4] << 8; 163 } 164#ifdef DEBUG_XBOX_PROTOCOL 165 SDL_Log("Xbox 360 capabilities:"); 166 SDL_Log(" type: %02x", ctx->capabilities.type); 167 SDL_Log(" subType: %02x", ctx->capabilities.subType); 168 SDL_Log(" flags: %04x", ctx->capabilities.flags); 169 SDL_Log(" wButtons: %02x", ctx->capabilities.gamepad.wButtons); 170 SDL_Log(" bLeftTrigger: %02x", ctx->capabilities.gamepad.bLeftTrigger); 171 SDL_Log(" bRightTrigger: %02x", ctx->capabilities.gamepad.bRightTrigger); 172 SDL_Log(" sThumbLX: %02x", ctx->capabilities.gamepad.sThumbLX); 173 SDL_Log(" sThumbLY: %02x", ctx->capabilities.gamepad.sThumbLY); 174 SDL_Log(" sThumbRX: %02x", ctx->capabilities.gamepad.sThumbRX); 175 SDL_Log(" sThumbRY: %02x", ctx->capabilities.gamepad.sThumbRY); 176 SDL_Log(" wLeftMotorSpeed: %02x", ctx->capabilities.vibration.wLeftMotorSpeed); 177 SDL_Log(" wRightMotorSpeed: %02x", ctx->capabilities.vibration.wRightMotorSpeed); 178#endif 179 } 180 SDL_QuitLibUSB(); 181 } 182} 183#endif 184 185static bool HIDAPI_DriverXbox360_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol) 186{ 187 const int XB360W_IFACE_PROTOCOL = 129; // Wireless 188 189 if (vendor_id == USB_VENDOR_ASTRO && product_id == USB_PRODUCT_ASTRO_C40_XBOX360) { 190 // This is the ASTRO C40 in Xbox 360 mode 191 return true; 192 } 193 if (vendor_id == USB_VENDOR_NVIDIA) { 194 // This is the NVIDIA Shield controller which doesn't talk Xbox controller protocol 195 return false; 196 } 197 if ((vendor_id == USB_VENDOR_MICROSOFT && (product_id == USB_PRODUCT_XBOX360_WIRELESS_RECEIVER_THIRDPARTY2 || product_id == USB_PRODUCT_XBOX360_WIRELESS_RECEIVER)) || 198 (type == SDL_GAMEPAD_TYPE_XBOX360 && interface_protocol == XB360W_IFACE_PROTOCOL)) { 199 // This is the wireless dongle, which talks a different protocol 200 return false; 201 } 202 if (interface_number > 0) { 203 // This is the chatpad or other input interface, not the Xbox 360 interface 204 return false; 205 } 206#ifdef SDL_PLATFORM_MACOS 207 if (IsControlledBy360ControllerDriverMacOS(device)) { 208 // Wired Xbox controllers are handled by this driver, when they are 209 // controlled by the 360Controller driver available from: 210 // https://github.com/360Controller/360Controller/releases 211 return true; 212 } 213#endif 214#if defined(SDL_PLATFORM_MACOS) && defined(SDL_JOYSTICK_MFI) 215 if (SDL_IsJoystickSteamVirtualGamepad(vendor_id, product_id, version)) { 216 // GCController support doesn't work with the Steam Virtual Gamepad 217 return true; 218 } else { 219 // On macOS when it isn't controlled by the 360Controller driver and 220 // it doesn't look like a Steam virtual gamepad we should rely on 221 // GCController support instead. 222 return false; 223 } 224#else 225 return (type == SDL_GAMEPAD_TYPE_XBOX360); 226#endif 227} 228 229static bool SetSlotLED(SDL_hid_device *dev, Uint8 slot, bool on) 230{ 231 const bool blink = false; 232 Uint8 mode = on ? ((blink ? 0x02 : 0x06) + slot) : 0; 233 Uint8 led_packet[] = { 0x01, 0x03, 0x00 }; 234 235 led_packet[2] = mode; 236 if (SDL_hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) { 237 return false; 238 } 239 return true; 240} 241 242static void UpdateSlotLED(SDL_DriverXbox360_Context *ctx) 243{ 244 if (ctx->player_lights && ctx->player_index >= 0) { 245 SetSlotLED(ctx->device->dev, (ctx->player_index % 4), true); 246 } else { 247 SetSlotLED(ctx->device->dev, 0, false); 248 } 249} 250 251static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 252{ 253 SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)userdata; 254 bool player_lights = SDL_GetStringBoolean(hint, true); 255 256 if (player_lights != ctx->player_lights) { 257 ctx->player_lights = player_lights; 258 259 UpdateSlotLED(ctx); 260 HIDAPI_UpdateDeviceProperties(ctx->device); 261 } 262} 263 264static bool HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *device) 265{ 266 SDL_DriverXbox360_Context *ctx; 267 268 ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx)); 269 if (!ctx) { 270 return false; 271 } 272 ctx->device = device; 273#ifdef SDL_PLATFORM_MACOS 274 ctx->controlled_by_360controller = IsControlledBy360ControllerDriverMacOS(device); 275#endif 276 277 device->context = ctx; 278 279 device->type = SDL_GAMEPAD_TYPE_XBOX360; 280 281 if (SDL_IsJoystickSteamVirtualGamepad(device->vendor_id, device->product_id, device->version) && 282 device->product_string && SDL_strncmp(device->product_string, "GamePad-", 8) == 0) { 283 int slot = 0; 284 SDL_sscanf(device->product_string, "GamePad-%d", &slot); 285 device->steam_virtual_gamepad_slot = (slot - 1); 286 } 287 288 return HIDAPI_JoystickConnected(device, NULL); 289} 290 291static int HIDAPI_DriverXbox360_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) 292{ 293 return -1; 294} 295 296static void HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 297{ 298 SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context; 299 300 if (!ctx->joystick) { 301 return; 302 } 303 304 ctx->player_index = player_index; 305 306 UpdateSlotLED(ctx); 307} 308 309static bool HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 310{ 311 SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context; 312 313 SDL_AssertJoysticksLocked(); 314 315 ctx->joystick = joystick; 316 SDL_zeroa(ctx->last_state); 317 318 // Initialize player index (needed for setting LEDs) 319 ctx->player_index = SDL_GetJoystickPlayerIndex(joystick); 320 ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, true); 321 UpdateSlotLED(ctx); 322 323 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, 324 SDL_PlayerLEDHintChanged, ctx); 325 326 // Initialize the joystick capabilities 327 joystick->nbuttons = 11; 328 joystick->naxes = SDL_GAMEPAD_AXIS_COUNT; 329 joystick->nhats = 1; 330#ifdef HAVE_LIBUSB 331 FetchXInputCapabilities(device); 332#endif 333 return true; 334} 335 336static bool HIDAPI_DriverXbox360_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 337{ 338#ifdef SDL_PLATFORM_MACOS 339 if (((SDL_DriverXbox360_Context *)device->context)->controlled_by_360controller) { 340 // On macOS the 360Controller driver uses this short report, 341 // and we need to prefix it with a magic token so hidapi passes it through untouched 342 Uint8 rumble_packet[] = { 'M', 'A', 'G', 'I', 'C', '0', 0x00, 0x04, 0x00, 0x00 }; 343 rumble_packet[6 + 2] = (low_frequency_rumble >> 8); 344 rumble_packet[6 + 3] = (high_frequency_rumble >> 8); 345 if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) { 346 return SDL_SetError("Couldn't send rumble packet"); 347 } 348 return true; 349 } 350#endif 351 Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 352 353 rumble_packet[3] = (low_frequency_rumble >> 8); 354 rumble_packet[4] = (high_frequency_rumble >> 8); 355 356 if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) { 357 return SDL_SetError("Couldn't send rumble packet"); 358 } 359 return true; 360} 361 362static bool HIDAPI_DriverXbox360_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 363{ 364 return SDL_Unsupported(); 365} 366 367static Uint32 HIDAPI_DriverXbox360_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 368{ 369 SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context; 370 Uint32 result = SDL_JOYSTICK_CAP_RUMBLE; 371 372 if (ctx->player_lights) { 373 result |= SDL_JOYSTICK_CAP_PLAYER_LED; 374 } 375 return result; 376} 377 378static bool HIDAPI_DriverXbox360_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 379{ 380 return SDL_Unsupported(); 381} 382 383static bool HIDAPI_DriverXbox360_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size) 384{ 385 return SDL_Unsupported(); 386} 387 388static bool HIDAPI_DriverXbox360_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled) 389{ 390 return SDL_Unsupported(); 391} 392 393static void HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size) 394{ 395 Sint16 axis; 396#ifdef SDL_PLATFORM_MACOS 397 const bool invert_y_axes = false; 398#else 399 const bool invert_y_axes = true; 400#endif 401 Uint64 timestamp = SDL_GetTicksNS(); 402 403 if (ctx->last_state[2] != data[2]) { 404 Uint8 hat = 0; 405 406 if (data[2] & 0x01) { 407 hat |= SDL_HAT_UP; 408 } 409 if (data[2] & 0x02) { 410 hat |= SDL_HAT_DOWN; 411 } 412 if (data[2] & 0x04) { 413 hat |= SDL_HAT_LEFT; 414 } 415 if (data[2] & 0x08) { 416 hat |= SDL_HAT_RIGHT; 417 } 418 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 419 420 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[2] & 0x10) != 0)); 421 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[2] & 0x20) != 0)); 422 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[2] & 0x40) != 0)); 423 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[2] & 0x80) != 0)); 424 } 425 426 if (ctx->last_state[3] != data[3]) { 427 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[3] & 0x01) != 0)); 428 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[3] & 0x02) != 0)); 429 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[3] & 0x04) != 0)); 430 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[3] & 0x10) != 0)); 431 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[3] & 0x20) != 0)); 432 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[3] & 0x40) != 0)); 433 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[3] & 0x80) != 0)); 434 } 435 436 axis = ((int)data[4] * 257) - 32768; 437 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 438 axis = ((int)data[5] * 257) - 32768; 439 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); 440 axis = SDL_Swap16LE(*(Sint16 *)(&data[6])); 441 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); 442 axis = SDL_Swap16LE(*(Sint16 *)(&data[8])); 443 if (invert_y_axes) { 444 axis = ~axis; 445 } 446 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis); 447 axis = SDL_Swap16LE(*(Sint16 *)(&data[10])); 448 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); 449 axis = SDL_Swap16LE(*(Sint16 *)(&data[12])); 450 if (invert_y_axes) { 451 axis = ~axis; 452 } 453 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis); 454 455 SDL_memcpy(ctx->last_state, data, SDL_min((size_t)size, sizeof(ctx->last_state))); 456} 457 458static bool HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device) 459{ 460 SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context; 461 SDL_Joystick *joystick = NULL; 462 Uint8 data[USB_PACKET_LENGTH]; 463 int size = 0; 464 465 if (device->num_joysticks > 0) { 466 joystick = SDL_GetJoystickFromID(device->joysticks[0]); 467 } else { 468 return false; 469 } 470 471 while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) { 472#ifdef DEBUG_XBOX_PROTOCOL 473 HIDAPI_DumpPacket("Xbox 360 packet: size = %d", data, size); 474#endif 475 if (!joystick) { 476 continue; 477 } 478 479 if (data[0] == 0x00) { 480 HIDAPI_DriverXbox360_HandleStatePacket(joystick, ctx, data, size); 481 } 482 } 483 484 if (size < 0) { 485 // Read error, device is disconnected 486 HIDAPI_JoystickDisconnected(device, device->joysticks[0]); 487 } 488 return (size >= 0); 489} 490 491static void HIDAPI_DriverXbox360_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 492{ 493 SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context; 494 495 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, 496 SDL_PlayerLEDHintChanged, ctx); 497 498 ctx->joystick = NULL; 499} 500 501static void HIDAPI_DriverXbox360_FreeDevice(SDL_HIDAPI_Device *device) 502{ 503} 504 505SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 = { 506 SDL_HINT_JOYSTICK_HIDAPI_XBOX_360, 507 true, 508 HIDAPI_DriverXbox360_RegisterHints, 509 HIDAPI_DriverXbox360_UnregisterHints, 510 HIDAPI_DriverXbox360_IsEnabled, 511 HIDAPI_DriverXbox360_IsSupportedDevice, 512 HIDAPI_DriverXbox360_InitDevice, 513 HIDAPI_DriverXbox360_GetDevicePlayerIndex, 514 HIDAPI_DriverXbox360_SetDevicePlayerIndex, 515 HIDAPI_DriverXbox360_UpdateDevice, 516 HIDAPI_DriverXbox360_OpenJoystick, 517 HIDAPI_DriverXbox360_RumbleJoystick, 518 HIDAPI_DriverXbox360_RumbleJoystickTriggers, 519 HIDAPI_DriverXbox360_GetJoystickCapabilities, 520 HIDAPI_DriverXbox360_SetJoystickLED, 521 HIDAPI_DriverXbox360_SendJoystickEffect, 522 HIDAPI_DriverXbox360_SetJoystickSensorsEnabled, 523 HIDAPI_DriverXbox360_CloseJoystick, 524 HIDAPI_DriverXbox360_FreeDevice, 525}; 526 527#endif // SDL_JOYSTICK_HIDAPI_XBOX360 528 529#endif // SDL_JOYSTICK_HIDAPI 530
[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.