1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#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