Skip to content

Latest commit

 

History

History
1317 lines (1182 loc) · 56.8 KB

SDL_hidapi_xbox360.c

File metadata and controls

1317 lines (1182 loc) · 56.8 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
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_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
32
#include "SDL_hidapi_rumble.h"
33
34
35
36
#ifdef SDL_JOYSTICK_HIDAPI_XBOX360
Aug 16, 2018
Aug 16, 2018
37
#ifdef __WIN32__
Sep 19, 2018
Sep 19, 2018
38
39
40
41
42
43
#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
44
45
46
#include "../../core/windows/SDL_xinput.h"
#endif
Sep 19, 2018
Sep 19, 2018
47
48
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
#include "../../core/windows/SDL_windows.h"
Mar 16, 2020
Mar 16, 2020
49
50
typedef struct WindowsGamingInputGamepadState WindowsGamingInputGamepadState;
#define GamepadButtons_GUIDE 0x40000000
Sep 19, 2018
Sep 19, 2018
51
52
53
54
#define COBJMACROS
#include "windows.gaming.input.h"
#endif
Mar 16, 2020
Mar 16, 2020
55
56
57
#if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
#define SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
#endif
58
59
60
typedef struct {
Uint8 last_state[USB_PACKET_LENGTH];
Mar 16, 2020
Mar 16, 2020
61
62
63
64
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
Uint32 match_state; /* Low 16 bits for button states, high 16 for 4 4bit axes */
Uint32 last_state_packet;
#endif
Sep 19, 2018
Sep 19, 2018
65
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
Aug 16, 2018
Aug 16, 2018
66
SDL_bool xinput_enabled;
Mar 16, 2020
Mar 16, 2020
67
68
69
70
SDL_bool xinput_correlated;
Uint8 xinput_correlation_id;
Uint8 xinput_correlation_count;
Uint8 xinput_uncorrelate_count;
Aug 16, 2018
Aug 16, 2018
71
72
Uint8 xinput_slot;
#endif
Sep 19, 2018
Sep 19, 2018
73
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
Mar 16, 2020
Mar 16, 2020
74
75
76
77
78
SDL_bool wgi_correlated;
Uint8 wgi_correlation_id;
Uint8 wgi_correlation_count;
Uint8 wgi_uncorrelate_count;
WindowsGamingInputGamepadState *wgi_slot;
Sep 19, 2018
Sep 19, 2018
79
#endif
80
81
} SDL_DriverXbox360_Context;
Mar 16, 2020
Mar 16, 2020
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
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
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
static struct {
Uint32 last_state_packet;
SDL_Joystick *joystick;
SDL_Joystick *last_joystick;
} guide_button_candidate;
typedef struct WindowsMatchState {
SHORT match_axes[4];
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
WORD xinput_buttons;
#endif
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
Uint32 wgi_buttons;
#endif
SDL_bool any_data;
} WindowsMatchState;
static void HIDAPI_DriverXbox360_FillMatchState(WindowsMatchState *state, Uint32 match_state)
{
int ii;
state->any_data = SDL_FALSE;
/* SHORT state->match_axes[4] = {
(match_state & 0x000F0000) >> 4,
(match_state & 0x00F00000) >> 8,
(match_state & 0x0F000000) >> 12,
(match_state & 0xF0000000) >> 16,
}; */
for (ii = 0; ii < 4; ii++) {
state->match_axes[ii] = (match_state & (0x000F0000 << (ii * 4))) >> (4 + ii * 4);
if ((Uint32)(state->match_axes[ii] + 0x1000) > 0x2000) { /* match_state bit is not 0xF, 0x1, or 0x2 */
state->any_data = SDL_TRUE;
}
}
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
/* Match axes by checking if the distance between the high 4 bits of axis and the 4 bits from match_state is 1 or less */
#define XInputAxesMatch(gamepad) (\
(Uint32)(gamepad.sThumbLX - state->match_axes[0] + 0x1000) <= 0x2fff && \
(Uint32)(~gamepad.sThumbLY - state->match_axes[1] + 0x1000) <= 0x2fff && \
(Uint32)(gamepad.sThumbRX - state->match_axes[2] + 0x1000) <= 0x2fff && \
(Uint32)(~gamepad.sThumbRY - state->match_axes[3] + 0x1000) <= 0x2fff)
/* Explicit
#define XInputAxesMatch(gamepad) (\
SDL_abs((Sint8)((gamepad.sThumbLX & 0xF000) >> 8) - ((match_state & 0x000F0000) >> 12)) <= 0x10 && \
SDL_abs((Sint8)((~gamepad.sThumbLY & 0xF000) >> 8) - ((match_state & 0x00F00000) >> 16)) <= 0x10 && \
SDL_abs((Sint8)((gamepad.sThumbRX & 0xF000) >> 8) - ((match_state & 0x0F000000) >> 20)) <= 0x10 && \
SDL_abs((Sint8)((~gamepad.sThumbRY & 0xF000) >> 8) - ((match_state & 0xF0000000) >> 24)) <= 0x10) */
state->xinput_buttons =
/* Bitwise map .RLDUWVQTS.KYXBA -> YXBA..WVQTKSRLDU */
match_state << 12 | (match_state & 0x0780) >> 1 | (match_state & 0x0010) << 1 | (match_state & 0x0040) >> 2 | (match_state & 0x7800) >> 11;
/* Explicit
((match_state & (1<<SDL_CONTROLLER_BUTTON_A)) ? XINPUT_GAMEPAD_A : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_B)) ? XINPUT_GAMEPAD_B : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_X)) ? XINPUT_GAMEPAD_X : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_Y)) ? XINPUT_GAMEPAD_Y : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_BACK)) ? XINPUT_GAMEPAD_BACK : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_START)) ? XINPUT_GAMEPAD_START : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSTICK)) ? XINPUT_GAMEPAD_LEFT_THUMB : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSTICK)) ? XINPUT_GAMEPAD_RIGHT_THUMB: 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) ? XINPUT_GAMEPAD_LEFT_SHOULDER : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) ? XINPUT_GAMEPAD_RIGHT_SHOULDER : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_UP)) ? XINPUT_GAMEPAD_DPAD_UP : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_DOWN)) ? XINPUT_GAMEPAD_DPAD_DOWN : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_LEFT)) ? XINPUT_GAMEPAD_DPAD_LEFT : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) ? XINPUT_GAMEPAD_DPAD_RIGHT : 0);
*/
if (state->xinput_buttons)
state->any_data = SDL_TRUE;
#endif
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
/* Match axes by checking if the distance between the high 4 bits of axis and the 4 bits from match_state is 1 or less */
#define WindowsGamingInputAxesMatch(gamepad) (\
(Uint16)(((Sint16)(gamepad.LeftThumbstickX * SDL_MAX_SINT16) & 0xF000) - state->match_axes[0] + 0x1000) <= 0x2fff && \
(Uint16)((~(Sint16)(gamepad.LeftThumbstickY * SDL_MAX_SINT16) & 0xF000) - state->match_axes[1] + 0x1000) <= 0x2fff && \
(Uint16)(((Sint16)(gamepad.RightThumbstickX * SDL_MAX_SINT16) & 0xF000) - state->match_axes[2] + 0x1000) <= 0x2fff && \
(Uint16)((~(Sint16)(gamepad.RightThumbstickY * SDL_MAX_SINT16) & 0xF000) - state->match_axes[3] + 0x1000) <= 0x2fff)
state->wgi_buttons =
/* Bitwise map .RLD UWVQ TS.K YXBA -> ..QT WVRL DUYX BAKS */
/* RStick/LStick (QT) RShould/LShould (WV) DPad R/L/D/U YXBA bac(K) (S)tart */
(match_state & 0x0180) << 5 | (match_state & 0x0600) << 1 | (match_state & 0x7800) >> 5 | (match_state & 0x000F) << 2 | (match_state & 0x0010) >> 3 | (match_state & 0x0040) >> 6;
/* Explicit
((match_state & (1<<SDL_CONTROLLER_BUTTON_A)) ? GamepadButtons_A : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_B)) ? GamepadButtons_B : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_X)) ? GamepadButtons_X : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_Y)) ? GamepadButtons_Y : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_BACK)) ? GamepadButtons_View : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_START)) ? GamepadButtons_Menu : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSTICK)) ? GamepadButtons_LeftThumbstick : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSTICK)) ? GamepadButtons_RightThumbstick: 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) ? GamepadButtons_LeftShoulder: 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) ? GamepadButtons_RightShoulder: 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_UP)) ? GamepadButtons_DPadUp : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_DOWN)) ? GamepadButtons_DPadDown : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_LEFT)) ? GamepadButtons_DPadLeft : 0) |
((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) ? GamepadButtons_DPadRight : 0); */
if (state->wgi_buttons)
state->any_data = SDL_TRUE;
#endif
}
#endif
Sep 19, 2018
Sep 19, 2018
194
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
Mar 16, 2020
Mar 16, 2020
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
static struct {
XINPUT_STATE_EX state;
SDL_bool connected; /* Currently has an active XInput device */
SDL_bool used; /* Is currently mapped to an SDL device */
Uint8 correlation_id;
} xinput_state[XUSER_MAX_COUNT];
static SDL_bool xinput_device_change = SDL_TRUE;
static SDL_bool xinput_state_dirty = SDL_TRUE;
static void
HIDAPI_DriverXbox360_UpdateXInput()
{
DWORD user_index;
if (xinput_device_change) {
for (user_index = 0; user_index < XUSER_MAX_COUNT; user_index++) {
XINPUT_CAPABILITIES capabilities;
xinput_state[user_index].connected = XINPUTGETCAPABILITIES(user_index, XINPUT_FLAG_GAMEPAD, &capabilities) == ERROR_SUCCESS;
}
xinput_device_change = SDL_FALSE;
xinput_state_dirty = SDL_TRUE;
}
if (xinput_state_dirty) {
xinput_state_dirty = SDL_FALSE;
for (user_index = 0; user_index < SDL_arraysize(xinput_state); ++user_index) {
if (xinput_state[user_index].connected) {
Apr 14, 2020
Apr 14, 2020
220
if (XINPUTGETSTATE(user_index, &xinput_state[user_index].state) != ERROR_SUCCESS) {
Mar 16, 2020
Mar 16, 2020
221
222
223
224
225
226
xinput_state[user_index].connected = SDL_FALSE;
}
}
}
}
}
Aug 16, 2018
Aug 16, 2018
227
228
229
230
231
static void
HIDAPI_DriverXbox360_MarkXInputSlotUsed(Uint8 xinput_slot)
{
if (xinput_slot != XUSER_INDEX_ANY) {
Mar 16, 2020
Mar 16, 2020
232
xinput_state[xinput_slot].used = SDL_TRUE;
Aug 16, 2018
Aug 16, 2018
233
234
235
236
237
238
239
}
}
static void
HIDAPI_DriverXbox360_MarkXInputSlotFree(Uint8 xinput_slot)
{
if (xinput_slot != XUSER_INDEX_ANY) {
Mar 16, 2020
Mar 16, 2020
240
xinput_state[xinput_slot].used = SDL_FALSE;
Aug 16, 2018
Aug 16, 2018
241
242
243
244
245
}
}
static SDL_bool
HIDAPI_DriverXbox360_MissingXInputSlot()
{
Mar 16, 2020
Mar 16, 2020
246
247
248
249
250
251
252
int ii;
for (ii = 0; ii < SDL_arraysize(xinput_state); ii++) {
if (xinput_state[ii].connected && !xinput_state[ii].used) {
return SDL_TRUE;
}
}
return SDL_FALSE;
Aug 16, 2018
Aug 16, 2018
253
254
}
Mar 16, 2020
Mar 16, 2020
255
256
static SDL_bool
HIDAPI_DriverXbox360_XInputSlotMatches(const WindowsMatchState *state, Uint8 slot_idx)
Aug 16, 2018
Aug 16, 2018
257
{
Mar 16, 2020
Mar 16, 2020
258
259
260
261
262
if (xinput_state[slot_idx].connected) {
WORD xinput_buttons = xinput_state[slot_idx].state.Gamepad.wButtons;
if ((xinput_buttons & ~XINPUT_GAMEPAD_GUIDE) == state->xinput_buttons && XInputAxesMatch(xinput_state[slot_idx].state.Gamepad)) {
return SDL_TRUE;
}
Aug 16, 2018
Aug 16, 2018
263
}
Mar 16, 2020
Mar 16, 2020
264
265
266
267
268
269
270
271
272
return SDL_FALSE;
}
static SDL_bool
HIDAPI_DriverXbox360_GuessXInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, Uint8 *slot_idx)
{
int user_index;
int match_count;
Aug 16, 2018
Aug 16, 2018
273
May 20, 2020
May 20, 2020
274
275
*slot_idx = 0;
Aug 16, 2018
Aug 16, 2018
276
277
match_count = 0;
for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) {
Mar 16, 2020
Mar 16, 2020
278
279
280
281
282
if (!xinput_state[user_index].used && HIDAPI_DriverXbox360_XInputSlotMatches(state, user_index)) {
++match_count;
*slot_idx = (Uint8)user_index;
/* Incrementing correlation_id for any match, as negative evidence for others being correlated */
*correlation_id = ++xinput_state[user_index].correlation_id;
Aug 16, 2018
Aug 16, 2018
283
284
}
}
Mar 16, 2020
Mar 16, 2020
285
286
287
288
289
/* Only return a match if we match exactly one, and we have some non-zero data (buttons or axes) that matched.
Note that we're still invalidating *other* potential correlations if we have more than one match or we have no
data. */
if (match_count == 1 && state->any_data) {
return SDL_TRUE;
Aug 16, 2018
Aug 16, 2018
290
}
Mar 16, 2020
Mar 16, 2020
291
return SDL_FALSE;
Aug 16, 2018
Aug 16, 2018
292
293
}
Sep 19, 2018
Sep 19, 2018
294
295
296
297
#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
Mar 16, 2020
Mar 16, 2020
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
typedef struct WindowsGamingInputGamepadState {
__x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
SDL_DriverXbox360_Context *correlated_context;
SDL_bool used; /* Is currently mapped to an SDL device */
SDL_bool connected; /* Just used during update to track disconnected */
Uint8 correlation_id;
struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
} WindowsGamingInputGamepadState;
static struct {
WindowsGamingInputGamepadState **per_gamepad;
int per_gamepad_count;
SDL_bool initialized;
SDL_bool dirty;
SDL_bool need_device_list_update;
int ref_count;
__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics;
} wgi_state;
Sep 19, 2018
Sep 19, 2018
318
static void
Mar 16, 2020
Mar 16, 2020
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
HIDAPI_DriverXbox360_MarkWindowsGamingInputSlotUsed(WindowsGamingInputGamepadState *wgi_slot, SDL_DriverXbox360_Context *ctx)
{
wgi_slot->used = SDL_TRUE;
wgi_slot->correlated_context = ctx;
}
static void
HIDAPI_DriverXbox360_MarkWindowsGamingInputSlotFree(WindowsGamingInputGamepadState *wgi_slot)
{
wgi_slot->used = SDL_FALSE;
wgi_slot->correlated_context = NULL;
}
static SDL_bool
HIDAPI_DriverXbox360_MissingWindowsGamingInputSlot()
{
int ii;
for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
if (!wgi_state.per_gamepad[ii]->used) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
static void
HIDAPI_DriverXbox360_UpdateWindowsGamingInput()
Sep 19, 2018
Sep 19, 2018
346
{
Mar 16, 2020
Mar 16, 2020
347
348
349
350
351
int ii;
if (!wgi_state.gamepad_statics)
return;
if (!wgi_state.dirty)
Sep 19, 2018
Sep 19, 2018
352
return;
Mar 16, 2020
Mar 16, 2020
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
wgi_state.dirty = SDL_FALSE;
if (wgi_state.need_device_list_update) {
wgi_state.need_device_list_update = SDL_FALSE;
for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
wgi_state.per_gamepad[ii]->connected = SDL_FALSE;
}
HRESULT hr;
__FIVectorView_1_Windows__CGaming__CInput__CGamepad *gamepads;
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_get_Gamepads(wgi_state.gamepad_statics, &gamepads);
if (SUCCEEDED(hr)) {
unsigned int num_gamepads;
hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_get_Size(gamepads, &num_gamepads);
if (SUCCEEDED(hr)) {
unsigned int i;
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)) {
SDL_bool found = SDL_FALSE;
int jj;
for (jj = 0; jj < wgi_state.per_gamepad_count ; jj++) {
if (wgi_state.per_gamepad[jj]->gamepad == gamepad) {
found = SDL_TRUE;
wgi_state.per_gamepad[jj]->connected = SDL_TRUE;
break;
}
}
if (!found) {
/* New device, add it */
wgi_state.per_gamepad_count++;
wgi_state.per_gamepad = SDL_realloc(wgi_state.per_gamepad, sizeof(wgi_state.per_gamepad[0]) * wgi_state.per_gamepad_count);
if (!wgi_state.per_gamepad) {
SDL_OutOfMemory();
return;
}
WindowsGamingInputGamepadState *gamepad_state = SDL_calloc(1, sizeof(*gamepad_state));
if (!gamepad_state) {
SDL_OutOfMemory();
return;
}
wgi_state.per_gamepad[wgi_state.per_gamepad_count - 1] = gamepad_state;
gamepad_state->gamepad = gamepad;
gamepad_state->connected = SDL_TRUE;
} else {
/* Already tracked */
__x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
}
}
}
for (ii = wgi_state.per_gamepad_count - 1; ii >= 0; ii--) {
WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[ii];
if (!gamepad_state->connected) {
/* Device missing, must be disconnected */
if (gamepad_state->correlated_context) {
gamepad_state->correlated_context->wgi_correlated = SDL_FALSE;
gamepad_state->correlated_context->wgi_slot = NULL;
}
__x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad_state->gamepad);
SDL_free(gamepad_state);
wgi_state.per_gamepad[ii] = wgi_state.per_gamepad[wgi_state.per_gamepad_count - 1];
--wgi_state.per_gamepad_count;
}
}
}
__FIVectorView_1_Windows__CGaming__CInput__CGamepad_Release(gamepads);
}
} /* need_device_list_update */
for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
HRESULT hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(wgi_state.per_gamepad[ii]->gamepad, &wgi_state.per_gamepad[ii]->state);
if (!SUCCEEDED(hr)) {
wgi_state.per_gamepad[ii]->connected = SDL_FALSE; /* Not used by anything, currently */
}
Sep 19, 2018
Sep 19, 2018
430
}
Mar 16, 2020
Mar 16, 2020
431
432
433
434
435
436
437
438
439
440
441
442
443
}
static void
HIDAPI_DriverXbox360_InitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
{
wgi_state.need_device_list_update = SDL_TRUE;
wgi_state.ref_count++;
if (!wgi_state.initialized) {
/* I think this takes care of RoInitialize() in a way that is compatible with the rest of SDL */
if (FAILED(WIN_CoInitialize())) {
return;
}
wgi_state.initialized = SDL_TRUE;
wgi_state.dirty = SDL_TRUE;
Sep 19, 2018
Sep 19, 2018
444
445
446
447
448
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
449
450
451
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
452
453
WindowsCreateString_t WindowsCreateStringFunc = (WindowsCreateString_t)GetProcAddress(hModule, "WindowsCreateString");
Sep 20, 2018
Sep 20, 2018
454
WindowsDeleteString_t WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule, "WindowsDeleteString");
Sep 19, 2018
Sep 19, 2018
455
RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory");
Sep 20, 2018
Sep 20, 2018
456
if (WindowsCreateStringFunc && WindowsDeleteStringFunc && RoGetActivationFactoryFunc) {
Sep 19, 2018
Sep 19, 2018
457
458
459
460
461
LPTSTR pNamespace = L"Windows.Gaming.Input.Gamepad";
HSTRING hNamespaceString;
hr = WindowsCreateStringFunc(pNamespace, SDL_wcslen(pNamespace), &hNamespaceString);
if (SUCCEEDED(hr)) {
Mar 16, 2020
Mar 16, 2020
462
RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, &wgi_state.gamepad_statics);
Sep 20, 2018
Sep 20, 2018
463
WindowsDeleteStringFunc(hNamespaceString);
Sep 19, 2018
Sep 19, 2018
464
465
466
467
468
469
470
}
}
FreeLibrary(hModule);
}
}
}
Mar 16, 2020
Mar 16, 2020
471
472
static SDL_bool
HIDAPI_DriverXbox360_WindowsGamingInputSlotMatches(const WindowsMatchState *state, WindowsGamingInputGamepadState *slot)
Sep 19, 2018
Sep 19, 2018
473
{
Mar 16, 2020
Mar 16, 2020
474
475
476
477
478
479
480
481
482
483
484
Uint32 wgi_buttons = slot->state.Buttons;
if ((wgi_buttons & 0x3FFF) == state->wgi_buttons && WindowsGamingInputAxesMatch(slot->state)) {
return SDL_TRUE;
}
return SDL_FALSE;
}
static SDL_bool
HIDAPI_DriverXbox360_GuessWindowsGamingInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, WindowsGamingInputGamepadState **slot)
{
int match_count;
Sep 19, 2018
Sep 19, 2018
485
Mar 16, 2020
Mar 16, 2020
486
487
488
489
490
491
492
493
match_count = 0;
for (int user_index = 0; user_index < wgi_state.per_gamepad_count; ++user_index) {
WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[user_index];
if (HIDAPI_DriverXbox360_WindowsGamingInputSlotMatches(state, gamepad_state)) {
++match_count;
*slot = gamepad_state;
/* Incrementing correlation_id for any match, as negative evidence for others being correlated */
*correlation_id = ++gamepad_state->correlation_id;
Sep 19, 2018
Sep 19, 2018
494
}
Mar 16, 2020
Mar 16, 2020
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
}
/* Only return a match if we match exactly one, and we have some non-zero data (buttons or axes) that matched.
Note that we're still invalidating *other* potential correlations if we have more than one match or we have no
data. */
if (match_count == 1 && state->any_data) {
return SDL_TRUE;
}
return SDL_FALSE;
}
static void
HIDAPI_DriverXbox360_QuitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
{
wgi_state.need_device_list_update = SDL_TRUE;
--wgi_state.ref_count;
if (!wgi_state.ref_count && wgi_state.initialized) {
for (int ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
__x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(wgi_state.per_gamepad[ii]->gamepad);
Sep 19, 2018
Sep 19, 2018
513
}
Mar 16, 2020
Mar 16, 2020
514
515
516
if (wgi_state.per_gamepad) {
SDL_free(wgi_state.per_gamepad);
wgi_state.per_gamepad = NULL;
Sep 19, 2018
Sep 19, 2018
517
}
Mar 16, 2020
Mar 16, 2020
518
519
520
521
wgi_state.per_gamepad_count = 0;
if (wgi_state.gamepad_statics) {
__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(wgi_state.gamepad_statics);
wgi_state.gamepad_statics = NULL;
Sep 19, 2018
Sep 19, 2018
522
}
Mar 16, 2020
Mar 16, 2020
523
524
WIN_CoUninitialize();
wgi_state.initialized = SDL_FALSE;
Sep 19, 2018
Sep 19, 2018
525
526
527
}
}
Mar 16, 2020
Mar 16, 2020
528
529
#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
Sep 19, 2018
Sep 19, 2018
530
static void
Mar 16, 2020
Mar 16, 2020
531
HIDAPI_DriverXbox360_PostUpdate(void)
Sep 19, 2018
Sep 19, 2018
532
{
Mar 16, 2020
Mar 16, 2020
533
534
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
SDL_bool unmapped_guide_pressed = SDL_FALSE;
Sep 19, 2018
Sep 19, 2018
535
Mar 16, 2020
Mar 16, 2020
536
537
538
539
540
541
542
543
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
if (!wgi_state.dirty) {
int ii;
for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[ii];
if (!gamepad_state->used && (gamepad_state->state.Buttons & GamepadButtons_GUIDE)) {
unmapped_guide_pressed = SDL_TRUE;
break;
Sep 19, 2018
Sep 19, 2018
544
545
546
}
}
}
Mar 16, 2020
Mar 16, 2020
547
548
wgi_state.dirty = SDL_TRUE;
#endif
Sep 19, 2018
Sep 19, 2018
549
Mar 16, 2020
Mar 16, 2020
550
551
552
553
554
555
556
557
558
559
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
if (!xinput_state_dirty) {
int ii;
for (ii = 0; ii < SDL_arraysize(xinput_state); ii++) {
if (xinput_state[ii].connected && !xinput_state[ii].used && (xinput_state[ii].state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE)) {
unmapped_guide_pressed = SDL_TRUE;
break;
}
}
Sep 19, 2018
Sep 19, 2018
560
}
Mar 16, 2020
Mar 16, 2020
561
562
xinput_state_dirty = SDL_TRUE;
#endif
Sep 19, 2018
Sep 19, 2018
563
Mar 16, 2020
Mar 16, 2020
564
565
566
567
568
569
570
571
if (unmapped_guide_pressed) {
if (guide_button_candidate.joystick && !guide_button_candidate.last_joystick) {
SDL_PrivateJoystickButton(guide_button_candidate.joystick, SDL_CONTROLLER_BUTTON_GUIDE, SDL_PRESSED);
guide_button_candidate.last_joystick = guide_button_candidate.joystick;
}
} else if (guide_button_candidate.last_joystick) {
SDL_PrivateJoystickButton(guide_button_candidate.last_joystick, SDL_CONTROLLER_BUTTON_GUIDE, SDL_RELEASED);
guide_button_candidate.last_joystick = NULL;
Sep 19, 2018
Sep 19, 2018
572
}
Mar 16, 2020
Mar 16, 2020
573
574
guide_button_candidate.joystick = NULL;
#endif
Sep 19, 2018
Sep 19, 2018
575
576
}
Mar 2, 2020
Mar 2, 2020
577
#if defined(__MACOSX__)
Mar 1, 2020
Mar 1, 2020
578
579
580
581
582
583
584
585
586
587
588
589
590
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
591
#endif
Mar 1, 2020
Mar 1, 2020
592
Jan 19, 2020
Jan 19, 2020
594
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
596
const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */
Nov 22, 2019
Nov 22, 2019
597
Jan 18, 2020
Jan 18, 2020
598
if (vendor_id == USB_VENDOR_NVIDIA) {
Dec 12, 2019
Dec 12, 2019
599
/* This is the NVIDIA Shield controller which doesn't talk Xbox controller protocol */
Nov 27, 2019
Nov 27, 2019
600
601
return SDL_FALSE;
}
Jan 18, 2020
Jan 18, 2020
602
603
604
605
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
606
}
Dec 17, 2019
Dec 17, 2019
607
608
609
610
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
611
#if defined(__MACOSX__) || defined(__WIN32__)
Jan 18, 2020
Jan 18, 2020
612
if (vendor_id == USB_VENDOR_MICROSOFT && product_id == 0x028e && version == 1) {
Aug 16, 2018
Aug 16, 2018
613
614
615
/* This is the Steam Virtual Gamepad, which isn't supported by this driver */
return SDL_FALSE;
}
Mar 2, 2020
Mar 2, 2020
616
617
618
619
620
621
622
623
624
625
626
#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
627
return (type == SDL_CONTROLLER_TYPE_XBOX360 || type == SDL_CONTROLLER_TYPE_XBOXONE);
Nov 22, 2019
Nov 22, 2019
629
return (type == SDL_CONTROLLER_TYPE_XBOX360);
630
631
632
633
634
635
#endif
}
static const char *
HIDAPI_DriverXbox360_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
{
Dec 12, 2019
Dec 12, 2019
636
return NULL;
637
638
639
640
}
static SDL_bool SetSlotLED(hid_device *dev, Uint8 slot)
{
Dec 20, 2019
Dec 20, 2019
641
642
Uint8 mode = 0x02 + slot;
const Uint8 led_packet[] = { 0x01, 0x03, mode };
643
644
if (hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
Aug 16, 2018
Aug 16, 2018
645
646
647
return SDL_FALSE;
}
return SDL_TRUE;
648
649
650
}
static SDL_bool
Dec 19, 2019
Dec 19, 2019
651
652
HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *device)
{
Mar 16, 2020
Mar 16, 2020
653
return HIDAPI_JoystickConnected(device, NULL, SDL_FALSE);
Dec 19, 2019
Dec 19, 2019
654
655
}
Dec 21, 2019
Dec 21, 2019
656
657
658
659
660
661
662
663
664
665
666
667
668
669
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
670
671
static SDL_bool
HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
672
673
{
SDL_DriverXbox360_Context *ctx;
Dec 21, 2019
Dec 21, 2019
674
int player_index;
675
676
677
678
679
680
ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
if (!ctx) {
SDL_OutOfMemory();
return SDL_FALSE;
}
Dec 19, 2019
Dec 19, 2019
681
Mar 16, 2020
Mar 16, 2020
682
683
684
685
686
687
688
if (device->path) { /* else opened for RAWINPUT driver */
device->dev = hid_open_path(device->path, 0);
if (!device->dev) {
SDL_SetError("Couldn't open %s", device->path);
SDL_free(ctx);
return SDL_FALSE;
}
Dec 19, 2019
Dec 19, 2019
689
690
691
}
device->context = ctx;
Sep 19, 2018
Sep 19, 2018
692
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
Mar 16, 2020
Mar 16, 2020
693
694
695
xinput_device_change = SDL_TRUE;
ctx->xinput_enabled = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_CORRELATE_XINPUT, SDL_TRUE);
if (ctx->xinput_enabled && (WIN_LoadXInputDLL() < 0 || !XINPUTGETSTATE)) {
Aug 16, 2018
Aug 16, 2018
696
697
698
ctx->xinput_enabled = SDL_FALSE;
}
ctx->xinput_slot = XUSER_INDEX_ANY;
Sep 19, 2018
Sep 19, 2018
699
700
701
#endif
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
Aug 16, 2018
Aug 16, 2018
702
#endif
703
704
/* Set the controller LED */
Dec 21, 2019
Dec 21, 2019
705
player_index = SDL_JoystickGetPlayerIndex(joystick);
Mar 16, 2020
Mar 16, 2020
706
if (player_index >= 0 && device->dev) {
Dec 21, 2019
Dec 21, 2019
707
708
SetSlotLED(device->dev, (player_index % 4));
}
709
710
711
712
713
714
715
716
717
718
/* 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
719
HIDAPI_DriverXbox360_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
Feb 4, 2020
Feb 4, 2020
721
#if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT)
Dec 19, 2019
Dec 19, 2019
722
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
Feb 4, 2020
Feb 4, 2020
723
#endif
Sep 19, 2018
Sep 19, 2018
724
Aug 16, 2018
Aug 16, 2018
725
#ifdef __WIN32__
Sep 19, 2018
Sep 19, 2018
726
727
728
SDL_bool rumbled = SDL_FALSE;
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
Mar 16, 2020
Mar 16, 2020
729
730
if (!rumbled && ctx->wgi_correlated) {
WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
Sep 19, 2018
Sep 19, 2018
731
HRESULT hr;
Mar 16, 2020
Mar 16, 2020
732
733
734
gamepad_state->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
gamepad_state->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
Sep 19, 2018
Sep 19, 2018
735
736
737
738
739
740
741
if (SUCCEEDED(hr)) {
rumbled = SDL_TRUE;
}
}
#endif
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
Mar 16, 2020
Mar 16, 2020
742
if (!rumbled && ctx->xinput_correlated) {
Aug 16, 2018
Aug 16, 2018
743
744
745
746
747
748
749
750
XINPUT_VIBRATION XVibration;
if (!XINPUTSETSTATE) {
return SDL_Unsupported();
}
XVibration.wLeftMotorSpeed = low_frequency_rumble;
XVibration.wRightMotorSpeed = high_frequency_rumble;
Sep 19, 2018
Sep 19, 2018
751
752
753
if (XINPUTSETSTATE(ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) {
rumbled = SDL_TRUE;
} else {
Aug 16, 2018
Aug 16, 2018
754
755
756
return SDL_SetError("XInputSetState() failed");
}
}
Sep 19, 2018
Sep 19, 2018
757
758
759
760
#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
#else /* !__WIN32__ */
Mar 1, 2020
Mar 1, 2020
762
763
764
765
766
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
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
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");
}
}
784
785
786
787
788
789
#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
790
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
791
792
return SDL_SetError("Couldn't send rumble packet");
}
Mar 1, 2020
Mar 1, 2020
793
#endif
Aug 16, 2018
Aug 16, 2018
794
#endif /* __WIN32__ */
Aug 16, 2018
Aug 16, 2018
799
#ifdef __WIN32__
Aug 16, 2018
Aug 16, 2018
800
801
802
/* 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
803
804
We use XInput and Windows.Gaming.Input to make up for these shortcomings.
Aug 16, 2018
Aug 16, 2018
805
806
*/
static void
Aug 16, 2018
Aug 16, 2018
807
HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
Aug 16, 2018
Aug 16, 2018
808
{
Mar 16, 2020
Mar 16, 2020
809
810
811
812
813
814
815
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
Uint32 match_state = ctx->match_state;
/* Update match_state with button bit, then fall through */
# define SDL_PrivateJoystickButton(joystick, button, state) if (state) match_state |= 1 << (button); else match_state &=~(1<<(button)); SDL_PrivateJoystickButton(joystick, button, state)
/* Grab high 4 bits of value, then fall through */
# define SDL_PrivateJoystickAxis(joystick, axis, value) if (axis < 4) match_state = (match_state & ~(0xF << (4 * axis + 16))) | ((value) & 0xF000) << (4 * axis + 4); SDL_PrivateJoystickAxis(joystick, axis, value)
#endif
Aug 16, 2018
Aug 16, 2018
816
Sint16 axis;
Sep 19, 2018
Sep 19, 2018
817
SDL_bool has_trigger_data = SDL_FALSE;
Aug 16, 2018
Aug 16, 2018
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
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);
Mar 16, 2020
Mar 16, 2020
886
887
888
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
#undef SDL_PrivateJoystickAxis
#endif
Aug 16, 2018
Aug 16, 2018
889
Mar 16, 2020
Mar 16, 2020
890
891
892
893
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
/* Prefer XInput over WindowsGamingInput, it continues to provide data in the background */
if (!has_trigger_data && ctx->xinput_enabled && ctx->xinput_correlated) {
has_trigger_data = SDL_TRUE;
Sep 19, 2018
Sep 19, 2018
894
}
Mar 16, 2020
Mar 16, 2020
895
#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
Sep 19, 2018
Sep 19, 2018
896
Mar 16, 2020
Mar 16, 2020
897
898
899
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
if (!has_trigger_data && ctx->wgi_correlated) {
has_trigger_data = SDL_TRUE;
Sep 19, 2018
Sep 19, 2018
900
901
902
903
}
#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
if (!has_trigger_data) {
Aug 16, 2018
Aug 16, 2018
904
905
906
axis = (data[9] * 257) - 32768;
if (data[9] < 0x80) {
axis = -axis * 2 - 32769;
Mar 16, 2020
Mar 16, 2020
907
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_MIN_SINT16);
Aug 16, 2018
Aug 16, 2018
908
909
910
911
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);
Mar 16, 2020
Mar 16, 2020
912
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, SDL_MIN_SINT16);
Aug 16, 2018
Aug 16, 2018
913
914
915
916
} 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
917
918
}
Mar 16, 2020
Mar 16, 2020
919
920
921
922
923
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
ctx->match_state = match_state;
ctx->last_state_packet = SDL_GetTicks();
#undef SDL_PrivateJoystickButton
#endif
Aug 16, 2018
Aug 16, 2018
924
925
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
Mar 16, 2020
Mar 16, 2020
926
927
928
929
930
931
932
933
934
935
#ifdef SDL_JOYSTICK_RAWINPUT
static void
HIDAPI_DriverXbox360_HandleStatePacketFromRAWINPUT(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 *data, int size)
{
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
HIDAPI_DriverXbox360_HandleStatePacket(joystick, NULL, ctx, data, size);
}
#endif
Aug 16, 2018
Aug 16, 2018
936
#else
Aug 16, 2018
Aug 16, 2018
937
938
939
940
941
942
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
943
const SDL_bool invert_y_axes = SDL_FALSE;
Aug 16, 2018
Aug 16, 2018
945
const SDL_bool invert_y_axes = SDL_TRUE;
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
#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
976
977
978
if (invert_y_axes) {
axis = ~axis;
}
979
980
981
982
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
983
984
985
if (invert_y_axes) {
axis = ~axis;
}
986
987
988
989
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
990
#endif /* __WIN32__ */
Mar 16, 2020
Mar 16, 2020
992
993
994
static void
HIDAPI_DriverXbox360_UpdateOtherAPIs(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
Mar 16, 2020
Mar 16, 2020
995
#if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
Mar 16, 2020
Mar 16, 2020
996
997
998
999
1000
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
SDL_bool has_trigger_data = SDL_FALSE;
SDL_bool correlated = SDL_FALSE;
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_MATCHING
WindowsMatchState match_state_xinput;