Atlas - SDL_hidapi_xboxone.c

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