SDL 2.0
SDL_hidapi_xbox360.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "../../SDL_internal.h"
22
23#ifdef SDL_JOYSTICK_HIDAPI
24
25#include "SDL_hints.h"
26#include "SDL_log.h"
27#include "SDL_events.h"
28#include "SDL_timer.h"
29#include "SDL_joystick.h"
30#include "SDL_gamecontroller.h"
31#include "../SDL_sysjoystick.h"
33
34
35#ifdef SDL_JOYSTICK_HIDAPI_XBOX360
36
37#ifdef __WIN32__
38#define SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
39/* This requires the Windows 10 SDK to build */
40/*#define SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT*/
41#endif
42
43#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
44#include "../../core/windows/SDL_xinput.h"
45#endif
46
47#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
48#include "../../core/windows/SDL_windows.h"
49#define COBJMACROS
50#include "windows.gaming.input.h"
51#endif
52
53#define USB_PACKET_LENGTH 64
54
55
56typedef struct {
57 Uint8 last_state[USB_PACKET_LENGTH];
58 Uint32 rumble_expiration;
59#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
60 SDL_bool xinput_enabled;
61 Uint8 xinput_slot;
62#endif
63#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
64 SDL_bool coinitialized;
65 __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics;
66 __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
67 struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
68#endif
69} SDL_DriverXbox360_Context;
70
71
72#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
73static Uint8 xinput_slots;
74
75static void
76HIDAPI_DriverXbox360_MarkXInputSlotUsed(Uint8 xinput_slot)
77{
78 if (xinput_slot != XUSER_INDEX_ANY) {
79 xinput_slots |= (0x01 << xinput_slot);
80 }
81}
82
83static void
84HIDAPI_DriverXbox360_MarkXInputSlotFree(Uint8 xinput_slot)
85{
86 if (xinput_slot != XUSER_INDEX_ANY) {
87 xinput_slots &= ~(0x01 << xinput_slot);
88 }
89}
90
91static SDL_bool
92HIDAPI_DriverXbox360_MissingXInputSlot()
93{
94 return xinput_slots != 0x0F;
95}
96
97static Uint8
98HIDAPI_DriverXbox360_GuessXInputSlot(WORD wButtons)
99{
100 DWORD user_index;
101 int match_count;
102 Uint8 match_slot;
103
104 if (!XINPUTGETSTATE) {
105 return XUSER_INDEX_ANY;
106 }
107
108 match_count = 0;
109 for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) {
110 XINPUT_STATE_EX xinput_state;
111
112 if (XINPUTGETSTATE(user_index, &xinput_state) == ERROR_SUCCESS) {
113 if (xinput_state.Gamepad.wButtons == wButtons) {
114 ++match_count;
115 match_slot = (Uint8)user_index;
116 }
117 }
118 }
119 if (match_count == 1) {
120 return match_slot;
121 }
122 return XUSER_INDEX_ANY;
123}
124
125#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
126
127#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
128
129static void
130HIDAPI_DriverXbox360_InitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
131{
132 /* I think this takes care of RoInitialize() in a way that is compatible with the rest of SDL */
133 if (FAILED(WIN_CoInitialize())) {
134 return;
135 }
136 ctx->coinitialized = SDL_TRUE;
137
138 {
139 static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } };
140 HRESULT hr;
141 HMODULE hModule = LoadLibraryA("combase.dll");
142 if (hModule != NULL) {
143 typedef HRESULT (WINAPI *WindowsCreateString_t)(PCNZWCH sourceString, UINT32 length, HSTRING* string);
144 typedef HRESULT (WINAPI *WindowsDeleteString_t)(HSTRING string);
145 typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory);
146
147 WindowsCreateString_t WindowsCreateStringFunc = (WindowsCreateString_t)GetProcAddress(hModule, "WindowsCreateString");
148 WindowsDeleteString_t WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule, "WindowsDeleteString");
149 RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory");
150 if (WindowsCreateStringFunc && WindowsDeleteStringFunc && RoGetActivationFactoryFunc) {
151 LPTSTR pNamespace = L"Windows.Gaming.Input.Gamepad";
152 HSTRING hNamespaceString;
153
154 hr = WindowsCreateStringFunc(pNamespace, SDL_wcslen(pNamespace), &hNamespaceString);
155 if (SUCCEEDED(hr)) {
156 RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, &ctx->gamepad_statics);
157 WindowsDeleteStringFunc(hNamespaceString);
158 }
159 }
160 FreeLibrary(hModule);
161 }
162 }
163}
164
165static Uint8
166HIDAPI_DriverXbox360_GetGamepadButtonsForMatch(__x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad)
167{
168 HRESULT hr;
169 struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
170 Uint8 buttons = 0;
171
172 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(gamepad, &state);
173 if (SUCCEEDED(hr)) {
174 if (state.Buttons & GamepadButtons_A) {
175 buttons |= (1 << SDL_CONTROLLER_BUTTON_A);
176 }
177 if (state.Buttons & GamepadButtons_B) {
178 buttons |= (1 << SDL_CONTROLLER_BUTTON_B);
179 }
180 if (state.Buttons & GamepadButtons_X) {
181 buttons |= (1 << SDL_CONTROLLER_BUTTON_X);
182 }
183 if (state.Buttons & GamepadButtons_Y) {
184 buttons |= (1 << SDL_CONTROLLER_BUTTON_Y);
185 }
186 }
187 return buttons;
188}
189
190static void
191HIDAPI_DriverXbox360_GuessGamepad(SDL_DriverXbox360_Context *ctx, Uint8 buttons)
192{
193 HRESULT hr;
194 __FIVectorView_1_Windows__CGaming__CInput__CGamepad *gamepads;
195
196 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_get_Gamepads(ctx->gamepad_statics, &gamepads);
197 if (SUCCEEDED(hr)) {
198 unsigned int i, num_gamepads;
199
200 hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_get_Size(gamepads, &num_gamepads);
201 if (SUCCEEDED(hr)) {
202 int match_count;
203 unsigned int match_slot;
204
205 match_count = 0;
206 for (i = 0; i < num_gamepads; ++i) {
207 __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
208
209 hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, i, &gamepad);
210 if (SUCCEEDED(hr)) {
211 Uint8 gamepad_buttons = HIDAPI_DriverXbox360_GetGamepadButtonsForMatch(gamepad);
212 if (buttons == gamepad_buttons) {
213 ++match_count;
214 match_slot = i;
215 }
216 __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
217 }
218 }
219 if (match_count == 1) {
220 hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, match_slot, &ctx->gamepad);
221 if (SUCCEEDED(hr)) {
222 }
223 }
224 }
225 __FIVectorView_1_Windows__CGaming__CInput__CGamepad_Release(gamepads);
226 }
227}
228
229static void
230HIDAPI_DriverXbox360_QuitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
231{
232 if (ctx->gamepad_statics) {
233 __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(ctx->gamepad_statics);
234 ctx->gamepad_statics = NULL;
235 }
236 if (ctx->gamepad) {
237 __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(ctx->gamepad);
238 ctx->gamepad = NULL;
239 }
240
241 if (ctx->coinitialized) {
243 ctx->coinitialized = SDL_FALSE;
244 }
245}
246
247#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
248
249static SDL_bool
250HIDAPI_DriverXbox360_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number)
251{
252#if defined(__MACOSX__) || defined(__WIN32__)
253 if (vendor_id == 0x045e && product_id == 0x028e && version == 1) {
254 /* This is the Steam Virtual Gamepad, which isn't supported by this driver */
255 return SDL_FALSE;
256 }
257 if (vendor_id == 0x045e && product_id == 0x02e0) {
258 /* This is the old Bluetooth Xbox One S firmware, which isn't supported by this driver */
259 return SDL_FALSE;
260 }
261 return SDL_IsJoystickXbox360(vendor_id, product_id) || SDL_IsJoystickXboxOne(vendor_id, product_id);
262#else
263 return SDL_IsJoystickXbox360(vendor_id, product_id);
264#endif
265}
266
267static const char *
268HIDAPI_DriverXbox360_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
269{
270 return HIDAPI_XboxControllerName(vendor_id, product_id);
271}
272
273static SDL_bool SetSlotLED(hid_device *dev, Uint8 slot)
274{
275 const Uint8 led_packet[] = { 0x01, 0x03, (2 + slot) };
276
277 if (hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
278 return SDL_FALSE;
279 }
280 return SDL_TRUE;
281}
282
283static SDL_bool
284HIDAPI_DriverXbox360_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
285{
286 SDL_DriverXbox360_Context *ctx;
287
288 ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
289 if (!ctx) {
291 return SDL_FALSE;
292 }
293#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
295 if (ctx->xinput_enabled && WIN_LoadXInputDLL() < 0) {
296 ctx->xinput_enabled = SDL_FALSE;
297 }
298 ctx->xinput_slot = XUSER_INDEX_ANY;
299#endif
300#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
301 HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
302#endif
303 *context = ctx;
304
305 /* Set the controller LED */
306 SetSlotLED(dev, (joystick->instance_id % 4));
307
308 /* Initialize the joystick capabilities */
309 joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
310 joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
311 joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
312
313 return SDL_TRUE;
314}
315
316static int
317HIDAPI_DriverXbox360_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
318{
319 SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
320
321#ifdef __WIN32__
322 SDL_bool rumbled = SDL_FALSE;
323
324#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
325 if (!rumbled && ctx->gamepad) {
326 HRESULT hr;
327
328 ctx->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
329 ctx->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
330 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(ctx->gamepad, ctx->vibration);
331 if (SUCCEEDED(hr)) {
332 rumbled = SDL_TRUE;
333 }
334 }
335#endif
336
337#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
338 if (!rumbled && ctx->xinput_slot != XUSER_INDEX_ANY) {
339 XINPUT_VIBRATION XVibration;
340
341 if (!XINPUTSETSTATE) {
342 return SDL_Unsupported();
343 }
344
345 XVibration.wLeftMotorSpeed = low_frequency_rumble;
346 XVibration.wRightMotorSpeed = high_frequency_rumble;
347 if (XINPUTSETSTATE(ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) {
348 rumbled = SDL_TRUE;
349 } else {
350 return SDL_SetError("XInputSetState() failed");
351 }
352 }
353#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
354
355#else /* !__WIN32__ */
356
357#ifdef __MACOSX__
358 /* On Mac OS X the 360Controller driver uses this short report,
359 and we need to prefix it with a magic token so hidapi passes it through untouched
360 */
361 Uint8 rumble_packet[] = { 'M', 'A', 'G', 'I', 'C', '0', 0x00, 0x04, 0x00, 0x00 };
362
363 rumble_packet[6+2] = (low_frequency_rumble >> 8);
364 rumble_packet[6+3] = (high_frequency_rumble >> 8);
365#else
366 Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
367
368 rumble_packet[3] = (low_frequency_rumble >> 8);
369 rumble_packet[4] = (high_frequency_rumble >> 8);
370#endif
371
372 if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
373 return SDL_SetError("Couldn't send rumble packet");
374 }
375#endif /* __WIN32__ */
376
377 if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
378 ctx->rumble_expiration = SDL_GetTicks() + duration_ms;
379 } else {
380 ctx->rumble_expiration = 0;
381 }
382 return 0;
383}
384
385#ifdef __WIN32__
386 /* This is the packet format for Xbox 360 and Xbox One controllers on Windows,
387 however with this interface there is no rumble support, no guide button,
388 and the left and right triggers are tied together as a single axis.
389
390 We use XInput and Windows.Gaming.Input to make up for these shortcomings.
391 */
392static void
393HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
394{
395 Sint16 axis;
396 SDL_bool has_trigger_data = SDL_FALSE;
397
398 if (ctx->last_state[10] != data[10]) {
407 }
408
409 if (ctx->last_state[11] != data[11]) {
410 SDL_bool dpad_up = SDL_FALSE;
411 SDL_bool dpad_down = SDL_FALSE;
412 SDL_bool dpad_left = SDL_FALSE;
413 SDL_bool dpad_right = SDL_FALSE;
414
417
418 switch (data[11] & 0x3C) {
419 case 4:
420 dpad_up = SDL_TRUE;
421 break;
422 case 8:
423 dpad_up = SDL_TRUE;
424 dpad_right = SDL_TRUE;
425 break;
426 case 12:
427 dpad_right = SDL_TRUE;
428 break;
429 case 16:
430 dpad_right = SDL_TRUE;
431 dpad_down = SDL_TRUE;
432 break;
433 case 20:
434 dpad_down = SDL_TRUE;
435 break;
436 case 24:
437 dpad_left = SDL_TRUE;
438 dpad_down = SDL_TRUE;
439 break;
440 case 28:
441 dpad_left = SDL_TRUE;
442 break;
443 case 32:
444 dpad_up = SDL_TRUE;
445 dpad_left = SDL_TRUE;
446 break;
447 default:
448 break;
449 }
454 }
455
456 axis = (int)*(Uint16*)(&data[0]) - 0x8000;
458 axis = (int)*(Uint16*)(&data[2]) - 0x8000;
460 axis = (int)*(Uint16*)(&data[4]) - 0x8000;
462 axis = (int)*(Uint16*)(&data[6]) - 0x8000;
464
465#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
466 if (ctx->gamepad_statics && !ctx->gamepad) {
467 Uint8 buttons = 0;
468
469 if (data[10] & 0x01) {
470 buttons |= (1 << SDL_CONTROLLER_BUTTON_A);
471 }
472 if (data[10] & 0x02) {
473 buttons |= (1 << SDL_CONTROLLER_BUTTON_B);
474 }
475 if (data[10] & 0x04) {
476 buttons |= (1 << SDL_CONTROLLER_BUTTON_X);
477 }
478 if (data[10] & 0x08) {
479 buttons |= (1 << SDL_CONTROLLER_BUTTON_Y);
480 }
481 if (buttons != 0) {
482 HIDAPI_DriverXbox360_GuessGamepad(ctx, buttons);
483 }
484 }
485
486 if (ctx->gamepad) {
487 HRESULT hr;
488 struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
489
490 hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(ctx->gamepad, &state);
491 if (SUCCEEDED(hr)) {
493 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)(state.LeftTrigger * SDL_MAX_UINT16)) - 32768);
494 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)(state.RightTrigger * SDL_MAX_UINT16)) - 32768);
495 has_trigger_data = SDL_TRUE;
496 }
497 }
498#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
499
500#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
501 if (ctx->xinput_enabled) {
502 if (ctx->xinput_slot == XUSER_INDEX_ANY && HIDAPI_DriverXbox360_MissingXInputSlot()) {
503 WORD wButtons = 0;
504
505 if (data[10] & 0x01) {
506 wButtons |= XINPUT_GAMEPAD_A;
507 }
508 if (data[10] & 0x02) {
509 wButtons |= XINPUT_GAMEPAD_B;
510 }
511 if (data[10] & 0x04) {
512 wButtons |= XINPUT_GAMEPAD_X;
513 }
514 if (data[10] & 0x08) {
515 wButtons |= XINPUT_GAMEPAD_Y;
516 }
517 if (wButtons != 0) {
518 Uint8 xinput_slot = HIDAPI_DriverXbox360_GuessXInputSlot(wButtons);
519 if (xinput_slot != XUSER_INDEX_ANY) {
520 HIDAPI_DriverXbox360_MarkXInputSlotUsed(xinput_slot);
521 ctx->xinput_slot = xinput_slot;
522 }
523 }
524 }
525
526 if (!has_trigger_data && ctx->xinput_slot != XUSER_INDEX_ANY) {
527 XINPUT_STATE_EX xinput_state;
528
529 if (XINPUTGETSTATE(ctx->xinput_slot, &xinput_state) == ERROR_SUCCESS) {
530 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (xinput_state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE) ? SDL_PRESSED : SDL_RELEASED);
531 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)xinput_state.Gamepad.bLeftTrigger * 257) - 32768);
532 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)xinput_state.Gamepad.bRightTrigger * 257) - 32768);
533 has_trigger_data = SDL_TRUE;
534 }
535 }
536 }
537#endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
538
539 if (!has_trigger_data) {
540 axis = (data[9] * 257) - 32768;
541 if (data[9] < 0x80) {
542 axis = -axis * 2 - 32769;
544 } else if (data[9] > 0x80) {
545 axis = axis * 2 - 32767;
547 } else {
550 }
551 }
552
553 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
554}
555#else
556
557static void
558HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
559{
560 Sint16 axis;
561#ifdef __MACOSX__
562 const SDL_bool invert_y_axes = SDL_FALSE;
563#else
564 const SDL_bool invert_y_axes = SDL_TRUE;
565#endif
566
567 if (ctx->last_state[2] != data[2]) {
576 }
577
578 if (ctx->last_state[3] != data[3]) {
586 }
587
588 axis = ((int)data[4] * 257) - 32768;
590 axis = ((int)data[5] * 257) - 32768;
592 axis = *(Sint16*)(&data[6]);
594 axis = *(Sint16*)(&data[8]);
595 if (invert_y_axes) {
596 axis = ~axis;
597 }
599 axis = *(Sint16*)(&data[10]);
601 axis = *(Sint16*)(&data[12]);
602 if (invert_y_axes) {
603 axis = ~axis;
604 }
606
607 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
608}
609#endif /* __WIN32__ */
610
611#ifdef __MACOSX__
612static void
613HIDAPI_DriverXboxOneS_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
614{
615 Sint16 axis;
616
617 if (ctx->last_state[14] != data[14]) {
624 }
625
626 if (ctx->last_state[15] != data[15]) {
630 }
631
632 if (ctx->last_state[16] != data[16]) {
634 }
635
636 if (ctx->last_state[13] != data[13]) {
637 SDL_bool dpad_up = SDL_FALSE;
638 SDL_bool dpad_down = SDL_FALSE;
639 SDL_bool dpad_left = SDL_FALSE;
640 SDL_bool dpad_right = SDL_FALSE;
641
642 switch (data[13]) {
643 case 1:
644 dpad_up = SDL_TRUE;
645 break;
646 case 2:
647 dpad_up = SDL_TRUE;
648 dpad_right = SDL_TRUE;
649 break;
650 case 3:
651 dpad_right = SDL_TRUE;
652 break;
653 case 4:
654 dpad_right = SDL_TRUE;
655 dpad_down = SDL_TRUE;
656 break;
657 case 5:
658 dpad_down = SDL_TRUE;
659 break;
660 case 6:
661 dpad_left = SDL_TRUE;
662 dpad_down = SDL_TRUE;
663 break;
664 case 7:
665 dpad_left = SDL_TRUE;
666 break;
667 case 8:
668 dpad_up = SDL_TRUE;
669 dpad_left = SDL_TRUE;
670 break;
671 default:
672 break;
673 }
678 }
679
680 axis = (int)*(Uint16*)(&data[1]) - 0x8000;
682 axis = (int)*(Uint16*)(&data[3]) - 0x8000;
684 axis = (int)*(Uint16*)(&data[5]) - 0x8000;
686 axis = (int)*(Uint16*)(&data[7]) - 0x8000;
688
689 axis = ((int)*(Sint16*)(&data[9]) * 64) - 32768;
690 if (axis == 32704) {
691 axis = 32767;
692 }
694
695 axis = ((int)*(Sint16*)(&data[11]) * 64) - 32768;
696 if (axis == 32704) {
697 axis = 32767;
698 }
700
701 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
702}
703
704static void
705HIDAPI_DriverXboxOneS_HandleGuidePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
706{
708}
709#endif /* __MACOSX__ */
710
711static SDL_bool
712HIDAPI_DriverXbox360_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
713{
714 SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
715 Uint8 data[USB_PACKET_LENGTH];
716 int size;
717
718 while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
719#ifdef __WIN32__
720 HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
721#else
722 switch (data[0]) {
723 case 0x00:
724 HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
725 break;
726#ifdef __MACOSX__
727 case 0x01:
728 HIDAPI_DriverXboxOneS_HandleStatePacket(joystick, dev, ctx, data, size);
729 break;
730 case 0x02:
731 HIDAPI_DriverXboxOneS_HandleGuidePacket(joystick, dev, ctx, data, size);
732 break;
733#endif
734 default:
735#ifdef DEBUG_JOYSTICK
736 SDL_Log("Unknown Xbox 360 packet, size = %d\n", size);
737 SDL_Log("%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
738 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
739 data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16]);
740#endif
741 break;
742 }
743#endif /* __WIN32__ */
744 }
745
746 if (ctx->rumble_expiration) {
747 Uint32 now = SDL_GetTicks();
748 if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
749 HIDAPI_DriverXbox360_Rumble(joystick, dev, context, 0, 0, 0);
750 }
751 }
752
753 return (size >= 0);
754}
755
756static void
757HIDAPI_DriverXbox360_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
758{
759#if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
760 SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
761#endif
762
763#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
764 if (ctx->xinput_enabled) {
765 HIDAPI_DriverXbox360_MarkXInputSlotFree(ctx->xinput_slot);
766 WIN_UnloadXInputDLL();
767 }
768#endif
769#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
770 HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
771#endif
773}
774
776{
778 SDL_TRUE,
779 HIDAPI_DriverXbox360_IsSupportedDevice,
780 HIDAPI_DriverXbox360_GetDeviceName,
781 HIDAPI_DriverXbox360_Init,
782 HIDAPI_DriverXbox360_Rumble,
783 HIDAPI_DriverXbox360_Update,
784 HIDAPI_DriverXbox360_Quit
785};
786
787#endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
788
789#endif /* SDL_JOYSTICK_HIDAPI */
790
791/* vi: set ts=4 sw=4 expandtab: */
#define SUCCEEDED(x)
Definition: SDL_directx.h:51
#define FAILED(x)
Definition: SDL_directx.h:54
#define SDL_SetError
#define SDL_wcslen
#define SDL_free
#define SDL_GetHintBoolean
#define SDL_memcpy
#define SDL_Log
#define SDL_calloc
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_Unsupported()
Definition: SDL_error.h:53
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_PRESSED
Definition: SDL_events.h:50
@ SDL_CONTROLLER_AXIS_LEFTX
@ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
@ SDL_CONTROLLER_AXIS_RIGHTY
@ SDL_CONTROLLER_AXIS_RIGHTX
@ SDL_CONTROLLER_AXIS_MAX
@ SDL_CONTROLLER_AXIS_TRIGGERLEFT
@ SDL_CONTROLLER_AXIS_LEFTY
@ SDL_CONTROLLER_BUTTON_B
@ SDL_CONTROLLER_BUTTON_BACK
@ SDL_CONTROLLER_BUTTON_LEFTSTICK
@ SDL_CONTROLLER_BUTTON_START
@ SDL_CONTROLLER_BUTTON_DPAD_LEFT
@ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
@ SDL_CONTROLLER_BUTTON_DPAD_DOWN
@ SDL_CONTROLLER_BUTTON_DPAD_UP
@ SDL_CONTROLLER_BUTTON_MAX
@ SDL_CONTROLLER_BUTTON_LEFTSHOULDER
@ SDL_CONTROLLER_BUTTON_GUIDE
@ SDL_CONTROLLER_BUTTON_DPAD_RIGHT
@ SDL_CONTROLLER_BUTTON_X
@ SDL_CONTROLLER_BUTTON_RIGHTSTICK
@ SDL_CONTROLLER_BUTTON_Y
@ SDL_CONTROLLER_BUTTON_A
const char * HIDAPI_XboxControllerName(Uint16 vendor_id, Uint16 product_id)
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360
#define SDL_HINT_XINPUT_ENABLED
A variable that lets you disable the detection and use of Xinput gamepad devices.
Definition: SDL_hints.h:428
#define SDL_HINT_JOYSTICK_HIDAPI_XBOX
A variable controlling whether the HIDAPI driver for XBox controllers should be used.
Definition: SDL_hints.h:566
SDL_bool SDL_IsJoystickXbox360(Uint16 vendor, Uint16 product)
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:833
SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor, Uint16 product)
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:966
@ SDL_JOYSTICK_POWER_WIRED
Definition: SDL_joystick.h:104
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLsizeiptr size
GLuint GLsizei GLsizei * length
GLsizei const GLchar *const * string
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
uint32_t Uint32
Definition: SDL_stdinc.h:203
#define SDL_MAX_UINT16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:189
int16_t Sint16
Definition: SDL_stdinc.h:185
#define SDL_MIN_SINT16
Definition: SDL_stdinc.h:184
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
uint16_t Uint16
Definition: SDL_stdinc.h:191
uint8_t Uint8
Definition: SDL_stdinc.h:179
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
struct xkb_state * state
HRESULT WIN_CoInitialize(void)
void WIN_CoUninitialize(void)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:167
EGLContext ctx
Definition: eglext.h:208
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *device, unsigned char *data, size_t length, int milliseconds)
Read an Input report from a HID device with timeout.
struct hid_device_ hid_device
Definition: hidapi.h:50
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length)
Write an Output report to a HID device.
SDL_Texture * axis
static NativeWindowFactory * factory
Definition: testnative.c:37
static screen_context_t context
Definition: video.c:25