1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 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.h"
26 #include "SDL_events.h"
27 #include "SDL_timer.h"
28 #include "SDL_joystick.h"
29 #include "SDL_gamecontroller.h"
30 #include "../SDL_sysjoystick.h"
31 #include "SDL_hidapijoystick_c.h"
32 #include "SDL_hidapi_rumble.h"
33
34
35 #ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
36
37 /* Define this if you want verbose logging of the init sequence */
38 /*#define DEBUG_JOYSTICK*/
39
40 /* Define this if you want to log all packets from the controller */
41 /*#define DEBUG_XBOX_PROTOCOL*/
42
43 #define CONTROLLER_NEGOTIATION_TIMEOUT_MS 300
44 #define CONTROLLER_PREPARE_INPUT_TIMEOUT_MS 50
45
46
47 /* Start controller */
48 static const Uint8 xboxone_init0[] = {
49 0x05, 0x20, 0x03, 0x01, 0x00
50 };
51 /* Enable LED */
52 static const Uint8 xboxone_init1[] = {
53 0x0A, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
54 };
55 /* Setup rumble (not needed for Microsoft controllers, but it doesn't hurt) */
56 static const Uint8 xboxone_init2[] = {
57 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
58 0x00, 0x00, 0xFF, 0x00, 0xEB
59 };
60 /* This controller passed security check */
61 static const Uint8 security_passed_packet[] = {
62 0x06, 0x20, 0x00, 0x02, 0x01, 0x00
63 };
64
65 /*
66 * This specifies the selection of init packets that a gamepad
67 * will be sent on init *and* the order in which they will be
68 * sent. The correct sequence number will be added when the
69 * packet is going to be sent.
70 */
71 typedef struct {
72 Uint16 vendor_id;
73 Uint16 product_id;
74 Uint16 exclude_vendor_id;
75 Uint16 exclude_product_id;
76 const Uint8 *data;
77 int size;
78 const Uint8 response[2];
79 } SDL_DriverXboxOne_InitPacket;
80
81
82 static const SDL_DriverXboxOne_InitPacket xboxone_init_packets[] = {
83 /* The PDP Rock Candy controller doesn't start sending input until it gets this packet */
84 { 0x0e6f, 0x0246, 0x0000, 0x0000, security_passed_packet, sizeof(security_passed_packet), { 0x00, 0x00 } },
85 { 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init0, sizeof(xboxone_init0), { 0x00, 0x00 } },
86 { 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init1, sizeof(xboxone_init1), { 0x00, 0x00 } },
87 { 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init2, sizeof(xboxone_init2), { 0x00, 0x00 } },
88 };
89
90 typedef enum {
91 XBOX_ONE_INIT_STATE_START_NEGOTIATING = 0,
92 XBOX_ONE_INIT_STATE_NEGOTIATING = 1,
93 XBOX_ONE_INIT_STATE_PREPARE_INPUT = 2,
94 XBOX_ONE_INIT_STATE_COMPLETE = 3
95 } SDL_XboxOneInitState;
96
97 typedef struct {
98 Uint16 vendor_id;
99 Uint16 product_id;
100 SDL_bool bluetooth;
101 SDL_XboxOneInitState init_state;
102 int init_packet;
103 Uint32 start_time;
104 Uint8 sequence;
105 Uint32 send_time;
106 Uint8 last_state[USB_PACKET_LENGTH];
107 SDL_bool has_guide_packet;
108 SDL_bool has_color_led;
109 SDL_bool has_paddles;
110 SDL_bool has_trigger_rumble;
111 SDL_bool has_share_button;
112 Uint8 low_frequency_rumble;
113 Uint8 high_frequency_rumble;
114 Uint8 left_trigger_rumble;
115 Uint8 right_trigger_rumble;
116 } SDL_DriverXboxOne_Context;
117
118 static SDL_bool
ControllerHasColorLED(Uint16 vendor_id,Uint16 product_id)119 ControllerHasColorLED(Uint16 vendor_id, Uint16 product_id)
120 {
121 return (vendor_id == USB_VENDOR_MICROSOFT && product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2);
122 }
123
124 static SDL_bool
ControllerHasPaddles(Uint16 vendor_id,Uint16 product_id)125 ControllerHasPaddles(Uint16 vendor_id, Uint16 product_id)
126 {
127 return SDL_IsJoystickXboxOneElite(vendor_id, product_id);
128 }
129
130 static SDL_bool
ControllerHasTriggerRumble(Uint16 vendor_id,Uint16 product_id)131 ControllerHasTriggerRumble(Uint16 vendor_id, Uint16 product_id)
132 {
133 /* All the Microsoft Xbox One controllers have trigger rumble */
134 return (vendor_id == USB_VENDOR_MICROSOFT);
135 }
136
137 static SDL_bool
ControllerHasShareButton(Uint16 vendor_id,Uint16 product_id)138 ControllerHasShareButton(Uint16 vendor_id, Uint16 product_id)
139 {
140 return SDL_IsJoystickXboxSeriesX(vendor_id, product_id);
141 }
142
143 static void
SetInitState(SDL_DriverXboxOne_Context * ctx,SDL_XboxOneInitState state)144 SetInitState(SDL_DriverXboxOne_Context *ctx, SDL_XboxOneInitState state)
145 {
146 #ifdef DEBUG_JOYSTICK
147 SDL_Log("Setting init state %d\n", state);
148 #endif
149 ctx->init_state = state;
150 }
151
152 static void
SendAckIfNeeded(SDL_HIDAPI_Device * device,Uint8 * data,int size)153 SendAckIfNeeded(SDL_HIDAPI_Device *device, Uint8 *data, int size)
154 {
155 #ifdef __WIN32__
156 /* The Windows driver is taking care of acks */
157 #else
158 if ((data[1] & 0x30) == 0x30) {
159 Uint8 ack_packet[] = { 0x01, 0x20, 0x00, 0x09, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
160
161 ack_packet[2] = data[2];
162 ack_packet[5] = data[0];
163 ack_packet[7] = data[3];
164
165 /* The initial ack needs 0x80 added to the response, for some reason */
166 if (data[0] == 0x04 && data[1] == 0xF0) {
167 ack_packet[11] = 0x80;
168 }
169
170 #ifdef DEBUG_XBOX_PROTOCOL
171 HIDAPI_DumpPacket("Xbox One sending ACK packet: size = %d", ack_packet, sizeof(ack_packet));
172 #endif
173 if (SDL_HIDAPI_LockRumble() < 0 ||
174 SDL_HIDAPI_SendRumbleAndUnlock(device, ack_packet, sizeof(ack_packet)) != sizeof(ack_packet)) {
175 SDL_SetError("Couldn't send ack packet");
176 }
177 }
178 #endif /* __WIN32__ */
179 }
180
181 #if 0
182 static SDL_bool
183 SendSerialRequest(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
184 {
185 Uint8 serial_packet[] = { 0x1E, 0x30, 0x07, 0x01, 0x04 };
186
187 ctx->send_time = SDL_GetTicks();
188
189 /* Request the serial number
190 * Sending this should be done only after the negotiation is complete.
191 * It will cancel the announce packet if sent before that, and will be
192 * ignored if sent during the negotiation.
193 */
194 if (SDL_HIDAPI_LockRumble() < 0 ||
195 SDL_HIDAPI_SendRumbleAndUnlock(device, serial_packet, sizeof(serial_packet)) != sizeof(serial_packet)) {
196 SDL_SetError("Couldn't send serial packet");
197 return SDL_FALSE;
198 }
199 return SDL_TRUE;
200 }
201 #endif
202
203 static SDL_bool
ControllerNeedsNegotiation(SDL_DriverXboxOne_Context * ctx)204 ControllerNeedsNegotiation(SDL_DriverXboxOne_Context *ctx)
205 {
206 if (ctx->vendor_id == USB_VENDOR_PDP && ctx->product_id == 0x0246) {
207 /* The PDP Rock Candy (PID 0x0246) doesn't send the announce packet on Linux for some reason */
208 return SDL_TRUE;
209 }
210 return SDL_FALSE;
211 }
212
213 static SDL_bool
SendControllerInit(SDL_HIDAPI_Device * device,SDL_DriverXboxOne_Context * ctx)214 SendControllerInit(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
215 {
216 Uint16 vendor_id = ctx->vendor_id;
217 Uint16 product_id = ctx->product_id;
218 Uint8 init_packet[USB_PACKET_LENGTH];
219
220 for ( ; ctx->init_packet < SDL_arraysize(xboxone_init_packets); ++ctx->init_packet) {
221 const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[ctx->init_packet];
222
223 if (packet->vendor_id && (vendor_id != packet->vendor_id)) {
224 continue;
225 }
226
227 if (packet->product_id && (product_id != packet->product_id)) {
228 continue;
229 }
230
231 if (packet->exclude_vendor_id && (vendor_id == packet->exclude_vendor_id)) {
232 continue;
233 }
234
235 if (packet->exclude_product_id && (product_id == packet->exclude_product_id)) {
236 continue;
237 }
238
239 SDL_memcpy(init_packet, packet->data, packet->size);
240 if (init_packet[0] != 0x01) {
241 init_packet[2] = ctx->sequence++;
242 }
243 #ifdef DEBUG_XBOX_PROTOCOL
244 HIDAPI_DumpPacket("Xbox One sending INIT packet: size = %d", init_packet, packet->size);
245 #endif
246 ctx->send_time = SDL_GetTicks();
247
248 if (SDL_HIDAPI_LockRumble() < 0 ||
249 SDL_HIDAPI_SendRumbleAndUnlock(device, init_packet, packet->size) != packet->size) {
250 SDL_SetError("Couldn't write Xbox One initialization packet");
251 return SDL_FALSE;
252 }
253
254 if (packet->response[0]) {
255 return SDL_TRUE;
256 }
257 }
258
259 /* All done with the negotiation, prepare for input! */
260 SetInitState(ctx, XBOX_ONE_INIT_STATE_PREPARE_INPUT);
261
262 return SDL_TRUE;
263 }
264
265 static SDL_bool
HIDAPI_DriverXboxOne_IsSupportedDevice(const char * name,SDL_GameControllerType type,Uint16 vendor_id,Uint16 product_id,Uint16 version,int interface_number,int interface_class,int interface_subclass,int interface_protocol)266 HIDAPI_DriverXboxOne_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
267 {
268 #ifdef __LINUX__
269 if (vendor_id == USB_VENDOR_POWERA && product_id == 0x541a) {
270 /* The PowerA Mini controller, model 1240245-01, blocks while writing feature reports */
271 return SDL_FALSE;
272 }
273 #endif
274 #ifdef __MACOSX__
275 /* Wired Xbox One controllers are handled by the 360Controller driver */
276 if (!SDL_IsJoystickBluetoothXboxOne(vendor_id, product_id)) {
277 return SDL_FALSE;
278 }
279 #endif
280 return (type == SDL_CONTROLLER_TYPE_XBOXONE) ? SDL_TRUE : SDL_FALSE;
281 }
282
283 static const char *
HIDAPI_DriverXboxOne_GetDeviceName(Uint16 vendor_id,Uint16 product_id)284 HIDAPI_DriverXboxOne_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
285 {
286 return NULL;
287 }
288
289 static SDL_bool
HIDAPI_DriverXboxOne_InitDevice(SDL_HIDAPI_Device * device)290 HIDAPI_DriverXboxOne_InitDevice(SDL_HIDAPI_Device *device)
291 {
292 return HIDAPI_JoystickConnected(device, NULL);
293 }
294
295 static int
HIDAPI_DriverXboxOne_GetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id)296 HIDAPI_DriverXboxOne_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
297 {
298 return -1;
299 }
300
301 static void
HIDAPI_DriverXboxOne_SetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id,int player_index)302 HIDAPI_DriverXboxOne_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
303 {
304 }
305
306 static SDL_bool HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
307 static void HIDAPI_DriverXboxOne_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
308
309 static SDL_bool
HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)310 HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
311 {
312 SDL_DriverXboxOne_Context *ctx;
313
314 ctx = (SDL_DriverXboxOne_Context *)SDL_calloc(1, sizeof(*ctx));
315 if (!ctx) {
316 SDL_OutOfMemory();
317 return SDL_FALSE;
318 }
319
320 device->dev = SDL_hid_open_path(device->path, 0);
321 if (!device->dev) {
322 SDL_free(ctx);
323 SDL_SetError("Couldn't open %s", device->path);
324 return SDL_FALSE;
325 }
326 device->context = ctx;
327
328 ctx->vendor_id = device->vendor_id;
329 ctx->product_id = device->product_id;
330 ctx->bluetooth = SDL_IsJoystickBluetoothXboxOne(device->vendor_id, device->product_id);
331 ctx->start_time = SDL_GetTicks();
332 ctx->sequence = 1;
333 ctx->has_color_led = ControllerHasColorLED(ctx->vendor_id, ctx->product_id);
334 ctx->has_paddles = ControllerHasPaddles(ctx->vendor_id, ctx->product_id);
335 ctx->has_trigger_rumble = ControllerHasTriggerRumble(ctx->vendor_id, ctx->product_id);
336 ctx->has_share_button = ControllerHasShareButton(ctx->vendor_id, ctx->product_id);
337
338 /* Assume that the controller is correctly initialized when we start */
339 if (ControllerNeedsNegotiation(ctx)) {
340 ctx->init_state = XBOX_ONE_INIT_STATE_START_NEGOTIATING;
341 } else {
342 ctx->init_state = XBOX_ONE_INIT_STATE_COMPLETE;
343 }
344
345 #ifdef DEBUG_JOYSTICK
346 SDL_Log("Controller version: %d (0x%.4x)\n", device->version, device->version);
347 #endif
348
349 /* Initialize the joystick capabilities */
350 joystick->nbuttons = 15;
351 if (ctx->has_share_button) {
352 joystick->nbuttons += 1;
353 }
354 if (ctx->has_paddles) {
355 joystick->nbuttons += 4;
356 }
357 joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
358
359 if (!ctx->bluetooth) {
360 joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
361 }
362
363 return SDL_TRUE;
364 }
365
366 static int
HIDAPI_DriverXboxOne_UpdateRumble(SDL_HIDAPI_Device * device)367 HIDAPI_DriverXboxOne_UpdateRumble(SDL_HIDAPI_Device *device)
368 {
369 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
370
371 if (ctx->bluetooth) {
372 Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB };
373
374 rumble_packet[2] = ctx->left_trigger_rumble;
375 rumble_packet[3] = ctx->right_trigger_rumble;
376 rumble_packet[4] = ctx->low_frequency_rumble;
377 rumble_packet[5] = ctx->high_frequency_rumble;
378
379 if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
380 return SDL_SetError("Couldn't send rumble packet");
381 }
382 } else {
383 Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB };
384
385 rumble_packet[6] = ctx->left_trigger_rumble;
386 rumble_packet[7] = ctx->right_trigger_rumble;
387 rumble_packet[8] = ctx->low_frequency_rumble;
388 rumble_packet[9] = ctx->high_frequency_rumble;
389
390 if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
391 return SDL_SetError("Couldn't send rumble packet");
392 }
393 }
394 return 0;
395 }
396
397 static int
HIDAPI_DriverXboxOne_RumbleJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)398 HIDAPI_DriverXboxOne_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
399 {
400 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
401
402 /* Magnitude is 1..100 so scale the 16-bit input here */
403 ctx->low_frequency_rumble = low_frequency_rumble / 655;
404 ctx->high_frequency_rumble = high_frequency_rumble / 655;
405
406 return HIDAPI_DriverXboxOne_UpdateRumble(device);
407 }
408
409 static int
HIDAPI_DriverXboxOne_RumbleJoystickTriggers(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint16 left_rumble,Uint16 right_rumble)410 HIDAPI_DriverXboxOne_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
411 {
412 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
413
414 if (!ctx->has_trigger_rumble) {
415 return SDL_Unsupported();
416 }
417
418 /* Magnitude is 1..100 so scale the 16-bit input here */
419 ctx->left_trigger_rumble = left_rumble / 655;
420 ctx->right_trigger_rumble = right_rumble / 655;
421
422 return HIDAPI_DriverXboxOne_UpdateRumble(device);
423 }
424
425 static Uint32
HIDAPI_DriverXboxOne_GetJoystickCapabilities(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)426 HIDAPI_DriverXboxOne_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
427 {
428 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
429 Uint32 result = 0;
430
431 result |= SDL_JOYCAP_RUMBLE;
432 if (ctx->has_trigger_rumble) {
433 result |= SDL_JOYCAP_RUMBLE_TRIGGERS;
434 }
435
436 if (ctx->has_color_led) {
437 result |= SDL_JOYCAP_LED;
438 }
439
440 return result;
441 }
442
443 static int
HIDAPI_DriverXboxOne_SetJoystickLED(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint8 red,Uint8 green,Uint8 blue)444 HIDAPI_DriverXboxOne_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
445 {
446 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
447
448 if (ctx->has_color_led) {
449 Uint8 led_packet[] = { 0x0E, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };
450
451 led_packet[5] = 0x00; /* Whiteness? Sets white intensity when RGB is 0, seems additive */
452 led_packet[6] = red;
453 led_packet[7] = green;
454 led_packet[8] = blue;
455
456 if (SDL_HIDAPI_SendRumble(device, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
457 return SDL_SetError("Couldn't send LED packet");
458 }
459 return 0;
460 } else {
461 return SDL_Unsupported();
462 }
463 }
464
465 static int
HIDAPI_DriverXboxOne_SendJoystickEffect(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,const void * data,int size)466 HIDAPI_DriverXboxOne_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
467 {
468 return SDL_Unsupported();
469 }
470
471 static int
HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,SDL_bool enabled)472 HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
473 {
474 return SDL_Unsupported();
475 }
476
477 static void
HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick * joystick,SDL_DriverXboxOne_Context * ctx,Uint8 * data,int size)478 HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
479 {
480 Sint16 axis;
481
482 if (ctx->last_state[4] != data[4]) {
483 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[4] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
484 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[4] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
485 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[4] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
486 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[4] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
487 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[4] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
488 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[4] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
489 }
490
491 if (ctx->last_state[5] != data[5]) {
492 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[5] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
493 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[5] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
494 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[5] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
495 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[5] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
496 if (ctx->vendor_id == USB_VENDOR_RAZER && ctx->product_id == USB_PRODUCT_RAZER_ATROX) {
497 /* The Razer Atrox has the right and left shoulder bits reversed */
498 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
499 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
500 } else {
501 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
502 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
503 }
504 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[5] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
505 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[5] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
506 }
507
508 if (ctx->has_share_button) {
509 /* Xbox Series X firmware version 5.0, report is 36 bytes, share button is in byte 18
510 * Xbox Series X firmware version 5.1, report is 44 bytes, share button is in byte 18
511 * Xbox Series X firmware version 5.5, report is 48 bytes, share button is in byte 22
512 * Victrix Gambit Tournament Controller, report is 50 bytes, share button is in byte 32
513 */
514 if (size < 48) {
515 if (ctx->last_state[18] != data[18]) {
516 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data[18] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
517 }
518 } else if (size == 48) {
519 if (ctx->last_state[22] != data[22]) {
520 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data[22] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
521 }
522 } else if (size == 50) {
523 if (ctx->last_state[32] != data[32]) {
524 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data[32] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
525 }
526 }
527 }
528
529 /* Xbox One S report is 18 bytes
530 Xbox One Elite Series 1 report is 33 bytes, paddles in data[32], mode in data[32] & 0x10, both modes have mapped paddles by default
531 Paddle bits:
532 P3: 0x01 (A) P1: 0x02 (B)
533 P4: 0x04 (X) P2: 0x08 (Y)
534 Xbox One Elite Series 2 4.x firmware report is 38 bytes, paddles in data[18], mode in data[19], mode 0 has no mapped paddles by default
535 Paddle bits:
536 P3: 0x04 (A) P1: 0x01 (B)
537 P4: 0x08 (X) P2: 0x02 (Y)
538 Xbox One Elite Series 2 5.x firmware report is 50 bytes, paddles in data[22], mode in data[23], mode 0 has no mapped paddles by default
539 Paddle bits:
540 P3: 0x04 (A) P1: 0x01 (B)
541 P4: 0x08 (X) P2: 0x02 (Y)
542 */
543 if (ctx->has_paddles && (size == 33 || size == 38 || size == 50)) {
544 int paddle_index;
545 int button1_bit;
546 int button2_bit;
547 int button3_bit;
548 int button4_bit;
549 SDL_bool paddles_mapped;
550
551 if (size == 33) {
552 /* XBox One Elite Series 1 */
553 paddle_index = 32;
554 button1_bit = 0x02;
555 button2_bit = 0x08;
556 button3_bit = 0x01;
557 button4_bit = 0x04;
558
559 /* The mapped controller state is at offset 4, the raw state is at offset 18, compare them to see if the paddles are mapped */
560 paddles_mapped = (SDL_memcmp(&data[4], &data[18], 2) != 0);
561
562 } else if (size == 38) {
563 /* XBox One Elite Series 2 */
564 paddle_index = 18;
565 button1_bit = 0x01;
566 button2_bit = 0x02;
567 button3_bit = 0x04;
568 button4_bit = 0x08;
569 paddles_mapped = (data[19] != 0);
570
571 } else /* if (size == 50) */{
572 /* XBox One Elite Series 2 */
573 paddle_index = 22;
574 button1_bit = 0x01;
575 button2_bit = 0x02;
576 button3_bit = 0x04;
577 button4_bit = 0x08;
578 paddles_mapped = (data[23] != 0);
579 }
580 #ifdef DEBUG_XBOX_PROTOCOL
581 SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s\n",
582 (data[paddle_index] & button1_bit) ? 1 : 0,
583 (data[paddle_index] & button2_bit) ? 1 : 0,
584 (data[paddle_index] & button3_bit) ? 1 : 0,
585 (data[paddle_index] & button4_bit) ? 1 : 0,
586 paddles_mapped ? "TRUE" : "FALSE"
587 );
588 #endif
589
590 if (paddles_mapped) {
591 /* Respect that the paddles are being used for other controls and don't pass them on to the app */
592 data[paddle_index] = 0;
593 }
594
595 if (ctx->last_state[paddle_index] != data[paddle_index]) {
596 int nButton = SDL_CONTROLLER_BUTTON_MISC1 + ctx->has_share_button; /* Next available button */
597 SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button1_bit) ? SDL_PRESSED : SDL_RELEASED);
598 SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button2_bit) ? SDL_PRESSED : SDL_RELEASED);
599 SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button3_bit) ? SDL_PRESSED : SDL_RELEASED);
600 SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button4_bit) ? SDL_PRESSED : SDL_RELEASED);
601 }
602 }
603
604 axis = ((int)*(Sint16*)(&data[6]) * 64) - 32768;
605 if (axis == 32704) {
606 axis = 32767;
607 }
608 if (axis == -32768 && size == 30 && (data[22] & 0x80) != 0) {
609 axis = 32767;
610 }
611 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
612
613 axis = ((int)*(Sint16*)(&data[8]) * 64) - 32768;
614 if (axis == -32768 && size == 30 && (data[22] & 0x40) != 0) {
615 axis = 32767;
616 }
617 if (axis == 32704) {
618 axis = 32767;
619 }
620 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
621
622 axis = *(Sint16*)(&data[10]);
623 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
624 axis = *(Sint16*)(&data[12]);
625 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
626 axis = *(Sint16*)(&data[14]);
627 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
628 axis = *(Sint16*)(&data[16]);
629 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
630
631 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
632 }
633
634 static void
HIDAPI_DriverXboxOne_HandleStatusPacket(SDL_Joystick * joystick,SDL_DriverXboxOne_Context * ctx,Uint8 * data,int size)635 HIDAPI_DriverXboxOne_HandleStatusPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
636 {
637 if (ctx->init_state < XBOX_ONE_INIT_STATE_COMPLETE) {
638 SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
639 }
640 }
641
642 static void
HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick * joystick,SDL_DriverXboxOne_Context * ctx,Uint8 * data,int size)643 HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
644 {
645 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
646 }
647
648 /*
649 * Xbox One S with firmware 3.1.1221 uses a 16 byte packet and the GUIDE button in a separate packet
650 */
651 static void
HIDAPI_DriverXboxOneBluetooth_HandleButtons16(SDL_Joystick * joystick,SDL_DriverXboxOne_Context * ctx,Uint8 * data,int size)652 HIDAPI_DriverXboxOneBluetooth_HandleButtons16(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
653 {
654 if (ctx->last_state[14] != data[14]) {
655 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[14] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
656 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[14] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
657 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[14] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
658 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[14] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
659 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[14] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
660 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[14] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
661 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[14] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
662 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[14] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
663 }
664
665 if (ctx->last_state[15] != data[15]) {
666 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[15] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
667 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[15] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
668 }
669
670 }
671
672 /*
673 * Xbox One S with firmware 4.8.1923 uses a 17 byte packet with BACK button in byte 16 and the GUIDE button in a separate packet (on Windows), or in byte 15 (on Linux)
674 * Xbox One S with firmware 5.x uses a 17 byte packet with BACK and GUIDE buttons in byte 15
675 * Xbox One Elite Series 2 with firmware 4.7.1872 uses a 55 byte packet with BACK button in byte 16, paddles starting at byte 33, and the GUIDE button in a separate packet
676 * Xbox One Elite Series 2 with firmware 4.8.1908 uses a 33 byte packet with BACK button in byte 16, paddles starting at byte 17, and the GUIDE button in a separate packet
677 * Xbox One Elite Series 2 with firmware 5.11.3112 uses a 19 byte packet with BACK and GUIDE buttons in byte 15
678 * Xbox Series X with firmware 5.5.2641 uses a 17 byte packet with BACK and GUIDE buttons in byte 15, and SHARE button in byte 17
679 */
680 static void
HIDAPI_DriverXboxOneBluetooth_HandleButtons(SDL_Joystick * joystick,SDL_DriverXboxOne_Context * ctx,Uint8 * data,int size)681 HIDAPI_DriverXboxOneBluetooth_HandleButtons(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
682 {
683 if (ctx->last_state[14] != data[14]) {
684 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[14] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
685 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[14] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
686 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[14] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
687 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[14] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
688 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[14] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
689 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[14] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
690 }
691
692 if (ctx->last_state[15] != data[15]) {
693 if (!ctx->has_guide_packet) {
694 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[15] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
695 }
696 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[15] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
697 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[15] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
698 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[15] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
699 }
700
701 if (ctx->has_share_button) {
702 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[15] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
703 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
704 } else {
705 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, ((data[15] & 0x04) || (data[16] & 0x01)) ? SDL_PRESSED : SDL_RELEASED);
706 }
707
708 /*
709 Paddle bits:
710 P3: 0x04 (A) P1: 0x01 (B)
711 P4: 0x08 (X) P2: 0x02 (Y)
712 */
713 if (ctx->has_paddles && (size == 39 || size == 55)) {
714 int paddle_index;
715 int button1_bit;
716 int button2_bit;
717 int button3_bit;
718 int button4_bit;
719 SDL_bool paddles_mapped;
720
721 if (size == 55) {
722 /* Initial firmware for the Xbox Elite Series 2 controller */
723 paddle_index = 33;
724 button1_bit = 0x01;
725 button2_bit = 0x02;
726 button3_bit = 0x04;
727 button4_bit = 0x08;
728 paddles_mapped = (data[35] != 0);
729 } else /* if (size == 39) */ {
730 /* Updated firmware for the Xbox Elite Series 2 controller */
731 paddle_index = 17;
732 button1_bit = 0x01;
733 button2_bit = 0x02;
734 button3_bit = 0x04;
735 button4_bit = 0x08;
736 paddles_mapped = (data[19] != 0);
737 }
738
739 #ifdef DEBUG_XBOX_PROTOCOL
740 SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s\n",
741 (data[paddle_index] & button1_bit) ? 1 : 0,
742 (data[paddle_index] & button2_bit) ? 1 : 0,
743 (data[paddle_index] & button3_bit) ? 1 : 0,
744 (data[paddle_index] & button4_bit) ? 1 : 0,
745 paddles_mapped ? "TRUE" : "FALSE"
746 );
747 #endif
748
749 if (paddles_mapped) {
750 /* Respect that the paddles are being used for other controls and don't pass them on to the app */
751 data[paddle_index] = 0;
752 }
753
754 if (ctx->last_state[paddle_index] != data[paddle_index]) {
755 int nButton = SDL_CONTROLLER_BUTTON_MISC1; /* Next available button */
756 SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button1_bit) ? SDL_PRESSED : SDL_RELEASED);
757 SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button2_bit) ? SDL_PRESSED : SDL_RELEASED);
758 SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button3_bit) ? SDL_PRESSED : SDL_RELEASED);
759 SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button4_bit) ? SDL_PRESSED : SDL_RELEASED);
760 }
761 }
762 }
763
764 static void
HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(SDL_Joystick * joystick,SDL_DriverXboxOne_Context * ctx,Uint8 * data,int size)765 HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
766 {
767 Sint16 axis;
768
769 if (size == 16) {
770 /* Original Xbox One S, with separate report for guide button */
771 HIDAPI_DriverXboxOneBluetooth_HandleButtons16(joystick, ctx, data, size);
772 } else if (size > 16) {
773 HIDAPI_DriverXboxOneBluetooth_HandleButtons(joystick, ctx, data, size);
774 } else {
775 #ifdef DEBUG_XBOX_PROTOCOL
776 SDL_Log("Unknown Bluetooth state packet format\n");
777 #endif
778 return;
779 }
780
781 if (ctx->last_state[13] != data[13]) {
782 SDL_bool dpad_up = SDL_FALSE;
783 SDL_bool dpad_down = SDL_FALSE;
784 SDL_bool dpad_left = SDL_FALSE;
785 SDL_bool dpad_right = SDL_FALSE;
786
787 switch (data[13]) {
788 case 1:
789 dpad_up = SDL_TRUE;
790 break;
791 case 2:
792 dpad_up = SDL_TRUE;
793 dpad_right = SDL_TRUE;
794 break;
795 case 3:
796 dpad_right = SDL_TRUE;
797 break;
798 case 4:
799 dpad_right = SDL_TRUE;
800 dpad_down = SDL_TRUE;
801 break;
802 case 5:
803 dpad_down = SDL_TRUE;
804 break;
805 case 6:
806 dpad_left = SDL_TRUE;
807 dpad_down = SDL_TRUE;
808 break;
809 case 7:
810 dpad_left = SDL_TRUE;
811 break;
812 case 8:
813 dpad_up = SDL_TRUE;
814 dpad_left = SDL_TRUE;
815 break;
816 default:
817 break;
818 }
819 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
820 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
821 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
822 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
823 }
824
825 axis = (int)*(Uint16*)(&data[1]) - 0x8000;
826 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
827 axis = (int)*(Uint16*)(&data[3]) - 0x8000;
828 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
829 axis = (int)*(Uint16*)(&data[5]) - 0x8000;
830 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
831 axis = (int)*(Uint16*)(&data[7]) - 0x8000;
832 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
833
834 axis = ((int)*(Sint16*)(&data[9]) * 64) - 32768;
835 if (axis == 32704) {
836 axis = 32767;
837 }
838 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
839
840 axis = ((int)*(Sint16*)(&data[11]) * 64) - 32768;
841 if (axis == 32704) {
842 axis = 32767;
843 }
844 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
845
846 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
847 }
848
849 static void
HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(SDL_Joystick * joystick,SDL_DriverXboxOne_Context * ctx,Uint8 * data,int size)850 HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
851 {
852 ctx->has_guide_packet = SDL_TRUE;
853 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
854 }
855
856 static void
HIDAPI_DriverXboxOneBluetooth_HandleBatteryPacket(SDL_Joystick * joystick,SDL_DriverXboxOne_Context * ctx,Uint8 * data,int size)857 HIDAPI_DriverXboxOneBluetooth_HandleBatteryPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
858 {
859 Uint8 flags = data[1];
860 SDL_bool on_usb = (((flags & 0x0C) >> 2) == 0);
861
862 if (on_usb) {
863 /* Does this ever happen? */
864 SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_WIRED);
865 } else {
866 switch ((flags & 0x03)) {
867 case 0:
868 SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_LOW);
869 break;
870 case 1:
871 SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_MEDIUM);
872 break;
873 default: /* 2, 3 */
874 SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_FULL);
875 break;
876 }
877 }
878 }
879
880 #ifdef SET_SERIAL_AFTER_OPEN
881 static void
HIDAPI_DriverXboxOne_HandleSerialIDPacket(SDL_Joystick * joystick,SDL_DriverXboxOne_Context * ctx,Uint8 * data,int size)882 HIDAPI_DriverXboxOne_HandleSerialIDPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
883 {
884 char serial[ 29 ];
885 int i;
886
887 for (i = 0; i < 14; ++i) {
888 SDL_uitoa( data[6 + i], &serial[i * 2], 16 );
889 }
890 serial[i * 2] = '\0';
891
892 if (!joystick->serial || SDL_strcmp(joystick->serial, serial) != 0) {
893 #ifdef DEBUG_JOYSTICK
894 SDL_Log("Setting serial number to %s\n", serial);
895 #endif
896 joystick->serial = SDL_strdup(serial);
897 }
898 }
899 #endif /* SET_SERIAL_AFTER_OPEN */
900
901 static SDL_bool
HIDAPI_DriverXboxOne_UpdateInitState(SDL_HIDAPI_Device * device,SDL_DriverXboxOne_Context * ctx)902 HIDAPI_DriverXboxOne_UpdateInitState(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
903 {
904 SDL_XboxOneInitState prev_state;
905 do
906 {
907 prev_state = ctx->init_state;
908
909 switch (ctx->init_state) {
910 case XBOX_ONE_INIT_STATE_START_NEGOTIATING:
911 #ifdef __WIN32__
912 /* The Windows driver is taking care of negotiation */
913 SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
914 #else
915 SetInitState(ctx, XBOX_ONE_INIT_STATE_NEGOTIATING);
916 ctx->init_packet = 0;
917 if (!SendControllerInit(device, ctx)) {
918 return SDL_FALSE;
919 }
920 #endif
921 break;
922 case XBOX_ONE_INIT_STATE_NEGOTIATING:
923 if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->send_time + CONTROLLER_NEGOTIATION_TIMEOUT_MS)) {
924 /* We haven't heard anything, let's move on */
925 #ifdef DEBUG_JOYSTICK
926 SDL_Log("Init sequence %d timed out after %u ms\n", ctx->init_packet, (SDL_GetTicks() - ctx->send_time));
927 #endif
928 ++ctx->init_packet;
929 if (!SendControllerInit(device, ctx)) {
930 return SDL_FALSE;
931 }
932 }
933 break;
934 case XBOX_ONE_INIT_STATE_PREPARE_INPUT:
935 if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->send_time + CONTROLLER_PREPARE_INPUT_TIMEOUT_MS)) {
936 #ifdef DEBUG_JOYSTICK
937 SDL_Log("Prepare input complete after %u ms\n", (SDL_GetTicks() - ctx->send_time));
938 #endif
939 SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
940 }
941 break;
942 case XBOX_ONE_INIT_STATE_COMPLETE:
943 break;
944 }
945
946 } while (ctx->init_state != prev_state);
947
948 return SDL_TRUE;
949 }
950
951 static SDL_bool
HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)952 HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
953 {
954 SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
955 Uint8 data[USB_PACKET_LENGTH];
956 int size;
957
958 while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
959 #ifdef DEBUG_XBOX_PROTOCOL
960 HIDAPI_DumpPacket("Xbox One packet: size = %d", data, size);
961 #endif
962 if (ctx->bluetooth) {
963 switch (data[0]) {
964 case 0x01:
965 if (size >= 16) {
966 HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(joystick, ctx, data, size);
967 } else {
968 #ifdef DEBUG_JOYSTICK
969 SDL_Log("Unknown Xbox One Bluetooth packet size: %d\n", size);
970 #endif
971 }
972 break;
973 case 0x02:
974 HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(joystick, ctx, data, size);
975 break;
976 case 0x04:
977 HIDAPI_DriverXboxOneBluetooth_HandleBatteryPacket(joystick, ctx, data, size);
978 break;
979 default:
980 #ifdef DEBUG_JOYSTICK
981 SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
982 #endif
983 break;
984 }
985 } else {
986 switch (data[0]) {
987 case 0x01:
988 /* ACK packet */
989 /* The data bytes are:
990 0x01 0x20 NN 0x09, where NN is the packet sequence
991 then 0x00
992 then a byte of the sequence being acked
993 then 0x20
994 then 16-bit LE value, the size of the previous packet payload when it's a single packet
995 then 4 bytes of unknown data, often all zero
996 */
997 break;
998 case 0x02:
999 /* Controller is connected and waiting for initialization */
1000 /* The data bytes are:
1001 0x02 0x20 NN 0x1c, where NN is the packet sequence
1002 then 6 bytes of wireless MAC address
1003 then 2 bytes padding
1004 then 16-bit VID
1005 then 16-bit PID
1006 then 16-bit firmware version quartet AA.BB.CC.DD
1007 e.g. 0x05 0x00 0x05 0x00 0x51 0x0a 0x00 0x00
1008 is firmware version 5.5.2641.0, and product version 0x0505 = 1285
1009 then 8 bytes of unknown data
1010 */
1011 if (data[1] == 0x20) {
1012 #ifdef DEBUG_JOYSTICK
1013 SDL_Log("Controller announce after %u ms\n", (SDL_GetTicks() - ctx->start_time));
1014 #endif
1015 SetInitState(ctx, XBOX_ONE_INIT_STATE_START_NEGOTIATING);
1016 } else {
1017 /* Possibly an announce from a device plugged into the controller */
1018 }
1019 break;
1020 case 0x03:
1021 /* Controller status update */
1022 HIDAPI_DriverXboxOne_HandleStatusPacket(joystick, ctx, data, size);
1023 break;
1024 case 0x04:
1025 /* Unknown chatty controller information, sent by both sides */
1026 break;
1027 case 0x06:
1028 /* Unknown chatty controller information, sent by both sides */
1029 break;
1030 case 0x07:
1031 HIDAPI_DriverXboxOne_HandleModePacket(joystick, ctx, data, size);
1032 break;
1033 case 0x1E:
1034 /* If the packet starts with this:
1035 0x1E 0x30 0x07 0x10 0x04 0x00
1036 then the next 14 bytes are the controller serial number
1037 e.g. 0x30 0x39 0x37 0x31 0x32 0x33 0x33 0x32 0x33 0x35 0x34 0x30 0x33 0x36
1038 is serial number "3039373132333332333534303336"
1039
1040 The controller sends that in response to this request:
1041 0x1E 0x30 0x07 0x01 0x04
1042 */
1043 #ifdef SET_SERIAL_AFTER_OPEN
1044 if (size == 20 && data[3] == 0x10) {
1045 HIDAPI_DriverXboxOne_HandleSerialIDPacket(joystick, ctx, data, size);
1046 }
1047 #endif
1048 break;
1049 case 0x20:
1050 if (ctx->init_state < XBOX_ONE_INIT_STATE_COMPLETE) {
1051 SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
1052
1053 /* Ignore the first input, it may be spurious */
1054 #ifdef DEBUG_JOYSTICK
1055 SDL_Log("Controller ignoring spurious input\n");
1056 #endif
1057 break;
1058 }
1059 HIDAPI_DriverXboxOne_HandleStatePacket(joystick, ctx, data, size);
1060 break;
1061 default:
1062 #ifdef DEBUG_JOYSTICK
1063 SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
1064 #endif
1065 break;
1066 }
1067
1068 SendAckIfNeeded(device, data, size);
1069
1070 if (ctx->init_state == XBOX_ONE_INIT_STATE_NEGOTIATING) {
1071 const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[ctx->init_packet];
1072
1073 if (size >= 4 && data[0] == packet->response[0] && data[1] == packet->response[1]) {
1074 #ifdef DEBUG_JOYSTICK
1075 SDL_Log("Init sequence %d got response after %u ms\n", ctx->init_packet, (SDL_GetTicks() - ctx->send_time));
1076 #endif
1077 ++ctx->init_packet;
1078 SendControllerInit(device, ctx);
1079 }
1080 }
1081 }
1082 }
1083
1084 HIDAPI_DriverXboxOne_UpdateInitState(device, ctx);
1085
1086 if (size < 0) {
1087 /* Read error, device is disconnected */
1088 HIDAPI_JoystickDisconnected(device, joystick->instance_id);
1089 }
1090 return (size >= 0);
1091 }
1092
1093 static SDL_bool
HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device * device)1094 HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
1095 {
1096 SDL_Joystick *joystick = NULL;
1097
1098 if (device->num_joysticks > 0) {
1099 joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
1100 }
1101 if (!joystick) {
1102 return SDL_FALSE;
1103 }
1104 return HIDAPI_DriverXboxOne_UpdateJoystick(device, joystick);
1105 }
1106
1107 static void
HIDAPI_DriverXboxOne_CloseJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)1108 HIDAPI_DriverXboxOne_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
1109 {
1110 SDL_LockMutex(device->dev_lock);
1111 {
1112 SDL_hid_close(device->dev);
1113 device->dev = NULL;
1114
1115 SDL_free(device->context);
1116 device->context = NULL;
1117 }
1118 SDL_UnlockMutex(device->dev_lock);
1119 }
1120
1121 static void
HIDAPI_DriverXboxOne_FreeDevice(SDL_HIDAPI_Device * device)1122 HIDAPI_DriverXboxOne_FreeDevice(SDL_HIDAPI_Device *device)
1123 {
1124 }
1125
1126 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
1127 {
1128 SDL_HINT_JOYSTICK_HIDAPI_XBOX,
1129 SDL_TRUE,
1130 SDL_TRUE,
1131 HIDAPI_DriverXboxOne_IsSupportedDevice,
1132 HIDAPI_DriverXboxOne_GetDeviceName,
1133 HIDAPI_DriverXboxOne_InitDevice,
1134 HIDAPI_DriverXboxOne_GetDevicePlayerIndex,
1135 HIDAPI_DriverXboxOne_SetDevicePlayerIndex,
1136 HIDAPI_DriverXboxOne_UpdateDevice,
1137 HIDAPI_DriverXboxOne_OpenJoystick,
1138 HIDAPI_DriverXboxOne_RumbleJoystick,
1139 HIDAPI_DriverXboxOne_RumbleJoystickTriggers,
1140 HIDAPI_DriverXboxOne_GetJoystickCapabilities,
1141 HIDAPI_DriverXboxOne_SetJoystickLED,
1142 HIDAPI_DriverXboxOne_SendJoystickEffect,
1143 HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled,
1144 HIDAPI_DriverXboxOne_CloseJoystick,
1145 HIDAPI_DriverXboxOne_FreeDevice,
1146 };
1147
1148 #endif /* SDL_JOYSTICK_HIDAPI_XBOXONE */
1149
1150 #endif /* SDL_JOYSTICK_HIDAPI */
1151
1152 /* vi: set ts=4 sw=4 expandtab: */
1153