Skip to content

Latest commit

 

History

History
767 lines (662 loc) · 27.6 KB

SDL_hidapi_xbox360.c

File metadata and controls

767 lines (662 loc) · 27.6 KB
 
1
2
/*
Simple DirectMedia Layer
Jan 17, 2020
Jan 17, 2020
3
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#ifdef SDL_JOYSTICK_HIDAPI
#include "SDL_hints.h"
#include "SDL_log.h"
#include "SDL_events.h"
#include "SDL_timer.h"
#include "SDL_joystick.h"
#include "SDL_gamecontroller.h"
#include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h"
Feb 4, 2020
Feb 4, 2020
33
#include "SDL_hidapi_rumble.h"
34
35
36
37
#ifdef SDL_JOYSTICK_HIDAPI_XBOX360
Aug 16, 2018
Aug 16, 2018
38
#ifdef __WIN32__
Sep 19, 2018
Sep 19, 2018
39
40
41
42
43
44
#define SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
/* This requires the Windows 10 SDK to build */
/*#define SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT*/
#endif
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
Aug 16, 2018
Aug 16, 2018
45
46
47
#include "../../core/windows/SDL_xinput.h"
#endif
Sep 19, 2018
Sep 19, 2018
48
49
50
51
52
53
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
#include "../../core/windows/SDL_windows.h"
#define COBJMACROS
#include "windows.gaming.input.h"
#endif
54
55
56
typedef struct {
Uint8 last_state[USB_PACKET_LENGTH];
Sep 19, 2018
Sep 19, 2018
57
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
Aug 16, 2018
Aug 16, 2018
58
59
60
SDL_bool xinput_enabled;
Uint8 xinput_slot;
#endif
Sep 19, 2018
Sep 19, 2018
61
62
63
64
65
66
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
SDL_bool coinitialized;
__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics;
__x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
#endif
67
68
69
} SDL_DriverXbox360_Context;
Sep 19, 2018
Sep 19, 2018
70
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
Aug 16, 2018
Aug 16, 2018
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
static Uint8 xinput_slots;
static void
HIDAPI_DriverXbox360_MarkXInputSlotUsed(Uint8 xinput_slot)
{
if (xinput_slot != XUSER_INDEX_ANY) {
xinput_slots |= (0x01 << xinput_slot);
}
}
static void
HIDAPI_DriverXbox360_MarkXInputSlotFree(Uint8 xinput_slot)
{
if (xinput_slot != XUSER_INDEX_ANY) {
xinput_slots &= ~(0x01 << xinput_slot);
}
}
static SDL_bool
HIDAPI_DriverXbox360_MissingXInputSlot()
{
return xinput_slots != 0x0F;
}
static Uint8
HIDAPI_DriverXbox360_GuessXInputSlot(WORD wButtons)
{
DWORD user_index;
int match_count;
Uint8 match_slot;
if (!XINPUTGETSTATE) {
return XUSER_INDEX_ANY;
}
match_count = 0;
for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) {
XINPUT_STATE_EX xinput_state;
if (XINPUTGETSTATE(user_index, &xinput_state) == ERROR_SUCCESS) {
if (xinput_state.Gamepad.wButtons == wButtons) {
++match_count;
match_slot = (Uint8)user_index;
}
}
}
if (match_count == 1) {
return match_slot;
}
return XUSER_INDEX_ANY;
}
Sep 19, 2018
Sep 19, 2018
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
static void
HIDAPI_DriverXbox360_InitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
{
/* I think this takes care of RoInitialize() in a way that is compatible with the rest of SDL */
if (FAILED(WIN_CoInitialize())) {
return;
}
ctx->coinitialized = SDL_TRUE;
{
static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } };
HRESULT hr;
HMODULE hModule = LoadLibraryA("combase.dll");
if (hModule != NULL) {
Sep 20, 2018
Sep 20, 2018
141
142
143
typedef HRESULT (WINAPI *WindowsCreateString_t)(PCNZWCH sourceString, UINT32 length, HSTRING* string);
typedef HRESULT (WINAPI *WindowsDeleteString_t)(HSTRING string);
typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory);
Sep 19, 2018
Sep 19, 2018
144
145
WindowsCreateString_t WindowsCreateStringFunc = (WindowsCreateString_t)GetProcAddress(hModule, "WindowsCreateString");
Sep 20, 2018
Sep 20, 2018
146
WindowsDeleteString_t WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule, "WindowsDeleteString");
Sep 19, 2018
Sep 19, 2018
147
RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory");
Sep 20, 2018
Sep 20, 2018
148
if (WindowsCreateStringFunc && WindowsDeleteStringFunc && RoGetActivationFactoryFunc) {
Sep 19, 2018
Sep 19, 2018
149
150
151
152
153
LPTSTR pNamespace = L"Windows.Gaming.Input.Gamepad";
HSTRING hNamespaceString;
hr = WindowsCreateStringFunc(pNamespace, SDL_wcslen(pNamespace), &hNamespaceString);
if (SUCCEEDED(hr)) {
Sep 20, 2018
Sep 20, 2018
154
155
RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, &ctx->gamepad_statics);
WindowsDeleteStringFunc(hNamespaceString);
Sep 19, 2018
Sep 19, 2018
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
}
}
FreeLibrary(hModule);
}
}
}
static Uint8
HIDAPI_DriverXbox360_GetGamepadButtonsForMatch(__x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad)
{
HRESULT hr;
struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
Uint8 buttons = 0;
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(gamepad, &state);
if (SUCCEEDED(hr)) {
if (state.Buttons & GamepadButtons_A) {
buttons |= (1 << SDL_CONTROLLER_BUTTON_A);
}
if (state.Buttons & GamepadButtons_B) {
buttons |= (1 << SDL_CONTROLLER_BUTTON_B);
}
if (state.Buttons & GamepadButtons_X) {
buttons |= (1 << SDL_CONTROLLER_BUTTON_X);
}
if (state.Buttons & GamepadButtons_Y) {
buttons |= (1 << SDL_CONTROLLER_BUTTON_Y);
}
}
return buttons;
}
static void
HIDAPI_DriverXbox360_GuessGamepad(SDL_DriverXbox360_Context *ctx, Uint8 buttons)
{
HRESULT hr;
__FIVectorView_1_Windows__CGaming__CInput__CGamepad *gamepads;
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_get_Gamepads(ctx->gamepad_statics, &gamepads);
if (SUCCEEDED(hr)) {
unsigned int i, num_gamepads;
hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_get_Size(gamepads, &num_gamepads);
if (SUCCEEDED(hr)) {
int match_count;
unsigned int match_slot;
match_count = 0;
for (i = 0; i < num_gamepads; ++i) {
__x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, i, &gamepad);
if (SUCCEEDED(hr)) {
Uint8 gamepad_buttons = HIDAPI_DriverXbox360_GetGamepadButtonsForMatch(gamepad);
if (buttons == gamepad_buttons) {
++match_count;
match_slot = i;
}
__x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
}
}
if (match_count == 1) {
hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, match_slot, &ctx->gamepad);
if (SUCCEEDED(hr)) {
}
}
}
__FIVectorView_1_Windows__CGaming__CInput__CGamepad_Release(gamepads);
}
}
static void
HIDAPI_DriverXbox360_QuitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
{
if (ctx->gamepad_statics) {
__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(ctx->gamepad_statics);
ctx->gamepad_statics = NULL;
}
if (ctx->gamepad) {
__x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(ctx->gamepad);
ctx->gamepad = NULL;
}
if (ctx->coinitialized) {
WIN_CoUninitialize();
ctx->coinitialized = SDL_FALSE;
}
}
#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
Aug 16, 2018
Aug 16, 2018
246
Mar 2, 2020
Mar 2, 2020
247
#if defined(__MACOSX__)
Mar 1, 2020
Mar 1, 2020
248
249
250
251
252
253
254
255
256
257
258
259
260
static SDL_bool
IsBluetoothXboxOneController(Uint16 vendor_id, Uint16 product_id)
{
/* Check to see if it's the Xbox One S or Xbox One Elite Series 2 in Bluetooth mode */
if (vendor_id == USB_VENDOR_MICROSOFT) {
if (product_id == USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH ||
product_id == USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH ||
product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
Mar 2, 2020
Mar 2, 2020
261
#endif
Mar 1, 2020
Mar 1, 2020
262
Jan 19, 2020
Jan 19, 2020
264
HIDAPI_DriverXbox360_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)
Jan 18, 2020
Jan 18, 2020
266
const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */
Nov 22, 2019
Nov 22, 2019
267
Jan 18, 2020
Jan 18, 2020
268
if (vendor_id == USB_VENDOR_NVIDIA) {
Dec 12, 2019
Dec 12, 2019
269
/* This is the NVIDIA Shield controller which doesn't talk Xbox controller protocol */
Nov 27, 2019
Nov 27, 2019
270
271
return SDL_FALSE;
}
Jan 18, 2020
Jan 18, 2020
272
273
274
275
if ((vendor_id == USB_VENDOR_MICROSOFT && (product_id == 0x0291 || product_id == 0x0719)) ||
(type == SDL_CONTROLLER_TYPE_XBOX360 && interface_protocol == XB360W_IFACE_PROTOCOL)) {
/* This is the wireless dongle, which talks a different protocol */
return SDL_FALSE;
Dec 20, 2019
Dec 20, 2019
276
}
Dec 17, 2019
Dec 17, 2019
277
278
279
280
if (interface_number > 0) {
/* This is the chatpad or other input interface, not the Xbox 360 interface */
return SDL_FALSE;
}
Aug 16, 2018
Aug 16, 2018
281
#if defined(__MACOSX__) || defined(__WIN32__)
Jan 18, 2020
Jan 18, 2020
282
if (vendor_id == USB_VENDOR_MICROSOFT && product_id == 0x028e && version == 1) {
Aug 16, 2018
Aug 16, 2018
283
284
285
/* This is the Steam Virtual Gamepad, which isn't supported by this driver */
return SDL_FALSE;
}
Mar 2, 2020
Mar 2, 2020
286
287
288
289
290
291
292
293
294
295
296
#if defined(__MACOSX__)
/* Wired Xbox One controllers are handled by this driver, interfacing with
the 360Controller driver available from:
https://github.com/360Controller/360Controller/releases
Bluetooth Xbox One controllers are handled by the SDL Xbox One driver
*/
if (IsBluetoothXboxOneController(vendor_id, product_id)) {
return SDL_FALSE;
}
#endif
Nov 22, 2019
Nov 22, 2019
297
return (type == SDL_CONTROLLER_TYPE_XBOX360 || type == SDL_CONTROLLER_TYPE_XBOXONE);
Nov 22, 2019
Nov 22, 2019
299
return (type == SDL_CONTROLLER_TYPE_XBOX360);
300
301
302
303
304
305
#endif
}
static const char *
HIDAPI_DriverXbox360_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
{
Dec 12, 2019
Dec 12, 2019
306
return NULL;
307
308
309
310
}
static SDL_bool SetSlotLED(hid_device *dev, Uint8 slot)
{
Dec 20, 2019
Dec 20, 2019
311
312
Uint8 mode = 0x02 + slot;
const Uint8 led_packet[] = { 0x01, 0x03, mode };
313
314
if (hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
Aug 16, 2018
Aug 16, 2018
315
316
317
return SDL_FALSE;
}
return SDL_TRUE;
318
319
320
}
static SDL_bool
Dec 19, 2019
Dec 19, 2019
321
322
323
324
325
HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *device)
{
return HIDAPI_JoystickConnected(device, NULL);
}
Dec 21, 2019
Dec 21, 2019
326
327
328
329
330
331
332
333
334
335
336
337
338
339
static int
HIDAPI_DriverXbox360_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
{
return -1;
}
static void
HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
{
if (device->dev) {
SetSlotLED(device->dev, (player_index % 4));
}
}
Dec 19, 2019
Dec 19, 2019
340
341
static SDL_bool
HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
342
343
{
SDL_DriverXbox360_Context *ctx;
Dec 21, 2019
Dec 21, 2019
344
int player_index;
345
346
347
348
349
350
ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
if (!ctx) {
SDL_OutOfMemory();
return SDL_FALSE;
}
Dec 19, 2019
Dec 19, 2019
351
352
353
354
355
356
357
358
359
device->dev = hid_open_path(device->path, 0);
if (!device->dev) {
SDL_free(ctx);
SDL_SetError("Couldn't open %s", device->path);
return SDL_FALSE;
}
device->context = ctx;
Sep 19, 2018
Sep 19, 2018
360
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
Aug 16, 2018
Aug 16, 2018
361
362
363
364
365
ctx->xinput_enabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE);
if (ctx->xinput_enabled && WIN_LoadXInputDLL() < 0) {
ctx->xinput_enabled = SDL_FALSE;
}
ctx->xinput_slot = XUSER_INDEX_ANY;
Sep 19, 2018
Sep 19, 2018
366
367
368
#endif
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
Aug 16, 2018
Aug 16, 2018
369
#endif
370
371
/* Set the controller LED */
Dec 21, 2019
Dec 21, 2019
372
373
374
375
player_index = SDL_JoystickGetPlayerIndex(joystick);
if (player_index >= 0) {
SetSlotLED(device->dev, (player_index % 4));
}
376
377
378
379
380
381
382
383
384
385
/* Initialize the joystick capabilities */
joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
return SDL_TRUE;
}
static int
Feb 4, 2020
Feb 4, 2020
386
HIDAPI_DriverXbox360_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
Feb 4, 2020
Feb 4, 2020
388
#if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT)
Dec 19, 2019
Dec 19, 2019
389
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
Feb 4, 2020
Feb 4, 2020
390
#endif
Sep 19, 2018
Sep 19, 2018
391
Aug 16, 2018
Aug 16, 2018
392
#ifdef __WIN32__
Sep 19, 2018
Sep 19, 2018
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
SDL_bool rumbled = SDL_FALSE;
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
if (!rumbled && ctx->gamepad) {
HRESULT hr;
ctx->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
ctx->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(ctx->gamepad, ctx->vibration);
if (SUCCEEDED(hr)) {
rumbled = SDL_TRUE;
}
}
#endif
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
if (!rumbled && ctx->xinput_slot != XUSER_INDEX_ANY) {
Aug 16, 2018
Aug 16, 2018
410
411
412
413
414
415
416
417
XINPUT_VIBRATION XVibration;
if (!XINPUTSETSTATE) {
return SDL_Unsupported();
}
XVibration.wLeftMotorSpeed = low_frequency_rumble;
XVibration.wRightMotorSpeed = high_frequency_rumble;
Sep 19, 2018
Sep 19, 2018
418
419
420
if (XINPUTSETSTATE(ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) {
rumbled = SDL_TRUE;
} else {
Aug 16, 2018
Aug 16, 2018
421
422
423
return SDL_SetError("XInputSetState() failed");
}
}
Sep 19, 2018
Sep 19, 2018
424
425
426
427
#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
#else /* !__WIN32__ */
Mar 1, 2020
Mar 1, 2020
429
430
431
432
433
if (IsBluetoothXboxOneController(device->vendor_id, device->product_id)) {
Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00 };
rumble_packet[4] = (low_frequency_rumble >> 8);
rumble_packet[5] = (high_frequency_rumble >> 8);
Mar 1, 2020
Mar 1, 2020
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
} else {
/* On Mac OS X the 360Controller driver uses this short report,
and we need to prefix it with a magic token so hidapi passes it through untouched
*/
Uint8 rumble_packet[] = { 'M', 'A', 'G', 'I', 'C', '0', 0x00, 0x04, 0x00, 0x00 };
rumble_packet[6+2] = (low_frequency_rumble >> 8);
rumble_packet[6+3] = (high_frequency_rumble >> 8);
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
}
451
452
453
454
455
456
#else
Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
rumble_packet[3] = (low_frequency_rumble >> 8);
rumble_packet[4] = (high_frequency_rumble >> 8);
Feb 4, 2020
Feb 4, 2020
457
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
458
459
return SDL_SetError("Couldn't send rumble packet");
}
Mar 1, 2020
Mar 1, 2020
460
#endif
Aug 16, 2018
Aug 16, 2018
461
#endif /* __WIN32__ */
Aug 16, 2018
Aug 16, 2018
466
#ifdef __WIN32__
Aug 16, 2018
Aug 16, 2018
467
468
469
/* This is the packet format for Xbox 360 and Xbox One controllers on Windows,
however with this interface there is no rumble support, no guide button,
and the left and right triggers are tied together as a single axis.
Sep 19, 2018
Sep 19, 2018
470
471
We use XInput and Windows.Gaming.Input to make up for these shortcomings.
Aug 16, 2018
Aug 16, 2018
472
473
*/
static void
Aug 16, 2018
Aug 16, 2018
474
HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
Aug 16, 2018
Aug 16, 2018
475
476
{
Sint16 axis;
Sep 19, 2018
Sep 19, 2018
477
SDL_bool has_trigger_data = SDL_FALSE;
Aug 16, 2018
Aug 16, 2018
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
if (ctx->last_state[10] != data[10]) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[10] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[10] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[10] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[10] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[10] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[10] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[10] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[10] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[11] != data[11]) {
SDL_bool dpad_up = SDL_FALSE;
SDL_bool dpad_down = SDL_FALSE;
SDL_bool dpad_left = SDL_FALSE;
SDL_bool dpad_right = SDL_FALSE;
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[11] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[11] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
switch (data[11] & 0x3C) {
case 4:
dpad_up = SDL_TRUE;
break;
case 8:
dpad_up = SDL_TRUE;
dpad_right = SDL_TRUE;
break;
case 12:
dpad_right = SDL_TRUE;
break;
case 16:
dpad_right = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 20:
dpad_down = SDL_TRUE;
break;
case 24:
dpad_left = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 28:
dpad_left = SDL_TRUE;
break;
case 32:
dpad_up = SDL_TRUE;
dpad_left = SDL_TRUE;
break;
default:
break;
}
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
}
axis = (int)*(Uint16*)(&data[0]) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
axis = (int)*(Uint16*)(&data[2]) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
axis = (int)*(Uint16*)(&data[4]) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
axis = (int)*(Uint16*)(&data[6]) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
Sep 19, 2018
Sep 19, 2018
546
547
548
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
if (ctx->gamepad_statics && !ctx->gamepad) {
Uint8 buttons = 0;
Aug 16, 2018
Aug 16, 2018
549
550
if (data[10] & 0x01) {
Sep 19, 2018
Sep 19, 2018
551
buttons |= (1 << SDL_CONTROLLER_BUTTON_A);
Aug 16, 2018
Aug 16, 2018
552
553
}
if (data[10] & 0x02) {
Sep 19, 2018
Sep 19, 2018
554
buttons |= (1 << SDL_CONTROLLER_BUTTON_B);
Aug 16, 2018
Aug 16, 2018
555
556
}
if (data[10] & 0x04) {
Sep 19, 2018
Sep 19, 2018
557
buttons |= (1 << SDL_CONTROLLER_BUTTON_X);
Aug 16, 2018
Aug 16, 2018
558
559
}
if (data[10] & 0x08) {
Sep 19, 2018
Sep 19, 2018
560
561
562
563
buttons |= (1 << SDL_CONTROLLER_BUTTON_Y);
}
if (buttons != 0) {
HIDAPI_DriverXbox360_GuessGamepad(ctx, buttons);
Aug 16, 2018
Aug 16, 2018
564
}
Sep 19, 2018
Sep 19, 2018
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
}
if (ctx->gamepad) {
HRESULT hr;
struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(ctx->gamepad, &state);
if (SUCCEEDED(hr)) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (state.Buttons & 0x40000000) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)(state.LeftTrigger * SDL_MAX_UINT16)) - 32768);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)(state.RightTrigger * SDL_MAX_UINT16)) - 32768);
has_trigger_data = SDL_TRUE;
}
}
#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
if (ctx->xinput_enabled) {
if (ctx->xinput_slot == XUSER_INDEX_ANY && HIDAPI_DriverXbox360_MissingXInputSlot()) {
WORD wButtons = 0;
if (data[10] & 0x01) {
wButtons |= XINPUT_GAMEPAD_A;
}
if (data[10] & 0x02) {
wButtons |= XINPUT_GAMEPAD_B;
}
if (data[10] & 0x04) {
wButtons |= XINPUT_GAMEPAD_X;
}
if (data[10] & 0x08) {
wButtons |= XINPUT_GAMEPAD_Y;
}
if (wButtons != 0) {
Uint8 xinput_slot = HIDAPI_DriverXbox360_GuessXInputSlot(wButtons);
if (xinput_slot != XUSER_INDEX_ANY) {
HIDAPI_DriverXbox360_MarkXInputSlotUsed(xinput_slot);
ctx->xinput_slot = xinput_slot;
}
}
}
if (!has_trigger_data && ctx->xinput_slot != XUSER_INDEX_ANY) {
XINPUT_STATE_EX xinput_state;
if (XINPUTGETSTATE(ctx->xinput_slot, &xinput_state) == ERROR_SUCCESS) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (xinput_state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)xinput_state.Gamepad.bLeftTrigger * 257) - 32768);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)xinput_state.Gamepad.bRightTrigger * 257) - 32768);
has_trigger_data = SDL_TRUE;
Aug 16, 2018
Aug 16, 2018
615
616
617
}
}
}
Sep 19, 2018
Sep 19, 2018
618
#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
Aug 16, 2018
Aug 16, 2018
619
Sep 19, 2018
Sep 19, 2018
620
if (!has_trigger_data) {
Aug 16, 2018
Aug 16, 2018
621
622
623
624
625
626
627
628
629
630
631
axis = (data[9] * 257) - 32768;
if (data[9] < 0x80) {
axis = -axis * 2 - 32769;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
} else if (data[9] > 0x80) {
axis = axis * 2 - 32767;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
} else {
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_MIN_SINT16);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, SDL_MIN_SINT16);
}
Aug 16, 2018
Aug 16, 2018
632
633
634
635
}
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
Aug 16, 2018
Aug 16, 2018
636
#else
Aug 16, 2018
Aug 16, 2018
637
638
639
640
641
642
static void
HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
{
Sint16 axis;
#ifdef __MACOSX__
Aug 16, 2018
Aug 16, 2018
643
const SDL_bool invert_y_axes = SDL_FALSE;
Aug 16, 2018
Aug 16, 2018
645
const SDL_bool invert_y_axes = SDL_TRUE;
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
#endif
if (ctx->last_state[2] != data[2]) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[2] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[2] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[2] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[2] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[2] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[2] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[3] != data[3]) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[3] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[3] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[3] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[3] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[3] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[3] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[3] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
axis = ((int)data[4] * 257) - 32768;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
axis = ((int)data[5] * 257) - 32768;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
axis = *(Sint16*)(&data[6]);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
axis = *(Sint16*)(&data[8]);
Aug 16, 2018
Aug 16, 2018
676
677
678
if (invert_y_axes) {
axis = ~axis;
}
679
680
681
682
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
axis = *(Sint16*)(&data[10]);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
axis = *(Sint16*)(&data[12]);
Aug 16, 2018
Aug 16, 2018
683
684
685
if (invert_y_axes) {
axis = ~axis;
}
686
687
688
689
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
Aug 16, 2018
Aug 16, 2018
690
#endif /* __WIN32__ */
Aug 16, 2018
Aug 16, 2018
692
static SDL_bool
Dec 19, 2019
Dec 19, 2019
693
HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
Dec 19, 2019
Dec 19, 2019
695
696
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
SDL_Joystick *joystick = NULL;
697
698
699
Uint8 data[USB_PACKET_LENGTH];
int size;
Dec 19, 2019
Dec 19, 2019
700
701
702
703
704
705
706
707
708
if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
}
if (!joystick) {
return SDL_FALSE;
}
while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
HIDAPI_DriverXbox360_HandleStatePacket(joystick, device->dev, ctx, data, size);
Dec 19, 2019
Dec 19, 2019
711
712
713
714
if (size < 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
}
Aug 16, 2018
Aug 16, 2018
715
return (size >= 0);
Dec 19, 2019
Dec 19, 2019
719
HIDAPI_DriverXbox360_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
Feb 4, 2020
Feb 4, 2020
721
#if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
Dec 19, 2019
Dec 19, 2019
722
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
Feb 4, 2020
Feb 4, 2020
723
#endif
Aug 16, 2018
Aug 16, 2018
724
Sep 19, 2018
Sep 19, 2018
725
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
Aug 16, 2018
Aug 16, 2018
726
727
728
729
if (ctx->xinput_enabled) {
HIDAPI_DriverXbox360_MarkXInputSlotFree(ctx->xinput_slot);
WIN_UnloadXInputDLL();
}
Sep 19, 2018
Sep 19, 2018
730
731
#endif
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
Dec 19, 2019
Dec 19, 2019
732
HIDAPI_DriverXbox360_QuitWindowsGamingInput(ctx);
Aug 16, 2018
Aug 16, 2018
733
#endif
Dec 19, 2019
Dec 19, 2019
734
735
736
737
738
739
740
741
742
743
744
hid_close(device->dev);
device->dev = NULL;
SDL_free(device->context);
device->context = NULL;
}
static void
HIDAPI_DriverXbox360_FreeDevice(SDL_HIDAPI_Device *device)
{
745
746
747
748
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 =
{
Aug 16, 2018
Aug 16, 2018
749
SDL_HINT_JOYSTICK_HIDAPI_XBOX,
750
751
752
SDL_TRUE,
HIDAPI_DriverXbox360_IsSupportedDevice,
HIDAPI_DriverXbox360_GetDeviceName,
Dec 19, 2019
Dec 19, 2019
753
HIDAPI_DriverXbox360_InitDevice,
Dec 21, 2019
Dec 21, 2019
754
755
HIDAPI_DriverXbox360_GetDevicePlayerIndex,
HIDAPI_DriverXbox360_SetDevicePlayerIndex,
Dec 19, 2019
Dec 19, 2019
756
757
758
759
760
HIDAPI_DriverXbox360_UpdateDevice,
HIDAPI_DriverXbox360_OpenJoystick,
HIDAPI_DriverXbox360_RumbleJoystick,
HIDAPI_DriverXbox360_CloseJoystick,
HIDAPI_DriverXbox360_FreeDevice
761
762
763
764
765
766
767
};
#endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
#endif /* SDL_JOYSTICK_HIDAPI */
/* vi: set ts=4 sw=4 expandtab: */