Atlas - SDL_hidapi_xboxone.c
Home / ext / SDL / src / joystick / hidapi Lines: 1 | Size: 72370 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 "../SDL_sysjoystick.h" 27#include "SDL_hidapijoystick_c.h" 28#include "SDL_hidapi_rumble.h" 29#include "SDL_report_descriptor.h" 30 31#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE 32 33// Define this if you want verbose logging of the init sequence 34// #define DEBUG_JOYSTICK 35 36// Define this if you want to log all packets from the controller 37#if 0 38#define DEBUG_XBOX_PROTOCOL 39#endif 40 41#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) 42#define XBOX_ONE_DRIVER_ACTIVE 1 43#else 44#define XBOX_ONE_DRIVER_ACTIVE 0 45#endif 46 47#define CONTROLLER_IDENTIFY_TIMEOUT_MS 100 48#define CONTROLLER_PREPARE_INPUT_TIMEOUT_MS 50 49 50// Deadzone thresholds 51#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849 52#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689 53#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD -25058 // Uint8 30 scaled to Sint16 full range 54 55enum 56{ 57 SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON = 11 58}; 59 60// Power on 61static const Uint8 xbox_init_power_on[] = { 62 0x05, 0x20, 0x00, 0x01, 0x00 63}; 64// Enable LED 65static const Uint8 xbox_init_enable_led[] = { 66 0x0A, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14 67}; 68// This controller passed security check 69static const Uint8 xbox_init_security_passed[] = { 70 0x06, 0x20, 0x00, 0x02, 0x01, 0x00 71}; 72// Some PowerA controllers need to actually start the rumble motors 73static const Uint8 xbox_init_powera_rumble[] = { 74 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 75 0x1D, 0x1D, 0xFF, 0x00, 0x00 76}; 77// Setup rumble (not needed for Microsoft controllers, but it doesn't hurt) 78static const Uint8 xbox_init_rumble[] = { 79 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 80 0x00, 0x00, 0xFF, 0x00, 0xEB 81}; 82 83/* 84 * This specifies the selection of init packets that a gamepad 85 * will be sent on init *and* the order in which they will be 86 * sent. The correct sequence number will be added when the 87 * packet is going to be sent. 88 */ 89typedef struct 90{ 91 Uint16 vendor_id; 92 Uint16 product_id; 93 const Uint8 *data; 94 int size; 95} SDL_DriverXboxOne_InitPacket; 96 97static const SDL_DriverXboxOne_InitPacket xboxone_init_packets[] = { 98 { 0x0000, 0x0000, xbox_init_power_on, sizeof(xbox_init_power_on) }, 99 { 0x0000, 0x0000, xbox_init_enable_led, sizeof(xbox_init_enable_led) }, 100 { 0x0000, 0x0000, xbox_init_security_passed, sizeof(xbox_init_security_passed) }, 101 { 0x24c6, 0x541a, xbox_init_powera_rumble, sizeof(xbox_init_powera_rumble) }, 102 { 0x24c6, 0x542a, xbox_init_powera_rumble, sizeof(xbox_init_powera_rumble) }, 103 { 0x24c6, 0x543a, xbox_init_powera_rumble, sizeof(xbox_init_powera_rumble) }, 104 { 0x0000, 0x0000, xbox_init_rumble, sizeof(xbox_init_rumble) }, 105}; 106 107typedef enum 108{ 109 XBOX_ONE_INIT_STATE_ANNOUNCED, 110 XBOX_ONE_INIT_STATE_IDENTIFYING, 111 XBOX_ONE_INIT_STATE_STARTUP, 112 XBOX_ONE_INIT_STATE_PREPARE_INPUT, 113 XBOX_ONE_INIT_STATE_COMPLETE, 114} SDL_XboxOneInitState; 115 116typedef enum 117{ 118 XBOX_ONE_RUMBLE_STATE_IDLE, 119 XBOX_ONE_RUMBLE_STATE_QUEUED, 120 XBOX_ONE_RUMBLE_STATE_BUSY 121} SDL_XboxOneRumbleState; 122 123typedef struct 124{ 125 SDL_HIDAPI_Device *device; 126 Uint16 vendor_id; 127 Uint16 product_id; 128 SDL_XboxOneInitState init_state; 129 Uint64 start_time; 130 Uint8 sequence; 131 Uint64 send_time; 132 bool has_guide_packet; 133 bool has_color_led; 134 bool has_paddles; 135 bool has_unmapped_state; 136 bool has_trigger_rumble; 137 bool has_share_button; 138 bool has_separate_back_button; 139 bool has_separate_guide_button; 140 Uint8 last_paddle_state; 141 Uint8 low_frequency_rumble; 142 Uint8 high_frequency_rumble; 143 Uint8 left_trigger_rumble; 144 Uint8 right_trigger_rumble; 145 SDL_XboxOneRumbleState rumble_state; 146 Uint64 rumble_time; 147 bool rumble_pending; 148 SDL_ReportDescriptor *descriptor; 149 Uint32 last_buttons; 150 Uint8 last_state[USB_PACKET_LENGTH]; 151 Uint8 *chunk_buffer; 152 Uint32 chunk_length; 153} SDL_DriverXboxOne_Context; 154 155static bool ControllerHasColorLED(Uint16 vendor_id, Uint16 product_id) 156{ 157 return vendor_id == USB_VENDOR_MICROSOFT && product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2; 158} 159 160static bool ControllerHasPaddles(Uint16 vendor_id, Uint16 product_id) 161{ 162 return SDL_IsJoystickXboxOneElite(vendor_id, product_id); 163} 164 165static bool ControllerHasTriggerRumble(Uint16 vendor_id, Uint16 product_id) 166{ 167 // All the Microsoft Xbox One controllers have trigger rumble 168 if (vendor_id == USB_VENDOR_MICROSOFT) { 169 return true; 170 } 171 172 /* It turns out other controllers a mixed bag as to whether they support 173 trigger rumble or not, and when they do it's often a buzz rather than 174 the vibration of the Microsoft trigger rumble, so for now just pretend 175 that it is not available. 176 */ 177 return false; 178} 179 180static bool ControllerHasShareButton(Uint16 vendor_id, Uint16 product_id) 181{ 182 return SDL_IsJoystickXboxSeriesX(vendor_id, product_id); 183} 184 185static int GetHomeLEDBrightness(const char *hint) 186{ 187 const int MAX_VALUE = 50; 188 int value = 20; 189 190 if (hint && *hint) { 191 if (SDL_strchr(hint, '.') != NULL) { 192 value = (int)(MAX_VALUE * SDL_atof(hint)); 193 } else if (!SDL_GetStringBoolean(hint, true)) { 194 value = 0; 195 } 196 } 197 return value; 198} 199 200static void SetHomeLED(SDL_DriverXboxOne_Context *ctx, int value) 201{ 202 Uint8 led_packet[] = { 0x0A, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00 }; 203 204 if (value > 0) { 205 led_packet[5] = 0x01; 206 led_packet[6] = (Uint8)value; 207 } 208 SDL_HIDAPI_SendRumble(ctx->device, led_packet, sizeof(led_packet)); 209} 210 211static void SDLCALL SDL_HomeLEDHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) 212{ 213 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)userdata; 214 215 if (hint && *hint) { 216 SetHomeLED(ctx, GetHomeLEDBrightness(hint)); 217 } 218} 219 220static void SetInitState(SDL_DriverXboxOne_Context *ctx, SDL_XboxOneInitState state) 221{ 222#ifdef DEBUG_JOYSTICK 223 SDL_Log("Setting init state %d", state); 224#endif 225 ctx->init_state = state; 226} 227 228static Uint8 GetNextPacketSequence(SDL_DriverXboxOne_Context *ctx) 229{ 230 ++ctx->sequence; 231 if (!ctx->sequence) { 232 ctx->sequence = 1; 233 } 234 return ctx->sequence; 235} 236 237static bool SendProtocolPacket(SDL_DriverXboxOne_Context *ctx, const Uint8 *data, int size) 238{ 239#ifdef DEBUG_XBOX_PROTOCOL 240 HIDAPI_DumpPacket("Xbox One sending packet: size = %d", data, size); 241#endif 242 243 ctx->send_time = SDL_GetTicks(); 244 245 if (!SDL_HIDAPI_LockRumble()) { 246 return false; 247 } 248 if (SDL_HIDAPI_SendRumbleAndUnlock(ctx->device, data, size) != size) { 249 return false; 250 } 251 return true; 252} 253 254#if 0 255static bool SendSerialRequest(SDL_DriverXboxOne_Context *ctx) 256{ 257 Uint8 packet[] = { 0x1E, 0x20, 0x00, 0x01, 0x04 }; 258 259 packet[2] = GetNextPacketSequence(ctx); 260 261 /* Request the serial number 262 * Sending this should be done only after startup is complete. 263 * It will cancel the announce packet if sent before that, and will be 264 * ignored if sent during the startup sequence. 265 */ 266 if (!SendProtocolPacket(ctx, packet, sizeof(packet))) { 267 SDL_SetError("Couldn't send serial request packet"); 268 return false; 269 } 270 return true; 271} 272#endif 273 274static bool ControllerSendsAnnouncement(Uint16 vendor_id, Uint16 product_id) 275{ 276 // The PDP Rock Candy (PID 0x0246) and PowerA Fusion Pro 4 (PID 0x400b) 277 // don't send the announce packet on Linux for some reason. 278 // 279 // Just to be safe and cover future products, we'll always send the startup 280 // protocol sequence for PDP and PowerA controllers 281 if (vendor_id == USB_VENDOR_PDP || 282 vendor_id == USB_VENDOR_POWERA || 283 vendor_id == USB_VENDOR_POWERA_ALT) { 284 return false; 285 } 286 return true; 287} 288 289static bool SendIdentificationRequest(SDL_DriverXboxOne_Context *ctx) 290{ 291 // Request identification, sent in response to announce packet 292 Uint8 packet[] = { 293 0x04, 0x20, 0x00, 0x00 294 }; 295 296 packet[2] = GetNextPacketSequence(ctx); 297 298 if (!SendProtocolPacket(ctx, packet, sizeof(packet))) { 299 SDL_SetError("Couldn't send identification request packet"); 300 return false; 301 } 302 return true; 303} 304 305static bool SendControllerStartup(SDL_DriverXboxOne_Context *ctx) 306{ 307 Uint16 vendor_id = ctx->vendor_id; 308 Uint16 product_id = ctx->product_id; 309 Uint8 init_packet[USB_PACKET_LENGTH]; 310 size_t i; 311 312 for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) { 313 const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i]; 314 315 if (packet->vendor_id && (vendor_id != packet->vendor_id)) { 316 continue; 317 } 318 319 if (packet->product_id && (product_id != packet->product_id)) { 320 continue; 321 } 322 323 SDL_memcpy(init_packet, packet->data, packet->size); 324 init_packet[2] = GetNextPacketSequence(ctx); 325 326 if (init_packet[0] == 0x0A) { 327 // Get the initial brightness value 328 int brightness = GetHomeLEDBrightness(SDL_GetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED)); 329 init_packet[5] = (brightness > 0) ? 0x01 : 0x00; 330 init_packet[6] = (Uint8)brightness; 331 } 332 333 if (!SendProtocolPacket(ctx, init_packet, packet->size)) { 334 SDL_SetError("Couldn't send initialization packet"); 335 return false; 336 } 337 338 // Wait to process the rumble packet 339 if (packet->data == xbox_init_powera_rumble) { 340 SDL_Delay(10); 341 } 342 } 343 return true; 344} 345 346static void HIDAPI_DriverXboxOne_RegisterHints(SDL_HintCallback callback, void *userdata) 347{ 348 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata); 349 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE, callback, userdata); 350} 351 352static void HIDAPI_DriverXboxOne_UnregisterHints(SDL_HintCallback callback, void *userdata) 353{ 354 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata); 355 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE, callback, userdata); 356} 357 358static bool HIDAPI_DriverXboxOne_IsEnabled(void) 359{ 360 return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE, 361 SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT))); 362} 363 364static bool HIDAPI_DriverXboxOne_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) 365{ 366 static const int LIBUSB_CLASS_VENDOR_SPEC = 0xFF; 367 static const int XBONE_IFACE_SUBCLASS = 71; 368 static const int XBONE_IFACE_PROTOCOL = 208; 369 370#if defined(SDL_PLATFORM_MACOS) && defined(SDL_JOYSTICK_MFI) 371 if (!SDL_IsJoystickBluetoothXboxOne(vendor_id, product_id)) { 372 // On macOS we get a shortened version of the real report and 373 // you can't write output reports for wired controllers, so 374 // we'll just use the GCController support instead. 375 return false; 376 } 377#endif 378 if (interface_class && 379 (interface_class != LIBUSB_CLASS_VENDOR_SPEC || 380 interface_subclass != XBONE_IFACE_SUBCLASS || 381 interface_protocol != XBONE_IFACE_PROTOCOL)) { 382 // This isn't the Xbox gamepad interface 383 return false; 384 } 385 return (type == SDL_GAMEPAD_TYPE_XBOXONE); 386} 387 388static bool HIDAPI_DriverXboxOne_InitDevice(SDL_HIDAPI_Device *device) 389{ 390 SDL_DriverXboxOne_Context *ctx; 391 392 ctx = (SDL_DriverXboxOne_Context *)SDL_calloc(1, sizeof(*ctx)); 393 if (!ctx) { 394 return false; 395 } 396 ctx->device = device; 397 398 device->context = ctx; 399 400 Uint8 descriptor[1024]; 401 int descriptor_len = SDL_hid_get_report_descriptor(device->dev, descriptor, sizeof(descriptor)); 402 if (descriptor_len > 0) { 403 HIDAPI_DumpPacket("Xbox One report descriptor: size = %d", descriptor, descriptor_len); 404 405 ctx->descriptor = SDL_ParseReportDescriptor(descriptor, descriptor_len); 406 if (ctx->descriptor) { 407 // Collapse the buttons into a single field read 408 int field_count = ctx->descriptor->field_count; 409 DescriptorInputField *fields = ctx->descriptor->fields; 410 int button_count = 0; 411 for (int i = 0; i < field_count; ++i) { 412 DescriptorInputField *field = &fields[i]; 413 if (field->usage == MAKE_USAGE(USB_USAGEPAGE_BUTTON, 1)) { 414 Uint32 expected_usage = field->usage; 415 int expected_offset = field->bit_offset; 416 for (int j = i; j < field_count; ++j) { 417 DescriptorInputField *other = &fields[j]; 418 if (other->usage != expected_usage || 419 other->bit_offset != expected_offset) { 420 break; 421 } 422 423 ++button_count; 424 ++expected_usage; 425 ++expected_offset; 426 } 427 field->bit_size = button_count; 428 429 int next_field = i + button_count; 430 int fields_left = (field_count - next_field); 431 SDL_memmove(&fields[i+1], &fields[next_field], (fields_left * sizeof(fields[0]))); 432 ctx->descriptor->field_count -= (button_count - 1); 433 break; 434 } 435 } 436 if (!SDL_DescriptorHasUsage(ctx->descriptor, USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_X) || 437 !SDL_DescriptorHasUsage(ctx->descriptor, USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_Y) || 438 (button_count != 12 && button_count != 15)) { 439 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Xbox report descriptor missing expected usages, ignoring"); 440 SDL_DestroyDescriptor(ctx->descriptor); 441 ctx->descriptor = NULL; 442 } 443 } else { 444 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't parse Xbox report descriptor: %s", SDL_GetError()); 445 } 446 } else { 447 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Xbox report descriptor not available"); 448 } 449 450 ctx->vendor_id = device->vendor_id; 451 ctx->product_id = device->product_id; 452 ctx->start_time = SDL_GetTicks(); 453 ctx->sequence = 0; 454 ctx->has_color_led = ControllerHasColorLED(ctx->vendor_id, ctx->product_id); 455 ctx->has_paddles = ControllerHasPaddles(ctx->vendor_id, ctx->product_id); 456 ctx->has_trigger_rumble = ControllerHasTriggerRumble(ctx->vendor_id, ctx->product_id); 457 ctx->has_share_button = ControllerHasShareButton(ctx->vendor_id, ctx->product_id); 458 459 // Assume that the controller is correctly initialized when we start 460 if (!ControllerSendsAnnouncement(device->vendor_id, device->product_id)) { 461 // Jump into the startup sequence for this controller 462 ctx->init_state = XBOX_ONE_INIT_STATE_STARTUP; 463 } else { 464 ctx->init_state = XBOX_ONE_INIT_STATE_COMPLETE; 465 } 466 467#ifdef DEBUG_JOYSTICK 468 SDL_Log("Controller version: %d (0x%.4x)", device->version, device->version); 469#endif 470 471 device->type = SDL_GAMEPAD_TYPE_XBOXONE; 472 473 return HIDAPI_JoystickConnected(device, NULL); 474} 475 476static int HIDAPI_DriverXboxOne_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) 477{ 478 return -1; 479} 480 481static void HIDAPI_DriverXboxOne_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 482{ 483} 484 485static bool HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 486{ 487 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context; 488 489 SDL_AssertJoysticksLocked(); 490 491 ctx->low_frequency_rumble = 0; 492 ctx->high_frequency_rumble = 0; 493 ctx->left_trigger_rumble = 0; 494 ctx->right_trigger_rumble = 0; 495 ctx->rumble_state = XBOX_ONE_RUMBLE_STATE_IDLE; 496 ctx->rumble_time = 0; 497 ctx->rumble_pending = false; 498 SDL_zeroa(ctx->last_state); 499 500 // Initialize the joystick capabilities 501 joystick->nbuttons = 11; 502 if (ctx->has_share_button) { 503 joystick->nbuttons += 1; 504 } 505 if (ctx->has_paddles) { 506 joystick->nbuttons += 4; 507 } 508 joystick->naxes = SDL_GAMEPAD_AXIS_COUNT; 509 joystick->nhats = 1; 510 511 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED, 512 SDL_HomeLEDHintChanged, ctx); 513 return true; 514} 515 516static void HIDAPI_DriverXboxOne_RumbleSent(void *userdata) 517{ 518 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)userdata; 519 ctx->rumble_time = SDL_GetTicks(); 520} 521 522static bool HIDAPI_DriverXboxOne_UpdateRumble(SDL_DriverXboxOne_Context *ctx) 523{ 524 if (ctx->rumble_state == XBOX_ONE_RUMBLE_STATE_QUEUED) { 525 if (ctx->rumble_time) { 526 ctx->rumble_state = XBOX_ONE_RUMBLE_STATE_BUSY; 527 } 528 } 529 530 if (ctx->rumble_state == XBOX_ONE_RUMBLE_STATE_BUSY) { 531 const int RUMBLE_BUSY_TIME_MS = ctx->device->is_bluetooth ? 50 : 10; 532 if (SDL_GetTicks() >= (ctx->rumble_time + RUMBLE_BUSY_TIME_MS)) { 533 ctx->rumble_time = 0; 534 ctx->rumble_state = XBOX_ONE_RUMBLE_STATE_IDLE; 535 } 536 } 537 538 if (!ctx->rumble_pending) { 539 return true; 540 } 541 542 if (ctx->rumble_state != XBOX_ONE_RUMBLE_STATE_IDLE) { 543 return true; 544 } 545 546 // We're no longer pending, even if we fail to send the rumble below 547 ctx->rumble_pending = false; 548 549 if (!SDL_HIDAPI_LockRumble()) { 550 return false; 551 } 552 553 if (ctx->device->is_bluetooth) { 554 Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB }; 555 556 rumble_packet[2] = ctx->left_trigger_rumble; 557 rumble_packet[3] = ctx->right_trigger_rumble; 558 rumble_packet[4] = ctx->low_frequency_rumble; 559 rumble_packet[5] = ctx->high_frequency_rumble; 560 561 if (SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(ctx->device, rumble_packet, sizeof(rumble_packet), HIDAPI_DriverXboxOne_RumbleSent, ctx) != sizeof(rumble_packet)) { 562 return SDL_SetError("Couldn't send rumble packet"); 563 } 564 } else { 565 Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB }; 566 567 rumble_packet[6] = ctx->left_trigger_rumble; 568 rumble_packet[7] = ctx->right_trigger_rumble; 569 rumble_packet[8] = ctx->low_frequency_rumble; 570 rumble_packet[9] = ctx->high_frequency_rumble; 571 572 if (SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(ctx->device, rumble_packet, sizeof(rumble_packet), HIDAPI_DriverXboxOne_RumbleSent, ctx) != sizeof(rumble_packet)) { 573 return SDL_SetError("Couldn't send rumble packet"); 574 } 575 } 576 577 ctx->rumble_state = XBOX_ONE_RUMBLE_STATE_QUEUED; 578 579 return true; 580} 581 582static bool HIDAPI_DriverXboxOne_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 583{ 584 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context; 585 586 // Magnitude is 1..100 so scale the 16-bit input here 587 ctx->low_frequency_rumble = (Uint8)(low_frequency_rumble / 655); 588 ctx->high_frequency_rumble = (Uint8)(high_frequency_rumble / 655); 589 ctx->rumble_pending = true; 590 591 return HIDAPI_DriverXboxOne_UpdateRumble(ctx); 592} 593 594static bool HIDAPI_DriverXboxOne_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 595{ 596 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context; 597 598 if (!ctx->has_trigger_rumble) { 599 return SDL_Unsupported(); 600 } 601 602 // Magnitude is 1..100 so scale the 16-bit input here 603 ctx->left_trigger_rumble = (Uint8)(left_rumble / 655); 604 ctx->right_trigger_rumble = (Uint8)(right_rumble / 655); 605 ctx->rumble_pending = true; 606 607 return HIDAPI_DriverXboxOne_UpdateRumble(ctx); 608} 609 610static Uint32 HIDAPI_DriverXboxOne_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 611{ 612 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context; 613 Uint32 result = 0; 614 615 result |= SDL_JOYSTICK_CAP_RUMBLE; 616 if (ctx->has_trigger_rumble) { 617 result |= SDL_JOYSTICK_CAP_TRIGGER_RUMBLE; 618 } 619 620 if (ctx->has_color_led) { 621 result |= SDL_JOYSTICK_CAP_RGB_LED; 622 } 623 624 return result; 625} 626 627static bool HIDAPI_DriverXboxOne_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 628{ 629 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context; 630 631 if (ctx->has_color_led) { 632 Uint8 led_packet[] = { 0x0E, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 }; 633 634 led_packet[5] = 0x00; // Whiteness? Sets white intensity when RGB is 0, seems additive 635 led_packet[6] = red; 636 led_packet[7] = green; 637 led_packet[8] = blue; 638 639 if (SDL_HIDAPI_SendRumble(device, led_packet, sizeof(led_packet)) != sizeof(led_packet)) { 640 return SDL_SetError("Couldn't send LED packet"); 641 } 642 return true; 643 } else { 644 return SDL_Unsupported(); 645 } 646} 647 648static bool HIDAPI_DriverXboxOne_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size) 649{ 650 return SDL_Unsupported(); 651} 652 653static bool HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled) 654{ 655 return SDL_Unsupported(); 656} 657 658static void HIDAPI_DriverXboxOne_HandleBatteryState(SDL_Joystick *joystick, Uint32 flags) 659{ 660 bool on_usb = (((flags & 0x0C) >> 2) == 0); 661 SDL_PowerState state; 662 int percent = 0; 663 664 // Mapped percentage value from: 665 // https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/reference/input/gameinput/interfaces/igameinputdevice/methods/igameinputdevice_getbatterystate 666 switch (flags & 0x03) { 667 case 0: 668 percent = 10; 669 break; 670 case 1: 671 percent = 40; 672 break; 673 case 2: 674 percent = 70; 675 break; 676 case 3: 677 percent = 100; 678 break; 679 } 680 if (on_usb) { 681 state = SDL_POWERSTATE_CHARGING; 682 } else { 683 state = SDL_POWERSTATE_ON_BATTERY; 684 } 685 SDL_SendJoystickPowerInfo(joystick, state, percent); 686} 687 688static void HandleDescriptorAxis(Uint64 timestamp, SDL_Joystick *joystick, SDL_GamepadAxis axis, Uint32 value) 689{ 690 Sint16 axis_value = (Sint16)((int)value - 0x8000); 691 SDL_SendJoystickAxis(timestamp, joystick, axis, axis_value); 692} 693 694static void HandleDescriptorTrigger(Uint64 timestamp, SDL_Joystick *joystick, SDL_GamepadAxis axis, Uint32 value) 695{ 696 Sint16 axis_value = (Sint16)(((int)value * 64) - 32768); 697 if (axis_value == 32704) { 698 axis_value = 32767; 699 } 700 SDL_SendJoystickAxis(timestamp, joystick, axis, axis_value); 701} 702 703static bool HIDAPI_DriverXboxOne_HandleDescriptorReport(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size) 704{ 705 const SDL_ReportDescriptor *descriptor = ctx->descriptor; 706 Uint64 timestamp = SDL_GetTicksNS(); 707 708 // Skip the report ID 709 const Uint8 report_id = *data; 710 ++data; 711 --size; 712 713 for (int i = 0; i < descriptor->field_count; ++i) { 714 DescriptorInputField *field = &descriptor->fields[i]; 715 if (field->report_id != report_id) { 716 continue; 717 } 718 719 Uint32 value; 720 if (!SDL_ReadReportData(data, size, field->bit_offset, field->bit_size, &value)) { 721 continue; 722 } 723 724 switch (field->usage) { 725 case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_X): 726 { 727 HandleDescriptorAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, value); 728 break; 729 } 730 case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_Y): 731 { 732 HandleDescriptorAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, value); 733 break; 734 } 735 // Some controllers use Z+RZ for the right thumbstick and BRAKE and ACCEL for the left and right triggers 736 // and others use RX+RY for the right thumbstick and Z and RZ for the left and right triggers 737 case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_Z): 738 { 739 if (field->bit_size == 16) { 740 HandleDescriptorAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, value); 741 } else if (field->bit_size == 10) { 742 HandleDescriptorTrigger(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, value); 743 } 744 break; 745 } 746 case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_RX): 747 { 748 HandleDescriptorAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, value); 749 break; 750 } 751 case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_RY): 752 { 753 HandleDescriptorAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, value); 754 break; 755 } 756 case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_RZ): 757 { 758 if (field->bit_size == 16) { 759 HandleDescriptorAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, value); 760 } else if (field->bit_size == 10) { 761 HandleDescriptorTrigger(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, value); 762 } 763 break; 764 } 765 case MAKE_USAGE(USB_USAGEPAGE_SIMULATION, USB_USAGE_SIMULATION_BRAKE): 766 { 767 HandleDescriptorTrigger(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, value); 768 break; 769 } 770 case MAKE_USAGE(USB_USAGEPAGE_SIMULATION, USB_USAGE_SIMULATION_ACCELERATOR): 771 { 772 HandleDescriptorTrigger(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, value); 773 break; 774 } 775 case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_HAT): 776 { 777 Uint8 hat; 778 779 switch (value) { 780 case 1: 781 hat = SDL_HAT_UP; 782 break; 783 case 2: 784 hat = SDL_HAT_RIGHTUP; 785 break; 786 case 3: 787 hat = SDL_HAT_RIGHT; 788 break; 789 case 4: 790 hat = SDL_HAT_RIGHTDOWN; 791 break; 792 case 5: 793 hat = SDL_HAT_DOWN; 794 break; 795 case 6: 796 hat = SDL_HAT_LEFTDOWN; 797 break; 798 case 7: 799 hat = SDL_HAT_LEFT; 800 break; 801 case 8: 802 hat = SDL_HAT_LEFTUP; 803 break; 804 default: 805 hat = SDL_HAT_CENTERED; 806 break; 807 } 808 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 809 break; 810 } 811 case MAKE_USAGE(USB_USAGEPAGE_BUTTON, 1): 812 { 813 static const SDL_GamepadButton button_map_12[] = { 814 // 0x0001 815 SDL_GAMEPAD_BUTTON_SOUTH, 816 // 0x0002 817 SDL_GAMEPAD_BUTTON_EAST, 818 // 0x0004 819 SDL_GAMEPAD_BUTTON_WEST, 820 // 0x0008 821 SDL_GAMEPAD_BUTTON_NORTH, 822 // 0x0010 823 SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, 824 // 0x0020 825 SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, 826 // 0x0040 827 SDL_GAMEPAD_BUTTON_BACK, 828 // 0x0080 829 SDL_GAMEPAD_BUTTON_START, 830 // 0x0100 831 SDL_GAMEPAD_BUTTON_LEFT_STICK, 832 // 0x0200 833 SDL_GAMEPAD_BUTTON_RIGHT_STICK, 834 // 0x0400 835 SDL_GAMEPAD_BUTTON_GUIDE, 836 // 0x0800 837 SDL_GAMEPAD_BUTTON_INVALID, 838 }; 839 static const SDL_GamepadButton button_map_15[] = { 840 // 0x0001 841 SDL_GAMEPAD_BUTTON_SOUTH, 842 // 0x0002 843 SDL_GAMEPAD_BUTTON_EAST, 844 // 0x0004 845 SDL_GAMEPAD_BUTTON_INVALID, 846 // 0x0008 847 SDL_GAMEPAD_BUTTON_WEST, 848 // 0x0010 849 SDL_GAMEPAD_BUTTON_NORTH, 850 // 0x0020 851 SDL_GAMEPAD_BUTTON_INVALID, 852 // 0x0040 853 SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, 854 // 0x0080 855 SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, 856 // 0x0100 857 SDL_GAMEPAD_BUTTON_INVALID, 858 // 0x0200 859 SDL_GAMEPAD_BUTTON_INVALID, 860 // 0x0400 861 SDL_GAMEPAD_BUTTON_BACK, 862 // 0x0800 863 SDL_GAMEPAD_BUTTON_START, 864 // 0x1000 865 SDL_GAMEPAD_BUTTON_GUIDE, 866 // 0x2000 867 SDL_GAMEPAD_BUTTON_LEFT_STICK, 868 // 0x4000 869 SDL_GAMEPAD_BUTTON_RIGHT_STICK, 870 }; 871 872 if (value == ctx->last_buttons) { 873 break; 874 } 875 ctx->last_buttons = value; 876 877 const SDL_GamepadButton *button_map; 878 if (field->bit_size == 12) { 879 button_map = button_map_12; 880 } else if (field->bit_size == 15) { 881 button_map = button_map_15; 882 } else { 883 // Should never happen 884 break; 885 } 886 for (int button_index = 0; button_index < field->bit_size; ++button_index, value >>= 1) { 887 SDL_GamepadButton button = button_map[button_index]; 888 if (button == SDL_GAMEPAD_BUTTON_INVALID) { 889 continue; 890 } 891 if (button == SDL_GAMEPAD_BUTTON_BACK && ctx->has_separate_back_button) { 892 continue; 893 } 894 if (button == SDL_GAMEPAD_BUTTON_GUIDE && ctx->has_separate_guide_button) { 895 continue; 896 } 897 898 bool pressed = ((value & 1) != 0); 899 SDL_SendJoystickButton(timestamp, joystick, button, pressed); 900 } 901 break; 902 } 903 case MAKE_USAGE(USB_USAGEPAGE_CONSUMER, USB_USAGE_CONSUMER_AC_BACK): 904 { 905 bool pressed = (value != 0); 906 if (pressed) { 907 ctx->has_separate_back_button = true; 908 } 909 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, pressed); 910 break; 911 } 912 case MAKE_USAGE(USB_USAGEPAGE_CONSUMER, USB_USAGE_CONSUMER_AC_HOME): 913 { 914 bool pressed = (value != 0); 915 if (pressed) { 916 ctx->has_separate_guide_button = true; 917 } 918 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, pressed); 919 break; 920 } 921 case MAKE_USAGE(USB_USAGEPAGE_CONSUMER, USB_USAGE_CONSUMER_RECORD): 922 { 923 if (ctx->has_share_button) { 924 bool pressed = (value != 0); 925 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON, pressed); 926 } 927 break; 928 } 929 case MAKE_USAGE(USB_USAGEPAGE_CONSUMER, USB_USAGE_CONSUMER_ORDER_MOVIE): 930 { 931 // This value is the currently selected profile 932 ctx->has_unmapped_state = (value == 0); 933 break; 934 } 935 case MAKE_USAGE(USB_USAGEPAGE_CONSUMER, USB_USAGE_CONSUMER_ASSIGN_SELECTION): 936 { 937 if (ctx->has_paddles) { 938 if (!ctx->has_unmapped_state) { 939 value = 0; 940 } 941 942 Uint8 button = (Uint8)(SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON + ctx->has_share_button); // Next available button 943 SDL_SendJoystickButton(timestamp, joystick, button++, ((value & 0x1) != 0)); 944 SDL_SendJoystickButton(timestamp, joystick, button++, ((value & 0x2) != 0)); 945 SDL_SendJoystickButton(timestamp, joystick, button++, ((value & 0x4) != 0)); 946 SDL_SendJoystickButton(timestamp, joystick, button++, ((value & 0x8) != 0)); 947 } 948 break; 949 } 950 case MAKE_USAGE(USB_USAGEPAGE_DEVICE_CONTROLS, USB_USAGE_DEVICE_CONTROLS_BATTERY_STRENGTH): 951 { 952 HIDAPI_DriverXboxOne_HandleBatteryState(joystick, value); 953 break; 954 } 955 default: 956 break; 957 } 958 } 959 return true; 960} 961 962/* 963 * The Xbox One Elite controller with 5.13+ firmware sends the unmapped state in a separate packet. 964 * We can use this to send the paddle state when they aren't mapped 965 */ 966static void HIDAPI_DriverXboxOne_HandleUnmappedStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size) 967{ 968 Uint8 profile; 969 int paddle_index; 970 int button1_bit; 971 int button2_bit; 972 int button3_bit; 973 int button4_bit; 974 bool paddles_mapped; 975 Uint64 timestamp = SDL_GetTicksNS(); 976 977 if (size == 17) { 978 // XBox One Elite Series 2 979 paddle_index = 14; 980 button1_bit = 0x01; 981 button2_bit = 0x02; 982 button3_bit = 0x04; 983 button4_bit = 0x08; 984 profile = data[15]; 985 986 if (profile == 0) { 987 paddles_mapped = false; 988 } else if (SDL_memcmp(&data[0], &ctx->last_state[0], 14) == 0) { 989 // We're using a profile, but paddles aren't mapped 990 paddles_mapped = false; 991 } else { 992 // Something is mapped, we can't use the paddles 993 paddles_mapped = true; 994 } 995 996 } else { 997 // Unknown format 998 return; 999 } 1000#ifdef DEBUG_XBOX_PROTOCOL 1001 SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s", 1002 (data[paddle_index] & button1_bit) ? 1 : 0, 1003 (data[paddle_index] & button2_bit) ? 1 : 0, 1004 (data[paddle_index] & button3_bit) ? 1 : 0, 1005 (data[paddle_index] & button4_bit) ? 1 : 0, 1006 paddles_mapped ? "TRUE" : "FALSE"); 1007#endif 1008 1009 if (paddles_mapped) { 1010 // Respect that the paddles are being used for other controls and don't pass them on to the app 1011 data[paddle_index] = 0; 1012 } 1013 1014 if (ctx->last_paddle_state != data[paddle_index]) { 1015 Uint8 nButton = (Uint8)(SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON + ctx->has_share_button); // Next available button 1016 SDL_SendJoystickButton(timestamp, joystick, nButton++, ((data[paddle_index] & button1_bit) != 0)); 1017 SDL_SendJoystickButton(timestamp, joystick, nButton++, ((data[paddle_index] & button2_bit) != 0)); 1018 SDL_SendJoystickButton(timestamp, joystick, nButton++, ((data[paddle_index] & button3_bit) != 0)); 1019 SDL_SendJoystickButton(timestamp, joystick, nButton++, ((data[paddle_index] & button4_bit) != 0)); 1020 ctx->last_paddle_state = data[paddle_index]; 1021 } 1022 ctx->has_unmapped_state = true; 1023} 1024 1025static void HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size) 1026{ 1027 Sint16 axis; 1028 Uint64 timestamp = SDL_GetTicksNS(); 1029 1030 // Enable paddles on the Xbox Elite controller when connected over USB 1031 if (ctx->has_paddles && !ctx->has_unmapped_state && size == 46) { 1032 Uint8 packet[] = { 0x4d, 0x00, 0x00, 0x02, 0x07, 0x00 }; 1033 1034#ifdef DEBUG_JOYSTICK 1035 SDL_Log("Enabling paddles on XBox Elite 2"); 1036#endif 1037 SDL_HIDAPI_SendRumble(ctx->device, packet, sizeof(packet)); 1038 } 1039 1040 if (ctx->last_state[0] != data[0]) { 1041 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[0] & 0x04) != 0)); 1042 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[0] & 0x08) != 0)); 1043 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[0] & 0x10) != 0)); 1044 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[0] & 0x20) != 0)); 1045 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[0] & 0x40) != 0)); 1046 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[0] & 0x80) != 0)); 1047 } 1048 1049 if (ctx->last_state[1] != data[1]) { 1050 Uint8 hat = 0; 1051 1052 if (data[1] & 0x01) { 1053 hat |= SDL_HAT_UP; 1054 } 1055 if (data[1] & 0x02) { 1056 hat |= SDL_HAT_DOWN; 1057 } 1058 if (data[1] & 0x04) { 1059 hat |= SDL_HAT_LEFT; 1060 } 1061 if (data[1] & 0x08) { 1062 hat |= SDL_HAT_RIGHT; 1063 } 1064 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 1065 1066 if (ctx->vendor_id == USB_VENDOR_RAZER && ctx->product_id == USB_PRODUCT_RAZER_ATROX) { 1067 // The Razer Atrox has the right and left shoulder bits reversed 1068 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[1] & 0x20) != 0)); 1069 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[1] & 0x10) != 0)); 1070 } else { 1071 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[1] & 0x10) != 0)); 1072 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[1] & 0x20) != 0)); 1073 } 1074 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[1] & 0x40) != 0)); 1075 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[1] & 0x80) != 0)); 1076 } 1077 1078 if (ctx->has_share_button) { 1079 /* Xbox Series X firmware version 5.0, report is 32 bytes, share button is in byte 14 1080 * Xbox Series X firmware version 5.1, report is 40 bytes, share button is in byte 14 1081 * Xbox Series X firmware version 5.5, report is 44 bytes, share button is in byte 18 1082 * Victrix Gambit Tournament Controller, report is 46 bytes, share button is in byte 28 1083 * ThrustMaster eSwap PRO Controller Xbox, report is 60 bytes, share button is in byte 42 1084 */ 1085 if (size < 44) { 1086 if (ctx->last_state[14] != data[14]) { 1087 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON, ((data[14] & 0x01) != 0)); 1088 } 1089 } else if (size == 44) { 1090 if (ctx->last_state[18] != data[18]) { 1091 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON, ((data[18] & 0x01) != 0)); 1092 } 1093 } else if (size == 46) { 1094 if (ctx->last_state[28] != data[28]) { 1095 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON, ((data[28] & 0x01) != 0)); 1096 } 1097 } else if (size == 60) { 1098 if (ctx->last_state[42] != data[42]) { 1099 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON, ((data[42] & 0x01) != 0)); 1100 } 1101 } 1102 } 1103 1104 /* Xbox One S report is 14 bytes 1105 Xbox One Elite Series 1 report is 29 bytes, paddles in data[28], mode in data[28] & 0x10, both modes have mapped paddles by default 1106 Paddle bits: 1107 P3: 0x01 (A) P1: 0x02 (B) 1108 P4: 0x04 (X) P2: 0x08 (Y) 1109 Xbox One Elite Series 2 4.x firmware report is 34 bytes, paddles in data[14], mode in data[15], mode 0 has no mapped paddles by default 1110 Paddle bits: 1111 P3: 0x04 (A) P1: 0x01 (B) 1112 P4: 0x08 (X) P2: 0x02 (Y) 1113 Xbox One Elite Series 2 5.x firmware report is 46 bytes, paddles in data[18], mode in data[19], mode 0 has no mapped paddles by default 1114 Paddle bits: 1115 P3: 0x04 (A) P1: 0x01 (B) 1116 P4: 0x08 (X) P2: 0x02 (Y) 1117 Xbox One Elite Series 2 5.17+ firmware report is 47 bytes, paddles in data[14], mode in data[20], mode 0 has no mapped paddles by default 1118 Paddle bits: 1119 P3: 0x04 (A) P1: 0x01 (B) 1120 P4: 0x08 (X) P2: 0x02 (Y) 1121 */ 1122 if (ctx->has_paddles && !ctx->has_unmapped_state && (size == 29 || size == 34 || size == 46 || size == 47)) { 1123 int paddle_index; 1124 int button1_bit; 1125 int button2_bit; 1126 int button3_bit; 1127 int button4_bit; 1128 bool paddles_mapped; 1129 1130 if (size == 29) { 1131 // XBox One Elite Series 1 1132 paddle_index = 28; 1133 button1_bit = 0x02; 1134 button2_bit = 0x08; 1135 button3_bit = 0x01; 1136 button4_bit = 0x04; 1137 1138 // The mapped controller state is at offset 0, the raw state is at offset 14, compare them to see if the paddles are mapped 1139 paddles_mapped = (SDL_memcmp(&data[0], &data[14], 2) != 0); 1140 1141 } else if (size == 34) { 1142 // XBox One Elite Series 2 1143 paddle_index = 14; 1144 button1_bit = 0x01; 1145 button2_bit = 0x02; 1146 button3_bit = 0x04; 1147 button4_bit = 0x08; 1148 paddles_mapped = (data[15] != 0); 1149 1150 } else if (size == 46) { 1151 // XBox One Elite Series 2 1152 paddle_index = 18; 1153 button1_bit = 0x01; 1154 button2_bit = 0x02; 1155 button3_bit = 0x04; 1156 button4_bit = 0x08; 1157 paddles_mapped = (data[19] != 0); 1158 } else /* if (size == 47) */ { 1159 // XBox One Elite Series 2 1160 paddle_index = 14; 1161 button1_bit = 0x01; 1162 button2_bit = 0x02; 1163 button3_bit = 0x04; 1164 button4_bit = 0x08; 1165 paddles_mapped = (data[20] != 0); 1166 } 1167#ifdef DEBUG_XBOX_PROTOCOL 1168 SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s", 1169 (data[paddle_index] & button1_bit) ? 1 : 0, 1170 (data[paddle_index] & button2_bit) ? 1 : 0, 1171 (data[paddle_index] & button3_bit) ? 1 : 0, 1172 (data[paddle_index] & button4_bit) ? 1 : 0, 1173 paddles_mapped ? "TRUE" : "FALSE"); 1174#endif 1175 1176 if (paddles_mapped) { 1177 // Respect that the paddles are being used for other controls and don't pass them on to the app 1178 data[paddle_index] = 0; 1179 } 1180 1181 if (ctx->last_paddle_state != data[paddle_index]) { 1182 Uint8 nButton = (Uint8)(SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON + ctx->has_share_button); // Next available button 1183 SDL_SendJoystickButton(timestamp, joystick, nButton++, ((data[paddle_index] & button1_bit) != 0)); 1184 SDL_SendJoystickButton(timestamp, joystick, nButton++, ((data[paddle_index] & button2_bit) != 0)); 1185 SDL_SendJoystickButton(timestamp, joystick, nButton++, ((data[paddle_index] & button3_bit) != 0)); 1186 SDL_SendJoystickButton(timestamp, joystick, nButton++, ((data[paddle_index] & button4_bit) != 0)); 1187 ctx->last_paddle_state = data[paddle_index]; 1188 } 1189 } 1190 1191 axis = ((int)LOAD16(data[2], data[3]) * 64) - 32768; 1192 if (axis == 32704) { 1193 axis = 32767; 1194 } 1195 if (axis == -32768 && size == 26 && (data[18] & 0x80)) { 1196 axis = 32767; 1197 } 1198 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 1199 1200 axis = ((int)LOAD16(data[4], data[5]) * 64) - 32768; 1201 if (axis == -32768 && size == 26 && (data[18] & 0x40)) { 1202 axis = 32767; 1203 } 1204 if (axis == 32704) { 1205 axis = 32767; 1206 } 1207 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); 1208 1209 axis = LOAD16(data[6], data[7]); 1210 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); 1211 axis = LOAD16(data[8], data[9]); 1212 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, ~axis); 1213 axis = LOAD16(data[10], data[11]); 1214 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); 1215 axis = LOAD16(data[12], data[13]); 1216 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, ~axis); 1217 1218 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state))); 1219 1220 // We don't have the unmapped state for this packet 1221 ctx->has_unmapped_state = false; 1222} 1223 1224static void HIDAPI_DriverXboxOne_HandleStatusPacket(SDL_DriverXboxOne_Context *ctx, const Uint8 *data, int size) 1225{ 1226 if (ctx->init_state < XBOX_ONE_INIT_STATE_COMPLETE) { 1227 SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE); 1228 } 1229} 1230 1231static void HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, const Uint8 *data, int size) 1232{ 1233 Uint64 timestamp = SDL_GetTicksNS(); 1234 1235 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[0] & 0x01) != 0)); 1236} 1237 1238/* 1239 * Xbox One S with firmware 3.1.1221 uses a 16 byte packet and the GUIDE button in a separate packet 1240 */ 1241static void HIDAPI_DriverXboxOneBluetooth_HandleButtons16(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, const Uint8 *data, int size) 1242{ 1243 if (ctx->last_state[14] != data[14]) { 1244 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[14] & 0x01) != 0)); 1245 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[14] & 0x02) != 0)); 1246 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[14] & 0x04) != 0)); 1247 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[14] & 0x08) != 0)); 1248 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[14] & 0x10) != 0)); 1249 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[14] & 0x20) != 0)); 1250 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[14] & 0x40) != 0)); 1251 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[14] & 0x80) != 0)); 1252 } 1253 1254 if (ctx->last_state[15] != data[15]) { 1255 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[15] & 0x01) != 0)); 1256 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[15] & 0x02) != 0)); 1257 } 1258} 1259 1260/* 1261 * Xbox One S with firmware 4.8.1923 uses a 17 byte packet with BACK button in byte 16 and the GUIDE button in a separate packet (on Windows), or in byte 15 (on Linux) 1262 * Xbox One S with firmware 5.x uses a 17 byte packet with BACK and GUIDE buttons in byte 15 1263 * Xbox One Elite Series 2 with firmware 4.7.1872 uses a 55 byte packet with BACK button in byte 16, paddles starting at byte 33, and the GUIDE button in a separate packet 1264 * Xbox One Elite Series 2 with firmware 4.8.1908 uses a 33 byte packet with BACK button in byte 16, paddles starting at byte 17, and the GUIDE button in a separate packet 1265 * Xbox One Elite Series 2 with firmware 5.11.3112 uses a 19 byte packet with BACK and GUIDE buttons in byte 15 1266 * Xbox Series X with firmware 5.5.2641 uses a 17 byte packet with BACK and GUIDE buttons in byte 15, and SHARE button in byte 17 1267 */ 1268static void HIDAPI_DriverXboxOneBluetooth_HandleButtons(Uint64 timestamp, SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size) 1269{ 1270 if (ctx->last_state[14] != data[14]) { 1271 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[14] & 0x01) != 0)); 1272 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[14] & 0x02) != 0)); 1273 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[14] & 0x08) != 0)); 1274 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[14] & 0x10) != 0)); 1275 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[14] & 0x40) != 0)); 1276 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[14] & 0x80) != 0)); 1277 } 1278 1279 if (ctx->last_state[15] != data[15]) { 1280 if (!ctx->has_guide_packet) { 1281 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[15] & 0x10) != 0)); 1282 } 1283 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[15] & 0x08) != 0)); 1284 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[15] & 0x20) != 0)); 1285 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[15] & 0x40) != 0)); 1286 } 1287 1288 if (ctx->has_share_button) { 1289 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[15] & 0x04) != 0)); 1290 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON, ((data[16] & 0x01) != 0)); 1291 } else { 1292 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[15] & 0x04) || ((data[16] & 0x01)) != 0)); 1293 } 1294 1295 /* 1296 Paddle bits: 1297 P3: 0x04 (A) P1: 0x01 (B) 1298 P4: 0x08 (X) P2: 0x02 (Y) 1299 */ 1300 if (ctx->has_paddles && (size == 20 || size == 39 || size == 55)) { 1301 int paddle_index; 1302 int button1_bit; 1303 int button2_bit; 1304 int button3_bit; 1305 int button4_bit; 1306 bool paddles_mapped; 1307 1308 if (size == 55) { 1309 // Initial firmware for the Xbox Elite Series 2 controller 1310 paddle_index = 33; 1311 button1_bit = 0x01; 1312 button2_bit = 0x02; 1313 button3_bit = 0x04; 1314 button4_bit = 0x08; 1315 paddles_mapped = (data[35] != 0); 1316 } else if (size == 39) { 1317 // Updated firmware for the Xbox Elite Series 2 controller 1318 paddle_index = 17; 1319 button1_bit = 0x01; 1320 button2_bit = 0x02; 1321 button3_bit = 0x04; 1322 button4_bit = 0x08; 1323 paddles_mapped = (data[19] != 0); 1324 } else /* if (size == 20) */ { 1325 // Updated firmware for the Xbox Elite Series 2 controller (5.13+) 1326 paddle_index = 19; 1327 button1_bit = 0x01; 1328 button2_bit = 0x02; 1329 button3_bit = 0x04; 1330 button4_bit = 0x08; 1331 paddles_mapped = (data[17] != 0); 1332 } 1333 1334#ifdef DEBUG_XBOX_PROTOCOL 1335 SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s", 1336 (data[paddle_index] & button1_bit) ? 1 : 0, 1337 (data[paddle_index] & button2_bit) ? 1 : 0, 1338 (data[paddle_index] & button3_bit) ? 1 : 0, 1339 (data[paddle_index] & button4_bit) ? 1 : 0, 1340 paddles_mapped ? "TRUE" : "FALSE"); 1341#endif 1342 1343 if (paddles_mapped) { 1344 // Respect that the paddles are being used for other controls and don't pass them on to the app 1345 data[paddle_index] = 0; 1346 } 1347 1348 if (ctx->last_paddle_state != data[paddle_index]) { 1349 Uint8 nButton = SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON; // Next available button 1350 SDL_SendJoystickButton(timestamp, joystick, nButton++, ((data[paddle_index] & button1_bit) != 0)); 1351 SDL_SendJoystickButton(timestamp, joystick, nButton++, ((data[paddle_index] & button2_bit) != 0)); 1352 SDL_SendJoystickButton(timestamp, joystick, nButton++, ((data[paddle_index] & button3_bit) != 0)); 1353 SDL_SendJoystickButton(timestamp, joystick, nButton++, ((data[paddle_index] & button4_bit) != 0)); 1354 ctx->last_paddle_state = data[paddle_index]; 1355 } 1356 } 1357} 1358 1359static void HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size) 1360{ 1361 Sint16 axis; 1362 Uint64 timestamp = SDL_GetTicksNS(); 1363 1364 if (size == 16) { 1365 // Original Xbox One S, with separate report for guide button 1366 HIDAPI_DriverXboxOneBluetooth_HandleButtons16(timestamp, joystick, ctx, data, size); 1367 } else if (size > 16) { 1368 HIDAPI_DriverXboxOneBluetooth_HandleButtons(timestamp, joystick, ctx, data, size); 1369 } else { 1370#ifdef DEBUG_XBOX_PROTOCOL 1371 SDL_Log("Unknown Bluetooth state packet format"); 1372#endif 1373 return; 1374 } 1375 1376 if (ctx->last_state[13] != data[13]) { 1377 Uint8 hat; 1378 1379 switch (data[13]) { 1380 case 1: 1381 hat = SDL_HAT_UP; 1382 break; 1383 case 2: 1384 hat = SDL_HAT_RIGHTUP; 1385 break; 1386 case 3: 1387 hat = SDL_HAT_RIGHT; 1388 break; 1389 case 4: 1390 hat = SDL_HAT_RIGHTDOWN; 1391 break; 1392 case 5: 1393 hat = SDL_HAT_DOWN; 1394 break; 1395 case 6: 1396 hat = SDL_HAT_LEFTDOWN; 1397 break; 1398 case 7: 1399 hat = SDL_HAT_LEFT; 1400 break; 1401 case 8: 1402 hat = SDL_HAT_LEFTUP; 1403 break; 1404 default: 1405 hat = SDL_HAT_CENTERED; 1406 break; 1407 } 1408 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 1409 } 1410 1411 axis = ((int)LOAD16(data[9], data[10]) * 64) - 32768; 1412 if (axis == 32704) { 1413 axis = 32767; 1414 } 1415 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 1416 1417 axis = ((int)LOAD16(data[11], data[12]) * 64) - 32768; 1418 if (axis == 32704) { 1419 axis = 32767; 1420 } 1421 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); 1422 1423 axis = (int)(Uint16)LOAD16(data[1], data[2]) - 0x8000; 1424 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); 1425 axis = (int)(Uint16)LOAD16(data[3], data[4]) - 0x8000; 1426 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis); 1427 axis = (int)(Uint16)LOAD16(data[5], data[6]) - 0x8000; 1428 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); 1429 axis = (int)(Uint16)LOAD16(data[7], data[8]) - 0x8000; 1430 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis); 1431 1432 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state))); 1433} 1434 1435static void HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, const Uint8 *data, int size) 1436{ 1437 Uint64 timestamp = SDL_GetTicksNS(); 1438 1439 ctx->has_guide_packet = true; 1440 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[1] & 0x01) != 0)); 1441} 1442 1443static void HIDAPI_DriverXboxOneBluetooth_HandleBatteryPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, const Uint8 *data, int size) 1444{ 1445 HIDAPI_DriverXboxOne_HandleBatteryState(joystick, data[1]); 1446} 1447 1448static void HIDAPI_DriverXboxOne_HandleSerialIDPacket(SDL_DriverXboxOne_Context *ctx, const Uint8 *data, int size) 1449{ 1450 char serial[29]; 1451 int i; 1452 1453 for (i = 0; i < 14; ++i) { 1454 SDL_uitoa(data[2 + i], &serial[i * 2], 16); 1455 } 1456 serial[i * 2] = '\0'; 1457 1458#ifdef DEBUG_JOYSTICK 1459 SDL_Log("Setting serial number to %s", serial); 1460#endif 1461 HIDAPI_SetDeviceSerial(ctx->device, serial); 1462} 1463 1464static bool HIDAPI_DriverXboxOne_UpdateInitState(SDL_DriverXboxOne_Context *ctx) 1465{ 1466 SDL_XboxOneInitState prev_state; 1467 do { 1468 prev_state = ctx->init_state; 1469 1470 switch (ctx->init_state) { 1471 case XBOX_ONE_INIT_STATE_ANNOUNCED: 1472 if (XBOX_ONE_DRIVER_ACTIVE) { 1473 // The driver is taking care of identification 1474 SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE); 1475 } else { 1476 SendIdentificationRequest(ctx); 1477 SetInitState(ctx, XBOX_ONE_INIT_STATE_IDENTIFYING); 1478 } 1479 break; 1480 case XBOX_ONE_INIT_STATE_IDENTIFYING: 1481 if (SDL_GetTicks() >= (ctx->send_time + CONTROLLER_IDENTIFY_TIMEOUT_MS)) { 1482 // We haven't heard anything, let's move on 1483#ifdef DEBUG_JOYSTICK 1484 SDL_Log("Identification request timed out after %llu ms", (SDL_GetTicks() - ctx->send_time)); 1485#endif 1486 SetInitState(ctx, XBOX_ONE_INIT_STATE_STARTUP); 1487 } 1488 break; 1489 case XBOX_ONE_INIT_STATE_STARTUP: 1490 if (XBOX_ONE_DRIVER_ACTIVE) { 1491 // The driver is taking care of startup 1492 SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE); 1493 } else { 1494 SendControllerStartup(ctx); 1495 SetInitState(ctx, XBOX_ONE_INIT_STATE_PREPARE_INPUT); 1496 } 1497 break; 1498 case XBOX_ONE_INIT_STATE_PREPARE_INPUT: 1499 if (SDL_GetTicks() >= (ctx->send_time + CONTROLLER_PREPARE_INPUT_TIMEOUT_MS)) { 1500#ifdef DEBUG_JOYSTICK 1501 SDL_Log("Prepare input complete after %llu ms", (SDL_GetTicks() - ctx->send_time)); 1502#endif 1503 SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE); 1504 } 1505 break; 1506 case XBOX_ONE_INIT_STATE_COMPLETE: 1507 break; 1508 } 1509 1510 } while (ctx->init_state != prev_state); 1511 1512 return true; 1513} 1514 1515/* GIP protocol handling adapted under the Zlib license with permission from @medusalix: 1516 * https://github.com/medusalix/xone/blob/master/bus/protocol.h 1517 * https://github.com/medusalix/xone/blob/master/bus/protocol.c 1518 */ 1519#define GIP_HEADER_MIN_LENGTH 3 1520 1521// Internal commands 1522#define GIP_CMD_ACKNOWLEDGE 0x01 1523#define GIP_CMD_ANNOUNCE 0x02 1524#define GIP_CMD_STATUS 0x03 1525#define GIP_CMD_IDENTIFY 0x04 1526#define GIP_CMD_POWER 0x05 1527#define GIP_CMD_AUTHENTICATE 0x06 1528#define GIP_CMD_VIRTUAL_KEY 0x07 1529#define GIP_CMD_AUDIO_CONTROL 0x08 1530#define GIP_CMD_LED 0x0A 1531#define GIP_CMD_HID_REPORT 0x0B 1532#define GIP_CMD_FIRMWARE 0x0C 1533#define GIP_CMD_SERIAL_NUMBER 0x1E 1534#define GIP_CMD_AUDIO_SAMPLES 0x60 1535 1536// External commands 1537#define GIP_CMD_RUMBLE 0x09 1538#define GIP_CMD_UNMAPPED_STATE 0x0C 1539#define GIP_CMD_INPUT 0x20 1540 1541// Header option flags 1542#define GIP_OPT_ACKNOWLEDGE 0x10 1543#define GIP_OPT_INTERNAL 0x20 1544#define GIP_OPT_CHUNK_START 0x40 1545#define GIP_OPT_CHUNK 0x80 1546 1547#pragma pack(push, 1) 1548 1549struct gip_header { 1550 Uint8 command; 1551 Uint8 options; 1552 Uint8 sequence; 1553 Uint32 packet_length; 1554 Uint32 chunk_offset; 1555}; 1556 1557struct gip_pkt_acknowledge { 1558 Uint8 unknown; 1559 Uint8 command; 1560 Uint8 options; 1561 Uint16 length; 1562 Uint8 padding[2]; 1563 Uint16 remaining; 1564}; 1565 1566#pragma pack(pop) 1567 1568static int EncodeVariableInt(Uint8 *buf, Uint32 val) 1569{ 1570 int i; 1571 1572 for (i = 0; i < sizeof(val); i++) { 1573 buf[i] = (Uint8)val; 1574 if (val > 0x7F) { 1575 buf[i] |= 0x80; 1576 } 1577 1578 val >>= 7; 1579 if (!val) { 1580 break; 1581 } 1582 } 1583 return i + 1; 1584} 1585 1586static int DecodeVariableInt(const Uint8 *data, int len, void *out) 1587{ 1588 int i; 1589 Uint32 val = 0; 1590 1591 for (i = 0; i < sizeof(val) && i < len; i++) { 1592 val |= (data[i] & 0x7F) << (i * 7); 1593 1594 if (!(data[i] & 0x80)) { 1595 break; 1596 } 1597 } 1598 SDL_memcpy(out, &val, sizeof(val)); 1599 return i + 1; 1600} 1601 1602static int HIDAPI_GIP_GetActualHeaderLength(struct gip_header *hdr) 1603{ 1604 Uint32 pkt_len = hdr->packet_length; 1605 Uint32 chunk_offset = hdr->chunk_offset; 1606 int len = GIP_HEADER_MIN_LENGTH; 1607 1608 do { 1609 len++; 1610 pkt_len >>= 7; 1611 } while (pkt_len); 1612 1613 if (hdr->options & GIP_OPT_CHUNK) { 1614 while (chunk_offset) { 1615 len++; 1616 chunk_offset >>= 7; 1617 } 1618 } 1619 1620 return len; 1621} 1622 1623static int HIDAPI_GIP_GetHeaderLength(struct gip_header *hdr) 1624{ 1625 int len = HIDAPI_GIP_GetActualHeaderLength(hdr); 1626 1627 // Header length must be even 1628 return len + (len % 2); 1629} 1630 1631static void HIDAPI_GIP_EncodeHeader(struct gip_header *hdr, Uint8 *buf) 1632{ 1633 int hdr_len = 0; 1634 1635 buf[hdr_len++] = hdr->command; 1636 buf[hdr_len++] = hdr->options; 1637 buf[hdr_len++] = hdr->sequence; 1638 1639 hdr_len += EncodeVariableInt(buf + hdr_len, hdr->packet_length); 1640 1641 // Header length must be even 1642 if (HIDAPI_GIP_GetActualHeaderLength(hdr) % 2) { 1643 buf[hdr_len - 1] |= 0x80; 1644 buf[hdr_len++] = 0; 1645 } 1646 1647 if (hdr->options & GIP_OPT_CHUNK) { 1648 EncodeVariableInt(buf + hdr_len, hdr->chunk_offset); 1649 } 1650} 1651 1652static int HIDAPI_GIP_DecodeHeader(struct gip_header *hdr, const Uint8 *data, int len) 1653{ 1654 int hdr_len = 0; 1655 1656 hdr->command = data[hdr_len++]; 1657 hdr->options = data[hdr_len++]; 1658 hdr->sequence = data[hdr_len++]; 1659 hdr->packet_length = 0; 1660 hdr->chunk_offset = 0; 1661 1662 hdr_len += DecodeVariableInt(data + hdr_len, len - hdr_len, &hdr->packet_length); 1663 1664 if (hdr->options & GIP_OPT_CHUNK) { 1665 hdr_len += DecodeVariableInt(data + hdr_len, len - hdr_len, &hdr->chunk_offset); 1666 } 1667 return hdr_len; 1668} 1669 1670static bool HIDAPI_GIP_SendPacket(SDL_DriverXboxOne_Context *ctx, struct gip_header *hdr, const void *data) 1671{ 1672 Uint8 packet[USB_PACKET_LENGTH]; 1673 int hdr_len, size; 1674 1675 hdr_len = HIDAPI_GIP_GetHeaderLength(hdr); 1676 size = (hdr_len + hdr->packet_length); 1677 if (size > sizeof(packet)) { 1678 SDL_SetError("Couldn't send GIP packet, size (%d) too large", size); 1679 return false; 1680 } 1681 1682 if (!hdr->sequence) { 1683 hdr->sequence = GetNextPacketSequence(ctx); 1684 } 1685 1686 HIDAPI_GIP_EncodeHeader(hdr, packet); 1687 if (data) { 1688 SDL_memcpy(&packet[hdr_len], data, hdr->packet_length); 1689 } 1690 1691 if (!SendProtocolPacket(ctx, packet, size)) { 1692 SDL_SetError("Couldn't send protocol packet"); 1693 return false; 1694 } 1695 return true; 1696} 1697 1698static bool HIDAPI_GIP_AcknowledgePacket(SDL_DriverXboxOne_Context *ctx, struct gip_header *ack) 1699{ 1700 if (XBOX_ONE_DRIVER_ACTIVE) { 1701 // The driver is taking care of acks 1702 return true; 1703 } else { 1704 struct gip_header hdr; 1705 struct gip_pkt_acknowledge pkt; 1706 1707 SDL_zero(hdr); 1708 hdr.command = GIP_CMD_ACKNOWLEDGE; 1709 hdr.options = GIP_OPT_INTERNAL; 1710 hdr.sequence = ack->sequence; 1711 hdr.packet_length = sizeof(pkt); 1712 1713 SDL_zero(pkt); 1714 pkt.command = ack->command; 1715 pkt.options = GIP_OPT_INTERNAL; 1716 pkt.length = SDL_Swap16LE((Uint16)(ack->chunk_offset + ack->packet_length)); 1717 1718 if ((ack->options & GIP_OPT_CHUNK) && ctx->chunk_buffer) { 1719 pkt.remaining = SDL_Swap16LE((Uint16)(ctx->chunk_length - pkt.length)); 1720 } 1721 1722 return HIDAPI_GIP_SendPacket(ctx, &hdr, &pkt); 1723 } 1724} 1725 1726static bool HIDAPI_GIP_DispatchPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, struct gip_header *hdr, Uint8 *data, Uint32 size) 1727{ 1728 if ((hdr->options & 0x0F) != 0) { 1729 // This is a packet for a device plugged into the controller, skip it 1730 return true; 1731 } 1732 1733 if (hdr->options & GIP_OPT_INTERNAL) { 1734 switch (hdr->command) { 1735 case GIP_CMD_ACKNOWLEDGE: 1736 // Ignore this packet 1737 break; 1738 case GIP_CMD_ANNOUNCE: 1739 // Controller is connected and waiting for initialization 1740 /* The data bytes are: 1741 0x02 0x20 NN 0x1c, where NN is the packet sequence 1742 then 6 bytes of wireless MAC address 1743 then 2 bytes padding 1744 then 16-bit VID 1745 then 16-bit PID 1746 then 16-bit firmware version quartet AA.BB.CC.DD 1747 e.g. 0x05 0x00 0x05 0x00 0x51 0x0a 0x00 0x00 1748 is firmware version 5.5.2641.0, and product version 0x0505 = 1285 1749 then 8 bytes of unknown data 1750 */ 1751#ifdef DEBUG_JOYSTICK 1752 SDL_Log("Controller announce after %llu ms", (SDL_GetTicks() - ctx->start_time)); 1753#endif 1754 SetInitState(ctx, XBOX_ONE_INIT_STATE_ANNOUNCED); 1755 break; 1756 case GIP_CMD_STATUS: 1757 // Controller status update 1758 HIDAPI_DriverXboxOne_HandleStatusPacket(ctx, data, size); 1759 break; 1760 case GIP_CMD_IDENTIFY: 1761#ifdef DEBUG_JOYSTICK 1762 SDL_Log("Identification request completed after %llu ms", (SDL_GetTicks() - ctx->send_time)); 1763#endif 1764#ifdef DEBUG_XBOX_PROTOCOL 1765 HIDAPI_DumpPacket("Xbox One identification data: size = %d", data, size); 1766#endif 1767 SetInitState(ctx, XBOX_ONE_INIT_STATE_STARTUP); 1768 break; 1769 case GIP_CMD_POWER: 1770 // Ignore this packet 1771 break; 1772 case GIP_CMD_AUTHENTICATE: 1773 // Ignore this packet 1774 break; 1775 case GIP_CMD_VIRTUAL_KEY: 1776 if (!joystick) { 1777 break; 1778 } 1779 HIDAPI_DriverXboxOne_HandleModePacket(joystick, ctx, data, size); 1780 break; 1781 case GIP_CMD_SERIAL_NUMBER: 1782 /* If the packet starts with this: 1783 0x1E 0x30 0x00 0x10 0x04 0x00 1784 then the next 14 bytes are the controller serial number 1785 e.g. 0x30 0x39 0x37 0x31 0x32 0x33 0x33 0x32 0x33 0x35 0x34 0x30 0x33 0x36 1786 is serial number "3039373132333332333534303336" 1787 1788 The controller sends that in response to this request: 1789 0x1E 0x20 0x00 0x01 0x04 1790 */ 1791 HIDAPI_DriverXboxOne_HandleSerialIDPacket(ctx, data, size); 1792 break; 1793 default: 1794#ifdef DEBUG_JOYSTICK 1795 SDL_Log("Unknown Xbox One packet: 0x%.2x", hdr->command); 1796#endif 1797 break; 1798 } 1799 } else { 1800 switch (hdr->command) { 1801 case GIP_CMD_INPUT: 1802 if (ctx->init_state < XBOX_ONE_INIT_STATE_COMPLETE) { 1803 SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE); 1804 1805 // Ignore the first input, it may be spurious 1806#ifdef DEBUG_JOYSTICK 1807 SDL_Log("Controller ignoring spurious input"); 1808#endif 1809 break; 1810 } 1811 if (!joystick) { 1812 break; 1813 } 1814 HIDAPI_DriverXboxOne_HandleStatePacket(joystick, ctx, data, size); 1815 break; 1816 case GIP_CMD_UNMAPPED_STATE: 1817 if (!joystick) { 1818 break; 1819 } 1820 HIDAPI_DriverXboxOne_HandleUnmappedStatePacket(joystick, ctx, data, size); 1821 break; 1822 default: 1823#ifdef DEBUG_JOYSTICK 1824 SDL_Log("Unknown Xbox One packet: 0x%.2x", hdr->command); 1825#endif 1826 break; 1827 } 1828 } 1829 return true; 1830} 1831 1832static void HIDAPI_GIP_DestroyChunkBuffer(SDL_DriverXboxOne_Context *ctx) 1833{ 1834 if (ctx->chunk_buffer) { 1835 SDL_free(ctx->chunk_buffer); 1836 ctx->chunk_buffer = NULL; 1837 ctx->chunk_length = 0; 1838 } 1839} 1840 1841static bool HIDAPI_GIP_CreateChunkBuffer(SDL_DriverXboxOne_Context *ctx, Uint32 size) 1842{ 1843 HIDAPI_GIP_DestroyChunkBuffer(ctx); 1844 1845 ctx->chunk_buffer = (Uint8 *)SDL_malloc(size); 1846 if (ctx->chunk_buffer) { 1847 ctx->chunk_length = size; 1848 return true; 1849 } else { 1850 return false; 1851 } 1852} 1853 1854static bool HIDAPI_GIP_ProcessPacketChunked(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, struct gip_header *hdr, Uint8 *data) 1855{ 1856 bool result; 1857 1858 if (!ctx->chunk_buffer) { 1859 return false; 1860 } 1861 1862 if ((hdr->chunk_offset + hdr->packet_length) > ctx->chunk_length) { 1863 return false; 1864 } 1865 1866 if (hdr->packet_length) { 1867 SDL_memcpy(ctx->chunk_buffer + hdr->chunk_offset, data, hdr->packet_length); 1868 return true; 1869 } 1870 1871 result = HIDAPI_GIP_DispatchPacket(joystick, ctx, hdr, ctx->chunk_buffer, ctx->chunk_length); 1872 1873 HIDAPI_GIP_DestroyChunkBuffer(ctx); 1874 1875 return result; 1876} 1877 1878static bool HIDAPI_GIP_ProcessPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, struct gip_header *hdr, Uint8 *data) 1879{ 1880 if (hdr->options & GIP_OPT_CHUNK_START) { 1881 if (!HIDAPI_GIP_CreateChunkBuffer(ctx, hdr->chunk_offset)) { 1882 return false; 1883 } 1884 ctx->chunk_length = hdr->chunk_offset; 1885 1886 hdr->chunk_offset = 0; 1887 } 1888 1889 if (hdr->options & GIP_OPT_ACKNOWLEDGE) { 1890 if (!HIDAPI_GIP_AcknowledgePacket(ctx, hdr)) { 1891 return false; 1892 } 1893 } 1894 1895 if (hdr->options & GIP_OPT_CHUNK) { 1896 return HIDAPI_GIP_ProcessPacketChunked(joystick, ctx, hdr, data); 1897 } else { 1898 return HIDAPI_GIP_DispatchPacket(joystick, ctx, hdr, data, hdr->packet_length); 1899 } 1900} 1901 1902static bool HIDAPI_GIP_ProcessData(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size) 1903{ 1904 struct gip_header hdr; 1905 int hdr_len; 1906 1907 while (size > GIP_HEADER_MIN_LENGTH) { 1908 hdr_len = HIDAPI_GIP_DecodeHeader(&hdr, data, size); 1909 if ((hdr_len + hdr.packet_length) > (Uint32)size) { 1910 // On macOS we get a shortened version of the real report 1911 hdr.packet_length = (Uint32)(size - hdr_len); 1912 } 1913 1914 if (!HIDAPI_GIP_ProcessPacket(joystick, ctx, &hdr, data + hdr_len)) { 1915 return false; 1916 } 1917 1918 data += hdr_len + hdr.packet_length; 1919 size -= hdr_len + hdr.packet_length; 1920 } 1921 return true; 1922} 1923 1924static bool HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device) 1925{ 1926 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context; 1927 SDL_Joystick *joystick = NULL; 1928 Uint8 data[USB_PACKET_LENGTH]; 1929 int size; 1930 1931 if (device->num_joysticks > 0) { 1932 joystick = SDL_GetJoystickFromID(device->joysticks[0]); 1933 } else { 1934 return false; 1935 } 1936 1937 while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) { 1938#ifdef DEBUG_XBOX_PROTOCOL 1939 HIDAPI_DumpPacket("Xbox One packet: size = %d", data, size); 1940#endif 1941 if (ctx->descriptor) { 1942 if (!joystick) { 1943 break; 1944 } 1945 HIDAPI_DriverXboxOne_HandleDescriptorReport(joystick, ctx, data, size); 1946 } else if (device->is_bluetooth) { 1947 switch (data[0]) { 1948 case 0x01: 1949 if (!joystick) { 1950 break; 1951 } 1952 if (size >= 16) { 1953 HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(joystick, ctx, data, size); 1954 } else { 1955#ifdef DEBUG_JOYSTICK 1956 SDL_Log("Unknown Xbox One Bluetooth packet size: %d", size); 1957#endif 1958 } 1959 break; 1960 case 0x02: 1961 if (!joystick) { 1962 break; 1963 } 1964 HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(joystick, ctx, data, size); 1965 break; 1966 case 0x04: 1967 if (!joystick) { 1968 break; 1969 } 1970 HIDAPI_DriverXboxOneBluetooth_HandleBatteryPacket(joystick, ctx, data, size); 1971 break; 1972 default: 1973#ifdef DEBUG_JOYSTICK 1974 SDL_Log("Unknown Xbox One packet: 0x%.2x", data[0]); 1975#endif 1976 break; 1977 } 1978 } else { 1979 HIDAPI_GIP_ProcessData(joystick, ctx, data, size); 1980 } 1981 } 1982 1983 HIDAPI_DriverXboxOne_UpdateInitState(ctx); 1984 HIDAPI_DriverXboxOne_UpdateRumble(ctx); 1985 1986 if (size < 0) { 1987 // Read error, device is disconnected 1988 HIDAPI_JoystickDisconnected(device, device->joysticks[0]); 1989 } 1990 return (size >= 0); 1991} 1992 1993static void HIDAPI_DriverXboxOne_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 1994{ 1995 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context; 1996 1997 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED, 1998 SDL_HomeLEDHintChanged, ctx); 1999} 2000 2001static void HIDAPI_DriverXboxOne_FreeDevice(SDL_HIDAPI_Device *device) 2002{ 2003 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context; 2004 2005 SDL_DestroyDescriptor(ctx->descriptor); 2006 2007 HIDAPI_GIP_DestroyChunkBuffer(ctx); 2008} 2009 2010SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne = { 2011 SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE, 2012 true, 2013 HIDAPI_DriverXboxOne_RegisterHints, 2014 HIDAPI_DriverXboxOne_UnregisterHints, 2015 HIDAPI_DriverXboxOne_IsEnabled, 2016 HIDAPI_DriverXboxOne_IsSupportedDevice, 2017 HIDAPI_DriverXboxOne_InitDevice, 2018 HIDAPI_DriverXboxOne_GetDevicePlayerIndex, 2019 HIDAPI_DriverXboxOne_SetDevicePlayerIndex, 2020 HIDAPI_DriverXboxOne_UpdateDevice, 2021 HIDAPI_DriverXboxOne_OpenJoystick, 2022 HIDAPI_DriverXboxOne_RumbleJoystick, 2023 HIDAPI_DriverXboxOne_RumbleJoystickTriggers, 2024 HIDAPI_DriverXboxOne_GetJoystickCapabilities, 2025 HIDAPI_DriverXboxOne_SetJoystickLED, 2026 HIDAPI_DriverXboxOne_SendJoystickEffect, 2027 HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled, 2028 HIDAPI_DriverXboxOne_CloseJoystick, 2029 HIDAPI_DriverXboxOne_FreeDevice, 2030}; 2031 2032#endif // SDL_JOYSTICK_HIDAPI_XBOXONE 2033 2034#endif // SDL_JOYSTICK_HIDAPI 2035[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.