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