Atlas - SDL_hidapi_ps3.c

Home / ext / SDL / src / joystick / hidapi Lines: 1 | Size: 52627 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 30#ifdef SDL_JOYSTICK_HIDAPI_PS3 31 32// Define this if you want to log all packets from the controller 33// #define DEBUG_PS3_PROTOCOL 34 35#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8)) 36 37typedef enum 38{ 39 k_EPS3ReportIdState = 1, 40 k_EPS3ReportIdEffects = 1, 41} EPS3ReportId; 42 43typedef enum 44{ 45 k_EPS3SonySixaxisReportIdState = 0, 46 k_EPS3SonySixaxisReportIdEffects = 0, 47} EPS3SonySixaxisReportId; 48 49// Commands for Sony's sixaxis.sys Windows driver 50// All commands must be sent using 49-byte buffer containing output report 51// Byte 0 indicates reportId and must always be 0 52// Byte 1 indicates a command, supported values are specified below: 53typedef enum 54{ 55 // This command allows to set user LEDs. 56 // Bytes 5,6.7.8 contain mode for corresponding LED: 0 - LED is off, 1 - LED in on, 2 - LED is flashing. 57 // Bytes 9-16 specify 64-bit LED flash period in 100 ns units if some LED is flashing, otherwise not used. 58 k_EPS3SixaxisCommandSetLEDs = 1, 59 60 // This command allows to set left and right motors. 61 // Byte 5 is right motor duration (0-255) and byte 6, if not zero, activates right motor. Zero value disables right motor. 62 // Byte 7 is left motor duration (0-255) and byte 8 is left motor amplitude (0-255). 63 k_EPS3SixaxisCommandSetMotors = 2, 64 65 // This command allows to block/unblock setting device LEDs by applications. 66 // Byte 5 is used as parameter - any non-zero value blocks LEDs, zero value will unblock LEDs. 67 k_EPS3SixaxisCommandBlockLEDs = 3, 68 69 // This command refreshes driver settings. No parameters used. 70 // When sixaxis driver loads it reads 'CurrentDriverSetting' binary value from 'HKLM\System\CurrentControlSet\Services\sixaxis\Parameters' registry key. 71 // If the key is not present then default values are used. Sending this command forces sixaxis driver to re-read the registry and update driver settings. 72 k_EPS3SixaxisCommandRefreshDriverSetting = 9, 73 74 // This command clears current bluetooth pairing. No parameters used. 75 k_EPS3SixaxisCommandClearPairing = 10 76} EPS3SixaxisDriverCommands; 77 78typedef struct 79{ 80 SDL_HIDAPI_Device *device; 81 SDL_Joystick *joystick; 82 bool is_shanwan; 83 bool has_analog_buttons; 84 bool report_sensors; 85 bool effects_updated; 86 int player_index; 87 Uint8 rumble_left; 88 Uint8 rumble_right; 89 Uint8 last_state[USB_PACKET_LENGTH]; 90} SDL_DriverPS3_Context; 91 92static bool HIDAPI_DriverPS3_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size); 93 94static void HIDAPI_DriverPS3_RegisterHints(SDL_HintCallback callback, void *userdata) 95{ 96 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS3, callback, userdata); 97} 98 99static void HIDAPI_DriverPS3_UnregisterHints(SDL_HintCallback callback, void *userdata) 100{ 101 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS3, callback, userdata); 102} 103 104static bool HIDAPI_DriverPS3_IsEnabled(void) 105{ 106 bool default_value; 107 108#ifdef SDL_PLATFORM_MACOS 109 // This works well on macOS 110 default_value = true; 111#elif defined(SDL_PLATFORM_WIN32) 112 /* For official Sony driver (sixaxis.sys) use SDL_HINT_JOYSTICK_HIDAPI_PS3_SIXAXIS_DRIVER. 113 * 114 * See https://github.com/ViGEm/DsHidMini as an alternative driver 115 */ 116 default_value = false; 117#elif defined(SDL_PLATFORM_LINUX) 118 /* Linux drivers do a better job of managing the transition between 119 * USB and Bluetooth. There are also some quirks in communicating 120 * with PS3 controllers that have been implemented in SDL's hidapi 121 * for libusb, but are not possible to support using hidraw if the 122 * kernel doesn't already know about them. 123 */ 124 default_value = false; 125#else 126 // Untested, default off 127 default_value = false; 128#endif 129 130 if (default_value) { 131 default_value = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT); 132 } 133 return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, default_value); 134} 135 136static bool HIDAPI_DriverPS3_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) 137{ 138 if (vendor_id == USB_VENDOR_SONY && product_id == USB_PRODUCT_SONY_DS3) { 139 return true; 140 } 141 if (vendor_id == USB_VENDOR_SHANWAN && product_id == USB_PRODUCT_SHANWAN_DS3) { 142 return true; 143 } 144 return false; 145} 146 147static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length) 148{ 149 SDL_memset(report, 0, length); 150 report[0] = report_id; 151 return SDL_hid_get_feature_report(dev, report, length); 152} 153 154static int SendFeatureReport(SDL_hid_device *dev, Uint8 *report, size_t length) 155{ 156 return SDL_hid_send_feature_report(dev, report, length); 157} 158 159static bool HIDAPI_DriverPS3_InitDevice(SDL_HIDAPI_Device *device) 160{ 161 SDL_DriverPS3_Context *ctx; 162 bool is_shanwan = false; 163 164 if (device->vendor_id == USB_VENDOR_SONY && 165 SDL_strncasecmp(device->name, "ShanWan", 7) == 0) { 166 is_shanwan = true; 167 } 168 if (device->vendor_id == USB_VENDOR_SHANWAN || 169 device->vendor_id == USB_VENDOR_SHANWAN_ALT) { 170 is_shanwan = true; 171 } 172 173 ctx = (SDL_DriverPS3_Context *)SDL_calloc(1, sizeof(*ctx)); 174 if (!ctx) { 175 return false; 176 } 177 ctx->device = device; 178 ctx->is_shanwan = is_shanwan; 179 ctx->has_analog_buttons = true; 180 181 device->context = ctx; 182 183 // Set the controller into report mode over Bluetooth 184 if (device->is_bluetooth) { 185 Uint8 data[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 }; 186 187 SendFeatureReport(device->dev, data, sizeof(data)); 188 } 189 190 // Set the controller into report mode over USB 191 if (!device->is_bluetooth) { 192 Uint8 data[USB_PACKET_LENGTH]; 193 194 int size = ReadFeatureReport(device->dev, 0xf2, data, 17); 195 if (size < 0) { 196 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 197 "HIDAPI_DriverPS3_InitDevice(): Couldn't read feature report 0xf2"); 198 return false; 199 } 200#ifdef DEBUG_PS3_PROTOCOL 201 HIDAPI_DumpPacket("PS3 0xF2 packet: size = %d", data, size); 202#endif 203 size = ReadFeatureReport(device->dev, 0xf5, data, 8); 204 if (size < 0) { 205 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 206 "HIDAPI_DriverPS3_InitDevice(): Couldn't read feature report 0xf5"); 207 return false; 208 } 209#ifdef DEBUG_PS3_PROTOCOL 210 HIDAPI_DumpPacket("PS3 0xF5 packet: size = %d", data, size); 211#endif 212 if (!ctx->is_shanwan) { 213 // An output report could cause ShanWan controllers to rumble non-stop 214 SDL_hid_write(device->dev, data, 1); 215 } 216 } 217 218 device->type = SDL_GAMEPAD_TYPE_PS3; 219 HIDAPI_SetDeviceName(device, "PS3 Controller"); 220 221 return HIDAPI_JoystickConnected(device, NULL); 222} 223 224static int HIDAPI_DriverPS3_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) 225{ 226 return -1; 227} 228 229static bool HIDAPI_DriverPS3_UpdateEffects(SDL_HIDAPI_Device *device) 230{ 231 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 232 233 Uint8 effects[] = { 234 0x01, 0xff, 0x00, 0xff, 0x00, 235 0x00, 0x00, 0x00, 0x00, 0x00, 236 0xff, 0x27, 0x10, 0x00, 0x32, 237 0xff, 0x27, 0x10, 0x00, 0x32, 238 0xff, 0x27, 0x10, 0x00, 0x32, 239 0xff, 0x27, 0x10, 0x00, 0x32, 240 0x00, 0x00, 0x00, 0x00, 0x00 241 }; 242 243 effects[2] = ctx->rumble_right ? 1 : 0; 244 effects[4] = ctx->rumble_left; 245 246 effects[9] = (0x01 << (1 + (ctx->player_index % 4))); 247 248 return HIDAPI_DriverPS3_SendJoystickEffect(device, ctx->joystick, effects, sizeof(effects)); 249} 250 251static void HIDAPI_DriverPS3_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 252{ 253 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 254 255 if (!ctx) { 256 return; 257 } 258 259 ctx->player_index = player_index; 260 261 // This will set the new LED state based on the new player index 262 HIDAPI_DriverPS3_UpdateEffects(device); 263} 264 265static bool HIDAPI_DriverPS3_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 266{ 267 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 268 269 SDL_AssertJoysticksLocked(); 270 271 ctx->joystick = joystick; 272 ctx->effects_updated = false; 273 ctx->rumble_left = 0; 274 ctx->rumble_right = 0; 275 SDL_zeroa(ctx->last_state); 276 277 // Initialize player index (needed for setting LEDs) 278 ctx->player_index = SDL_GetJoystickPlayerIndex(joystick); 279 280 // Initialize the joystick capabilities 281 joystick->nbuttons = 11; 282 joystick->naxes = 6; 283 if (ctx->has_analog_buttons) { 284 joystick->naxes += 10; 285 } 286 joystick->nhats = 1; 287 288 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 100.0f); 289 290 return true; 291} 292 293static bool HIDAPI_DriverPS3_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 294{ 295 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 296 297 ctx->rumble_left = (low_frequency_rumble >> 8); 298 ctx->rumble_right = (high_frequency_rumble >> 8); 299 300 return HIDAPI_DriverPS3_UpdateEffects(device); 301} 302 303static bool HIDAPI_DriverPS3_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 304{ 305 return SDL_Unsupported(); 306} 307 308static Uint32 HIDAPI_DriverPS3_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 309{ 310 return SDL_JOYSTICK_CAP_RUMBLE; 311} 312 313static bool HIDAPI_DriverPS3_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 314{ 315 return SDL_Unsupported(); 316} 317 318static bool HIDAPI_DriverPS3_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size) 319{ 320 Uint8 data[49]; 321 int report_size, offset; 322 323 SDL_zeroa(data); 324 325 data[0] = k_EPS3ReportIdEffects; 326 report_size = sizeof(data); 327 offset = 1; 328 SDL_memcpy(&data[offset], effect, SDL_min((sizeof(data) - offset), (size_t)size)); 329 330 if (SDL_HIDAPI_SendRumble(device, data, report_size) != report_size) { 331 return SDL_SetError("Couldn't send rumble packet"); 332 } 333 return true; 334} 335 336static bool HIDAPI_DriverPS3_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled) 337{ 338 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 339 340 ctx->report_sensors = enabled; 341 342 return true; 343} 344 345static float HIDAPI_DriverPS3_ScaleAccel(Sint16 value) 346{ 347 // Accelerometer values are in big endian order 348 value = SDL_Swap16BE(value); 349 return ((float)(value - 511) / 113.0f) * SDL_STANDARD_GRAVITY; 350} 351 352static void HIDAPI_DriverPS3_HandleMiniStatePacket(SDL_Joystick *joystick, SDL_DriverPS3_Context *ctx, Uint8 *data, int size) 353{ 354 Sint16 axis; 355 Uint64 timestamp = SDL_GetTicksNS(); 356 357 if (ctx->last_state[4] != data[4]) { 358 Uint8 hat; 359 360 switch (data[4] & 0x0f) { 361 case 0: 362 hat = SDL_HAT_UP; 363 break; 364 case 1: 365 hat = SDL_HAT_RIGHTUP; 366 break; 367 case 2: 368 hat = SDL_HAT_RIGHT; 369 break; 370 case 3: 371 hat = SDL_HAT_RIGHTDOWN; 372 break; 373 case 4: 374 hat = SDL_HAT_DOWN; 375 break; 376 case 5: 377 hat = SDL_HAT_LEFTDOWN; 378 break; 379 case 6: 380 hat = SDL_HAT_LEFT; 381 break; 382 case 7: 383 hat = SDL_HAT_LEFTUP; 384 break; 385 default: 386 hat = SDL_HAT_CENTERED; 387 break; 388 } 389 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 390 391 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[4] & 0x10) != 0)); 392 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[4] & 0x20) != 0)); 393 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[4] & 0x40) != 0)); 394 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[4] & 0x80) != 0)); 395 } 396 397 if (ctx->last_state[5] != data[5]) { 398 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[5] & 0x01) != 0)); 399 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[5] & 0x02) != 0)); 400 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, (data[5] & 0x04) ? SDL_JOYSTICK_AXIS_MAX : SDL_JOYSTICK_AXIS_MIN); 401 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, (data[5] & 0x08) ? SDL_JOYSTICK_AXIS_MAX : SDL_JOYSTICK_AXIS_MIN); 402 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[5] & 0x10) != 0)); 403 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[5] & 0x20) != 0)); 404 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[5] & 0x40) != 0)); 405 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[5] & 0x80) != 0)); 406 } 407 408 axis = ((int)data[2] * 257) - 32768; 409 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); 410 axis = ((int)data[3] * 257) - 32768; 411 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis); 412 axis = ((int)data[0] * 257) - 32768; 413 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); 414 axis = ((int)data[1] * 257) - 32768; 415 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis); 416 417 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state))); 418} 419 420static void HIDAPI_DriverPS3_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverPS3_Context *ctx, Uint8 *data, int size) 421{ 422 Sint16 axis; 423 Uint64 timestamp = SDL_GetTicksNS(); 424 425 if (ctx->last_state[2] != data[2]) { 426 Uint8 hat = 0; 427 428 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[2] & 0x01) != 0)); 429 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[2] & 0x02) != 0)); 430 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[2] & 0x04) != 0)); 431 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[2] & 0x08) != 0)); 432 433 if (data[2] & 0x10) { 434 hat |= SDL_HAT_UP; 435 } 436 if (data[2] & 0x20) { 437 hat |= SDL_HAT_RIGHT; 438 } 439 if (data[2] & 0x40) { 440 hat |= SDL_HAT_DOWN; 441 } 442 if (data[2] & 0x80) { 443 hat |= SDL_HAT_LEFT; 444 } 445 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 446 } 447 448 if (ctx->last_state[3] != data[3]) { 449 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[3] & 0x04) != 0)); 450 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[3] & 0x08) != 0)); 451 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[3] & 0x10) != 0)); 452 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[3] & 0x20) != 0)); 453 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[3] & 0x40) != 0)); 454 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[3] & 0x80) != 0)); 455 } 456 457 if (ctx->last_state[4] != data[4]) { 458 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[4] & 0x01) != 0)); 459 } 460 461 axis = ((int)data[18] * 257) - 32768; 462 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 463 axis = ((int)data[19] * 257) - 32768; 464 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); 465 axis = ((int)data[6] * 257) - 32768; 466 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); 467 axis = ((int)data[7] * 257) - 32768; 468 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis); 469 axis = ((int)data[8] * 257) - 32768; 470 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); 471 axis = ((int)data[9] * 257) - 32768; 472 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis); 473 474 // Buttons are mapped as axes in the order they appear in the button enumeration 475 if (ctx->has_analog_buttons) { 476 static int button_axis_offsets[] = { 477 24, // SDL_GAMEPAD_BUTTON_SOUTH 478 23, // SDL_GAMEPAD_BUTTON_EAST 479 25, // SDL_GAMEPAD_BUTTON_WEST 480 22, // SDL_GAMEPAD_BUTTON_NORTH 481 0, // SDL_GAMEPAD_BUTTON_BACK 482 0, // SDL_GAMEPAD_BUTTON_GUIDE 483 0, // SDL_GAMEPAD_BUTTON_START 484 0, // SDL_GAMEPAD_BUTTON_LEFT_STICK 485 0, // SDL_GAMEPAD_BUTTON_RIGHT_STICK 486 20, // SDL_GAMEPAD_BUTTON_LEFT_SHOULDER 487 21, // SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER 488 14, // SDL_GAMEPAD_BUTTON_DPAD_UP 489 16, // SDL_GAMEPAD_BUTTON_DPAD_DOWN 490 17, // SDL_GAMEPAD_BUTTON_DPAD_LEFT 491 15, // SDL_GAMEPAD_BUTTON_DPAD_RIGHT 492 }; 493 Uint8 i, axis_index = 6; 494 495 for (i = 0; i < SDL_arraysize(button_axis_offsets); ++i) { 496 int offset = button_axis_offsets[i]; 497 if (!offset) { 498 // This button doesn't report as an axis 499 continue; 500 } 501 502 axis = ((int)data[offset] * 257) - 32768; 503 SDL_SendJoystickAxis(timestamp, joystick, axis_index, axis); 504 ++axis_index; 505 } 506 } 507 508 if (ctx->report_sensors) { 509 float sensor_data[3]; 510 511 sensor_data[0] = HIDAPI_DriverPS3_ScaleAccel(LOAD16(data[41], data[42])); 512 sensor_data[1] = -HIDAPI_DriverPS3_ScaleAccel(LOAD16(data[45], data[46])); 513 sensor_data[2] = -HIDAPI_DriverPS3_ScaleAccel(LOAD16(data[43], data[44])); 514 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, timestamp, sensor_data, SDL_arraysize(sensor_data)); 515 } 516 517 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state))); 518} 519 520static bool HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device) 521{ 522 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 523 SDL_Joystick *joystick = NULL; 524 Uint8 data[USB_PACKET_LENGTH]; 525 int size; 526 527 if (device->num_joysticks > 0) { 528 joystick = SDL_GetJoystickFromID(device->joysticks[0]); 529 } else { 530 return false; 531 } 532 533 while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) { 534#ifdef DEBUG_PS3_PROTOCOL 535 HIDAPI_DumpPacket("PS3 packet: size = %d", data, size); 536#endif 537 if (!joystick) { 538 continue; 539 } 540 541 if (size == 7) { 542 // Seen on a ShanWan PS2 -> PS3 USB converter 543 HIDAPI_DriverPS3_HandleMiniStatePacket(joystick, ctx, data, size); 544 545 // Wait for the first report to set the LED state after the controller stops blinking 546 if (!ctx->effects_updated) { 547 HIDAPI_DriverPS3_UpdateEffects(device); 548 ctx->effects_updated = true; 549 } 550 continue; 551 } 552 553 switch (data[0]) { 554 case k_EPS3ReportIdState: 555 if (data[1] == 0xFF) { 556 // Invalid data packet, ignore 557 break; 558 } 559 HIDAPI_DriverPS3_HandleStatePacket(joystick, ctx, data, size); 560 561 // Wait for the first report to set the LED state after the controller stops blinking 562 if (!ctx->effects_updated) { 563 HIDAPI_DriverPS3_UpdateEffects(device); 564 ctx->effects_updated = true; 565 } 566 break; 567 default: 568#ifdef DEBUG_JOYSTICK 569 SDL_Log("Unknown PS3 packet: 0x%.2x", data[0]); 570#endif 571 break; 572 } 573 } 574 575 if (size < 0) { 576 // Read error, device is disconnected 577 HIDAPI_JoystickDisconnected(device, device->joysticks[0]); 578 } 579 return (size >= 0); 580} 581 582static void HIDAPI_DriverPS3_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 583{ 584 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 585 586 ctx->joystick = NULL; 587} 588 589static void HIDAPI_DriverPS3_FreeDevice(SDL_HIDAPI_Device *device) 590{ 591} 592 593SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS3 = { 594 SDL_HINT_JOYSTICK_HIDAPI_PS3, 595 true, 596 HIDAPI_DriverPS3_RegisterHints, 597 HIDAPI_DriverPS3_UnregisterHints, 598 HIDAPI_DriverPS3_IsEnabled, 599 HIDAPI_DriverPS3_IsSupportedDevice, 600 HIDAPI_DriverPS3_InitDevice, 601 HIDAPI_DriverPS3_GetDevicePlayerIndex, 602 HIDAPI_DriverPS3_SetDevicePlayerIndex, 603 HIDAPI_DriverPS3_UpdateDevice, 604 HIDAPI_DriverPS3_OpenJoystick, 605 HIDAPI_DriverPS3_RumbleJoystick, 606 HIDAPI_DriverPS3_RumbleJoystickTriggers, 607 HIDAPI_DriverPS3_GetJoystickCapabilities, 608 HIDAPI_DriverPS3_SetJoystickLED, 609 HIDAPI_DriverPS3_SendJoystickEffect, 610 HIDAPI_DriverPS3_SetJoystickSensorsEnabled, 611 HIDAPI_DriverPS3_CloseJoystick, 612 HIDAPI_DriverPS3_FreeDevice, 613}; 614 615static bool HIDAPI_DriverPS3ThirdParty_IsEnabled(void) 616{ 617 return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, 618 SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, 619 SDL_HIDAPI_DEFAULT)); 620} 621 622static bool HIDAPI_DriverPS3ThirdParty_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) 623{ 624 Uint8 data[USB_PACKET_LENGTH]; 625 int size; 626 627 if (vendor_id == USB_VENDOR_LOGITECH && 628 product_id == USB_PRODUCT_LOGITECH_CHILLSTREAM) { 629 return true; 630 } 631 632 if ((type == SDL_GAMEPAD_TYPE_PS3 && vendor_id != USB_VENDOR_SONY) || 633 HIDAPI_SupportsPlaystationDetection(vendor_id, product_id)) { 634 if (device && device->dev) { 635 size = ReadFeatureReport(device->dev, 0x03, data, sizeof(data)); 636 if (size == 8 && data[2] == 0x26) { 637 // Supported third party controller 638 return true; 639 } else { 640 return false; 641 } 642 } else { 643 // Might be supported by this driver, enumerate and find out 644 return true; 645 } 646 } 647 return false; 648} 649 650static bool HIDAPI_DriverPS3ThirdParty_InitDevice(SDL_HIDAPI_Device *device) 651{ 652 SDL_DriverPS3_Context *ctx; 653 654 ctx = (SDL_DriverPS3_Context *)SDL_calloc(1, sizeof(*ctx)); 655 if (!ctx) { 656 return false; 657 } 658 ctx->device = device; 659 if (device->vendor_id == USB_VENDOR_SWITCH && device->product_id == USB_PRODUCT_SWITCH_RETROBIT_CONTROLLER) { 660 ctx->has_analog_buttons = false; 661 } else { 662 ctx->has_analog_buttons = true; 663 } 664 665 device->context = ctx; 666 667 device->type = SDL_GAMEPAD_TYPE_PS3; 668 669 if (device->vendor_id == USB_VENDOR_LOGITECH && 670 device->product_id == USB_PRODUCT_LOGITECH_CHILLSTREAM) { 671 HIDAPI_SetDeviceName(device, "Logitech ChillStream"); 672 } 673 674 return HIDAPI_JoystickConnected(device, NULL); 675} 676 677static int HIDAPI_DriverPS3ThirdParty_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) 678{ 679 return -1; 680} 681 682static void HIDAPI_DriverPS3ThirdParty_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 683{ 684} 685 686static bool HIDAPI_DriverPS3ThirdParty_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 687{ 688 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 689 690 SDL_AssertJoysticksLocked(); 691 692 ctx->joystick = joystick; 693 SDL_zeroa(ctx->last_state); 694 695 // Initialize the joystick capabilities 696 joystick->nbuttons = 11; 697 joystick->naxes = 6; 698 if (ctx->has_analog_buttons) { 699 joystick->naxes += 10; 700 } 701 joystick->nhats = 1; 702 703 if (device->vendor_id == USB_VENDOR_SWITCH && device->product_id == USB_PRODUCT_SWITCH_RETROBIT_CONTROLLER) { 704 // This is a wireless controller using a USB dongle 705 joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRELESS; 706 } 707 708 return true; 709} 710 711static bool HIDAPI_DriverPS3ThirdParty_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 712{ 713 return SDL_Unsupported(); 714} 715 716static bool HIDAPI_DriverPS3ThirdParty_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 717{ 718 return SDL_Unsupported(); 719} 720 721static Uint32 HIDAPI_DriverPS3ThirdParty_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 722{ 723 return 0; 724} 725 726static bool HIDAPI_DriverPS3ThirdParty_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 727{ 728 return SDL_Unsupported(); 729} 730 731static bool HIDAPI_DriverPS3ThirdParty_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size) 732{ 733 return SDL_Unsupported(); 734} 735 736static bool HIDAPI_DriverPS3ThirdParty_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled) 737{ 738 return SDL_Unsupported(); 739} 740 741static void HIDAPI_DriverPS3ThirdParty_HandleStatePacket18(SDL_Joystick *joystick, SDL_DriverPS3_Context *ctx, Uint8 *data, int size) 742{ 743 Sint16 axis; 744 Uint64 timestamp = SDL_GetTicksNS(); 745 746 if (ctx->last_state[0] != data[0]) { 747 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[0] & 0x01) != 0)); 748 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[0] & 0x02) != 0)); 749 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[0] & 0x04) != 0)); 750 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[0] & 0x08) != 0)); 751 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[0] & 0x10) != 0)); 752 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[0] & 0x20) != 0)); 753 } 754 755 if (ctx->last_state[1] != data[1]) { 756 Uint8 hat; 757 758 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[1] & 0x01) != 0)); 759 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[1] & 0x02) != 0)); 760 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[1] & 0x04) != 0)); 761 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[1] & 0x08) != 0)); 762 763 switch (data[1] >> 4) { 764 case 0: 765 hat = SDL_HAT_UP; 766 break; 767 case 1: 768 hat = SDL_HAT_RIGHTUP; 769 break; 770 case 2: 771 hat = SDL_HAT_RIGHT; 772 break; 773 case 3: 774 hat = SDL_HAT_RIGHTDOWN; 775 break; 776 case 4: 777 hat = SDL_HAT_DOWN; 778 break; 779 case 5: 780 hat = SDL_HAT_LEFTDOWN; 781 break; 782 case 6: 783 hat = SDL_HAT_LEFT; 784 break; 785 case 7: 786 hat = SDL_HAT_LEFTUP; 787 break; 788 default: 789 hat = SDL_HAT_CENTERED; 790 break; 791 } 792 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 793 } 794 795 axis = ((int)data[16] * 257) - 32768; 796 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 797 axis = ((int)data[17] * 257) - 32768; 798 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); 799 axis = ((int)data[2] * 257) - 32768; 800 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); 801 axis = ((int)data[3] * 257) - 32768; 802 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis); 803 axis = ((int)data[4] * 257) - 32768; 804 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); 805 axis = ((int)data[5] * 257) - 32768; 806 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis); 807 808 // Buttons are mapped as axes in the order they appear in the button enumeration 809 if (ctx->has_analog_buttons) { 810 static int button_axis_offsets[] = { 811 12, // SDL_GAMEPAD_BUTTON_SOUTH 812 11, // SDL_GAMEPAD_BUTTON_EAST 813 13, // SDL_GAMEPAD_BUTTON_WEST 814 10, // SDL_GAMEPAD_BUTTON_NORTH 815 0, // SDL_GAMEPAD_BUTTON_BACK 816 0, // SDL_GAMEPAD_BUTTON_GUIDE 817 0, // SDL_GAMEPAD_BUTTON_START 818 0, // SDL_GAMEPAD_BUTTON_LEFT_STICK 819 0, // SDL_GAMEPAD_BUTTON_RIGHT_STICK 820 14, // SDL_GAMEPAD_BUTTON_LEFT_SHOULDER 821 15, // SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER 822 8, // SDL_GAMEPAD_BUTTON_DPAD_UP 823 9, // SDL_GAMEPAD_BUTTON_DPAD_DOWN 824 7, // SDL_GAMEPAD_BUTTON_DPAD_LEFT 825 6, // SDL_GAMEPAD_BUTTON_DPAD_RIGHT 826 }; 827 Uint8 i, axis_index = 6; 828 829 for (i = 0; i < SDL_arraysize(button_axis_offsets); ++i) { 830 int offset = button_axis_offsets[i]; 831 if (!offset) { 832 // This button doesn't report as an axis 833 continue; 834 } 835 836 axis = ((int)data[offset] * 257) - 32768; 837 SDL_SendJoystickAxis(timestamp, joystick, axis_index, axis); 838 ++axis_index; 839 } 840 } 841 842 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state))); 843} 844 845static void HIDAPI_DriverPS3ThirdParty_HandleStatePacket19(SDL_Joystick *joystick, SDL_DriverPS3_Context *ctx, Uint8 *data, int size) 846{ 847 Sint16 axis; 848 Uint64 timestamp = SDL_GetTicksNS(); 849 850 if (ctx->last_state[0] != data[0]) { 851 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[0] & 0x01) != 0)); 852 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[0] & 0x02) != 0)); 853 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[0] & 0x04) != 0)); 854 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[0] & 0x08) != 0)); 855 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[0] & 0x10) != 0)); 856 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[0] & 0x20) != 0)); 857 } 858 859 if (ctx->last_state[1] != data[1]) { 860 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[1] & 0x01) != 0)); 861 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[1] & 0x02) != 0)); 862 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[1] & 0x04) != 0)); 863 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[1] & 0x08) != 0)); 864 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[1] & 0x10) != 0)); 865 } 866 867 if (ctx->device->vendor_id == USB_VENDOR_SAITEK && ctx->device->product_id == USB_PRODUCT_SAITEK_CYBORG_V3) { 868 // Cyborg V.3 Rumble Pad doesn't set the dpad bits as expected, so use the axes instead 869 Uint8 hat = 0; 870 871 if (data[7]) { 872 hat |= SDL_HAT_RIGHT; 873 } 874 if (data[8]) { 875 hat |= SDL_HAT_LEFT; 876 } 877 if (data[9]) { 878 hat |= SDL_HAT_UP; 879 } 880 if (data[10]) { 881 hat |= SDL_HAT_DOWN; 882 } 883 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 884 } else { 885 if (ctx->last_state[2] != data[2]) { 886 Uint8 hat; 887 888 switch (data[2] & 0x0f) { 889 case 0: 890 hat = SDL_HAT_UP; 891 break; 892 case 1: 893 hat = SDL_HAT_RIGHTUP; 894 break; 895 case 2: 896 hat = SDL_HAT_RIGHT; 897 break; 898 case 3: 899 hat = SDL_HAT_RIGHTDOWN; 900 break; 901 case 4: 902 hat = SDL_HAT_DOWN; 903 break; 904 case 5: 905 hat = SDL_HAT_LEFTDOWN; 906 break; 907 case 6: 908 hat = SDL_HAT_LEFT; 909 break; 910 case 7: 911 hat = SDL_HAT_LEFTUP; 912 break; 913 default: 914 hat = SDL_HAT_CENTERED; 915 break; 916 } 917 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 918 } 919 } 920 921 if (data[0] & 0x40) { 922 axis = 32767; 923 } else { 924 axis = ((int)data[17] * 257) - 32768; 925 } 926 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 927 if (data[0] & 0x80) { 928 axis = 32767; 929 } else { 930 axis = ((int)data[18] * 257) - 32768; 931 } 932 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); 933 axis = ((int)data[3] * 257) - 32768; 934 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); 935 axis = ((int)data[4] * 257) - 32768; 936 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis); 937 axis = ((int)data[5] * 257) - 32768; 938 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); 939 axis = ((int)data[6] * 257) - 32768; 940 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis); 941 942 // Buttons are mapped as axes in the order they appear in the button enumeration 943 if (ctx->has_analog_buttons) { 944 static int button_axis_offsets[] = { 945 13, // SDL_GAMEPAD_BUTTON_SOUTH 946 12, // SDL_GAMEPAD_BUTTON_EAST 947 14, // SDL_GAMEPAD_BUTTON_WEST 948 11, // SDL_GAMEPAD_BUTTON_NORTH 949 0, // SDL_GAMEPAD_BUTTON_BACK 950 0, // SDL_GAMEPAD_BUTTON_GUIDE 951 0, // SDL_GAMEPAD_BUTTON_START 952 0, // SDL_GAMEPAD_BUTTON_LEFT_STICK 953 0, // SDL_GAMEPAD_BUTTON_RIGHT_STICK 954 15, // SDL_GAMEPAD_BUTTON_LEFT_SHOULDER 955 16, // SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER 956 9, // SDL_GAMEPAD_BUTTON_DPAD_UP 957 10, // SDL_GAMEPAD_BUTTON_DPAD_DOWN 958 8, // SDL_GAMEPAD_BUTTON_DPAD_LEFT 959 7, // SDL_GAMEPAD_BUTTON_DPAD_RIGHT 960 }; 961 Uint8 i, axis_index = 6; 962 963 for (i = 0; i < SDL_arraysize(button_axis_offsets); ++i) { 964 int offset = button_axis_offsets[i]; 965 if (!offset) { 966 // This button doesn't report as an axis 967 continue; 968 } 969 970 axis = ((int)data[offset] * 257) - 32768; 971 SDL_SendJoystickAxis(timestamp, joystick, axis_index, axis); 972 ++axis_index; 973 } 974 } 975 976 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state))); 977} 978 979static bool HIDAPI_DriverPS3ThirdParty_UpdateDevice(SDL_HIDAPI_Device *device) 980{ 981 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 982 SDL_Joystick *joystick = NULL; 983 Uint8 data[USB_PACKET_LENGTH]; 984 int size; 985 986 if (device->num_joysticks > 0) { 987 joystick = SDL_GetJoystickFromID(device->joysticks[0]); 988 } else { 989 return false; 990 } 991 992 while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) { 993#ifdef DEBUG_PS3_PROTOCOL 994 HIDAPI_DumpPacket("PS3 packet: size = %d", data, size); 995#endif 996 if (!joystick) { 997 continue; 998 } 999 1000 if (size >= 19) { 1001 HIDAPI_DriverPS3ThirdParty_HandleStatePacket19(joystick, ctx, data, size); 1002 } else if (size == 18) { 1003 // This packet format was seen with the Logitech ChillStream 1004 HIDAPI_DriverPS3ThirdParty_HandleStatePacket18(joystick, ctx, data, size); 1005 } else { 1006#ifdef DEBUG_JOYSTICK 1007 SDL_Log("Unknown PS3 packet, size %d", size); 1008#endif 1009 } 1010 } 1011 1012 if (size < 0) { 1013 // Read error, device is disconnected 1014 HIDAPI_JoystickDisconnected(device, device->joysticks[0]); 1015 } 1016 return (size >= 0); 1017} 1018 1019static void HIDAPI_DriverPS3ThirdParty_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 1020{ 1021 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 1022 1023 ctx->joystick = NULL; 1024} 1025 1026static void HIDAPI_DriverPS3ThirdParty_FreeDevice(SDL_HIDAPI_Device *device) 1027{ 1028} 1029 1030SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS3ThirdParty = { 1031 SDL_HINT_JOYSTICK_HIDAPI_PS3, 1032 true, 1033 HIDAPI_DriverPS3_RegisterHints, 1034 HIDAPI_DriverPS3_UnregisterHints, 1035 HIDAPI_DriverPS3ThirdParty_IsEnabled, 1036 HIDAPI_DriverPS3ThirdParty_IsSupportedDevice, 1037 HIDAPI_DriverPS3ThirdParty_InitDevice, 1038 HIDAPI_DriverPS3ThirdParty_GetDevicePlayerIndex, 1039 HIDAPI_DriverPS3ThirdParty_SetDevicePlayerIndex, 1040 HIDAPI_DriverPS3ThirdParty_UpdateDevice, 1041 HIDAPI_DriverPS3ThirdParty_OpenJoystick, 1042 HIDAPI_DriverPS3ThirdParty_RumbleJoystick, 1043 HIDAPI_DriverPS3ThirdParty_RumbleJoystickTriggers, 1044 HIDAPI_DriverPS3ThirdParty_GetJoystickCapabilities, 1045 HIDAPI_DriverPS3ThirdParty_SetJoystickLED, 1046 HIDAPI_DriverPS3ThirdParty_SendJoystickEffect, 1047 HIDAPI_DriverPS3ThirdParty_SetJoystickSensorsEnabled, 1048 HIDAPI_DriverPS3ThirdParty_CloseJoystick, 1049 HIDAPI_DriverPS3ThirdParty_FreeDevice, 1050}; 1051 1052static bool HIDAPI_DriverPS3_UpdateRumbleSonySixaxis(SDL_HIDAPI_Device *device); 1053static bool HIDAPI_DriverPS3_UpdateLEDsSonySixaxis(SDL_HIDAPI_Device *device); 1054 1055static void HIDAPI_DriverPS3SonySixaxis_RegisterHints(SDL_HintCallback callback, void *userdata) 1056{ 1057 SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS3_SIXAXIS_DRIVER, callback, userdata); 1058} 1059 1060static void HIDAPI_DriverPS3SonySixaxis_UnregisterHints(SDL_HintCallback callback, void *userdata) 1061{ 1062 SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS3_SIXAXIS_DRIVER, callback, userdata); 1063} 1064 1065static bool HIDAPI_DriverPS3SonySixaxis_IsEnabled(void) 1066{ 1067#ifdef SDL_PLATFORM_WIN32 1068 return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3_SIXAXIS_DRIVER, false); 1069#else 1070 return false; 1071#endif 1072} 1073 1074static bool HIDAPI_DriverPS3SonySixaxis_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) 1075{ 1076 if (vendor_id == USB_VENDOR_SONY && product_id == USB_PRODUCT_SONY_DS3) { 1077 return true; 1078 } 1079 return false; 1080} 1081 1082static bool HIDAPI_DriverPS3SonySixaxis_InitDevice(SDL_HIDAPI_Device *device) 1083{ 1084 SDL_DriverPS3_Context *ctx; 1085 1086 ctx = (SDL_DriverPS3_Context *)SDL_calloc(1, sizeof(*ctx)); 1087 if (!ctx) { 1088 return false; 1089 } 1090 ctx->device = device; 1091 ctx->has_analog_buttons = true; 1092 1093 device->context = ctx; 1094 1095 Uint8 data[USB_PACKET_LENGTH]; 1096 1097 int size = ReadFeatureReport(device->dev, 0xf2, data, sizeof(data)); 1098 if (size < 0) { 1099 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 1100 "HIDAPI_DriverPS3SonySixaxis_InitDevice(): Couldn't read feature report 0xf2. Trying again with 0x0."); 1101 SDL_zeroa(data); 1102 size = ReadFeatureReport(device->dev, 0x00, data, sizeof(data)); 1103 if (size < 0) { 1104 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 1105 "HIDAPI_DriverPS3SonySixaxis_InitDevice(): Couldn't read feature report 0x00."); 1106 return false; 1107 } 1108#ifdef DEBUG_PS3_PROTOCOL 1109 HIDAPI_DumpPacket("PS3 0x0 packet: size = %d", data, size); 1110#endif 1111 } 1112#ifdef DEBUG_PS3_PROTOCOL 1113 HIDAPI_DumpPacket("PS3 0xF2 packet: size = %d", data, size); 1114#endif 1115 1116 device->type = SDL_GAMEPAD_TYPE_PS3; 1117 HIDAPI_SetDeviceName(device, "PS3 Controller"); 1118 1119 return HIDAPI_JoystickConnected(device, NULL); 1120} 1121 1122static int HIDAPI_DriverPS3SonySixaxis_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) 1123{ 1124 return -1; 1125} 1126 1127static void HIDAPI_DriverPS3SonySixaxis_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 1128{ 1129 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 1130 1131 if (!ctx) { 1132 return; 1133 } 1134 1135 ctx->player_index = player_index; 1136 1137 // This will set the new LED state based on the new player index 1138 HIDAPI_DriverPS3_UpdateLEDsSonySixaxis(device); 1139} 1140 1141static bool HIDAPI_DriverPS3SonySixaxis_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 1142{ 1143 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 1144 1145 SDL_AssertJoysticksLocked(); 1146 1147 ctx->joystick = joystick; 1148 ctx->effects_updated = false; 1149 ctx->rumble_left = 0; 1150 ctx->rumble_right = 0; 1151 SDL_zeroa(ctx->last_state); 1152 1153 // Initialize player index (needed for setting LEDs) 1154 ctx->player_index = SDL_GetJoystickPlayerIndex(joystick); 1155 1156 // Initialize the joystick capabilities 1157 joystick->nbuttons = 11; 1158 joystick->naxes = 6; 1159 if (ctx->has_analog_buttons) { 1160 joystick->naxes += 10; 1161 } 1162 joystick->nhats = 1; 1163 1164 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 100.0f); 1165 1166 return true; 1167} 1168 1169static bool HIDAPI_DriverPS3SonySixaxis_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 1170{ 1171 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 1172 1173 ctx->rumble_left = (low_frequency_rumble >> 8); 1174 ctx->rumble_right = (high_frequency_rumble >> 8); 1175 1176 return HIDAPI_DriverPS3_UpdateRumbleSonySixaxis(device); 1177} 1178 1179static bool HIDAPI_DriverPS3SonySixaxis_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 1180{ 1181 return SDL_Unsupported(); 1182} 1183 1184static Uint32 HIDAPI_DriverPS3SonySixaxis_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 1185{ 1186 return 0; 1187} 1188 1189static bool HIDAPI_DriverPS3SonySixaxis_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 1190{ 1191 return SDL_Unsupported(); 1192} 1193 1194static bool HIDAPI_DriverPS3SonySixaxis_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size) 1195{ 1196 Uint8 data[49]; 1197 int report_size; 1198 1199 SDL_zeroa(data); 1200 1201 data[0] = k_EPS3SonySixaxisReportIdEffects; 1202 report_size = sizeof(data); 1203 1204 // No offset with Sony sixaxis.sys driver 1205 SDL_memcpy(&data, effect, SDL_min(sizeof(data), (size_t)size)); 1206 1207 if (SDL_HIDAPI_SendRumble(device, data, report_size) != report_size) { 1208 return SDL_SetError("Couldn't send rumble packet"); 1209 } 1210 return true; 1211} 1212 1213static bool HIDAPI_DriverPS3SonySixaxis_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled) 1214{ 1215 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 1216 1217 ctx->report_sensors = enabled; 1218 1219 return true; 1220} 1221 1222static void HIDAPI_DriverPS3SonySixaxis_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverPS3_Context *ctx, Uint8 *data, int size) 1223{ 1224 Sint16 axis; 1225 Uint64 timestamp = SDL_GetTicksNS(); 1226 1227 if (ctx->last_state[2] != data[2]) { 1228 Uint8 hat = 0; 1229 1230 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[2] & 0x01) != 0)); 1231 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[2] & 0x02) != 0)); 1232 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[2] & 0x04) != 0)); 1233 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[2] & 0x08) != 0)); 1234 1235 if (data[2] & 0x10) { 1236 hat |= SDL_HAT_UP; 1237 } 1238 if (data[2] & 0x20) { 1239 hat |= SDL_HAT_RIGHT; 1240 } 1241 if (data[2] & 0x40) { 1242 hat |= SDL_HAT_DOWN; 1243 } 1244 if (data[2] & 0x80) { 1245 hat |= SDL_HAT_LEFT; 1246 } 1247 SDL_SendJoystickHat(timestamp, joystick, 0, hat); 1248 } 1249 1250 if (ctx->last_state[3] != data[3]) { 1251 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[3] & 0x04) != 0)); 1252 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[3] & 0x08) != 0)); 1253 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[3] & 0x10) != 0)); 1254 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[3] & 0x20) != 0)); 1255 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[3] & 0x40) != 0)); 1256 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[3] & 0x80) != 0)); 1257 } 1258 1259 if (ctx->last_state[4] != data[4]) { 1260 SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[4] & 0x01) != 0)); 1261 } 1262 1263 axis = ((int)data[18] * 257) - 32768; 1264 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis); 1265 axis = ((int)data[19] * 257) - 32768; 1266 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis); 1267 axis = ((int)data[6] * 257) - 32768; 1268 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis); 1269 axis = ((int)data[7] * 257) - 32768; 1270 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis); 1271 axis = ((int)data[8] * 257) - 32768; 1272 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis); 1273 axis = ((int)data[9] * 257) - 32768; 1274 SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis); 1275 1276 // Buttons are mapped as axes in the order they appear in the button enumeration 1277 if (ctx->has_analog_buttons) { 1278 static int button_axis_offsets[] = { 1279 24, // SDL_GAMEPAD_BUTTON_SOUTH 1280 23, // SDL_GAMEPAD_BUTTON_EAST 1281 25, // SDL_GAMEPAD_BUTTON_WEST 1282 22, // SDL_GAMEPAD_BUTTON_NORTH 1283 0, // SDL_GAMEPAD_BUTTON_BACK 1284 0, // SDL_GAMEPAD_BUTTON_GUIDE 1285 0, // SDL_GAMEPAD_BUTTON_START 1286 0, // SDL_GAMEPAD_BUTTON_LEFT_STICK 1287 0, // SDL_GAMEPAD_BUTTON_RIGHT_STICK 1288 20, // SDL_GAMEPAD_BUTTON_LEFT_SHOULDER 1289 21, // SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER 1290 14, // SDL_GAMEPAD_BUTTON_DPAD_UP 1291 16, // SDL_GAMEPAD_BUTTON_DPAD_DOWN 1292 17, // SDL_GAMEPAD_BUTTON_DPAD_LEFT 1293 15, // SDL_GAMEPAD_BUTTON_DPAD_RIGHT 1294 }; 1295 Uint8 i, axis_index = 6; 1296 1297 for (i = 0; i < SDL_arraysize(button_axis_offsets); ++i) { 1298 int offset = button_axis_offsets[i]; 1299 if (!offset) { 1300 // This button doesn't report as an axis 1301 continue; 1302 } 1303 1304 axis = ((int)data[offset] * 257) - 32768; 1305 SDL_SendJoystickAxis(timestamp, joystick, axis_index, axis); 1306 ++axis_index; 1307 } 1308 } 1309 1310 if (ctx->report_sensors) { 1311 float sensor_data[3]; 1312 1313 sensor_data[0] = HIDAPI_DriverPS3_ScaleAccel(LOAD16(data[41], data[42])); 1314 sensor_data[1] = -HIDAPI_DriverPS3_ScaleAccel(LOAD16(data[45], data[46])); 1315 sensor_data[2] = -HIDAPI_DriverPS3_ScaleAccel(LOAD16(data[43], data[44])); 1316 SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, timestamp, sensor_data, SDL_arraysize(sensor_data)); 1317 } 1318 1319 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state))); 1320} 1321 1322static bool HIDAPI_DriverPS3SonySixaxis_UpdateDevice(SDL_HIDAPI_Device *device) 1323{ 1324 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 1325 SDL_Joystick *joystick = NULL; 1326 Uint8 data[USB_PACKET_LENGTH]; 1327 int size; 1328 1329 if (device->num_joysticks > 0) { 1330 joystick = SDL_GetJoystickFromID(device->joysticks[0]); 1331 } else { 1332 return false; 1333 } 1334 1335 if (!joystick) { 1336 return false; 1337 } 1338 1339 // With sixaxis.sys driver we need to use hid_get_feature_report instead of hid_read 1340 size = ReadFeatureReport(device->dev, 0x0, data, sizeof(data)); 1341 if (size < 0) { 1342 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, 1343 "HIDAPI_DriverPS3SonySixaxis_UpdateDevice(): Couldn't read feature report 0x00"); 1344 return false; 1345 } 1346 1347 switch (data[0]) { 1348 case k_EPS3SonySixaxisReportIdState: 1349 HIDAPI_DriverPS3SonySixaxis_HandleStatePacket(joystick, ctx, &data[1], size - 1); // report data starts in data[1] 1350 1351 // Wait for the first report to set the LED state after the controller stops blinking 1352 if (!ctx->effects_updated) { 1353 HIDAPI_DriverPS3_UpdateLEDsSonySixaxis(device); 1354 ctx->effects_updated = true; 1355 } 1356 1357 break; 1358 default: 1359#ifdef DEBUG_JOYSTICK 1360 SDL_Log("Unknown PS3 packet: 0x%.2x", data[0]); 1361#endif 1362 break; 1363 } 1364 1365 if (size < 0) { 1366 // Read error, device is disconnected 1367 HIDAPI_JoystickDisconnected(device, device->joysticks[0]); 1368 } 1369 return (size >= 0); 1370} 1371 1372static void HIDAPI_DriverPS3SonySixaxis_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 1373{ 1374 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 1375 1376 ctx->joystick = NULL; 1377} 1378 1379static void HIDAPI_DriverPS3SonySixaxis_FreeDevice(SDL_HIDAPI_Device *device) 1380{ 1381} 1382 1383static bool HIDAPI_DriverPS3_UpdateRumbleSonySixaxis(SDL_HIDAPI_Device *device) 1384{ 1385 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 1386 1387 Uint8 effects[] = { 1388 0x0, // Report Id 1389 k_EPS3SixaxisCommandSetMotors, // 2 = Set Motors 1390 0x00, 0x00, 0x00, // padding 1391 0xff, // Small Motor duration - 0xff is forever 1392 0x00, // Small Motor off/on (0 or 1) 1393 0xff, // Large Motor duration - 0xff is forever 1394 0x00 // Large Motor force (0 to 255) 1395 }; 1396 1397 effects[6] = ctx->rumble_right ? 1 : 0; // Small motor 1398 effects[8] = ctx->rumble_left; // Large motor 1399 1400 return HIDAPI_DriverPS3SonySixaxis_SendJoystickEffect(device, ctx->joystick, effects, sizeof(effects)); 1401} 1402 1403static bool HIDAPI_DriverPS3_UpdateLEDsSonySixaxis(SDL_HIDAPI_Device *device) 1404{ 1405 SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context; 1406 1407 Uint8 effects[] = { 1408 0x0, // Report Id 1409 k_EPS3SixaxisCommandSetLEDs, // 1 = Set LEDs 1410 0x00, 0x00, 0x00, // padding 1411 0x00, 0x00, 0x00, 0x00 // LED #4, LED #3, LED #2, LED #1 (0 = Off, 1 = On, 2 = Flashing) 1412 }; 1413 1414 // Turn on LED light on DS3 Controller for relevant player (player_index 0 lights up LED #1, player_index 1 lights up LED #2, etc) 1415 if (ctx->player_index < 4) { 1416 effects[8 - ctx->player_index] = 1; 1417 } 1418 1419 return HIDAPI_DriverPS3SonySixaxis_SendJoystickEffect(device, ctx->joystick, effects, sizeof(effects)); 1420} 1421 1422SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS3SonySixaxis = { 1423 SDL_HINT_JOYSTICK_HIDAPI_PS3_SIXAXIS_DRIVER, 1424 true, 1425 HIDAPI_DriverPS3SonySixaxis_RegisterHints, 1426 HIDAPI_DriverPS3SonySixaxis_UnregisterHints, 1427 HIDAPI_DriverPS3SonySixaxis_IsEnabled, 1428 HIDAPI_DriverPS3SonySixaxis_IsSupportedDevice, 1429 HIDAPI_DriverPS3SonySixaxis_InitDevice, 1430 HIDAPI_DriverPS3SonySixaxis_GetDevicePlayerIndex, 1431 HIDAPI_DriverPS3SonySixaxis_SetDevicePlayerIndex, 1432 HIDAPI_DriverPS3SonySixaxis_UpdateDevice, 1433 HIDAPI_DriverPS3SonySixaxis_OpenJoystick, 1434 HIDAPI_DriverPS3SonySixaxis_RumbleJoystick, 1435 HIDAPI_DriverPS3SonySixaxis_RumbleJoystickTriggers, 1436 HIDAPI_DriverPS3SonySixaxis_GetJoystickCapabilities, 1437 HIDAPI_DriverPS3SonySixaxis_SetJoystickLED, 1438 HIDAPI_DriverPS3SonySixaxis_SendJoystickEffect, 1439 HIDAPI_DriverPS3SonySixaxis_SetJoystickSensorsEnabled, 1440 HIDAPI_DriverPS3SonySixaxis_CloseJoystick, 1441 HIDAPI_DriverPS3SonySixaxis_FreeDevice, 1442}; 1443 1444#endif // SDL_JOYSTICK_HIDAPI_PS3 1445 1446#endif // SDL_JOYSTICK_HIDAPI 1447
[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.