SDL  2.0
SDL_hidapi_xbox360.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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"
32 #include "SDL_hidapijoystick_c.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 
56 typedef 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
73 static Uint8 xinput_slots;
74 
75 static void
76 HIDAPI_DriverXbox360_MarkXInputSlotUsed(Uint8 xinput_slot)
77 {
78  if (xinput_slot != XUSER_INDEX_ANY) {
79  xinput_slots |= (0x01 << xinput_slot);
80  }
81 }
82 
83 static void
84 HIDAPI_DriverXbox360_MarkXInputSlotFree(Uint8 xinput_slot)
85 {
86  if (xinput_slot != XUSER_INDEX_ANY) {
87  xinput_slots &= ~(0x01 << xinput_slot);
88  }
89 }
90 
91 static SDL_bool
92 HIDAPI_DriverXbox360_MissingXInputSlot()
93 {
94  return xinput_slots != 0x0F;
95 }
96 
97 static Uint8
98 HIDAPI_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 
129 static void
130 HIDAPI_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 
165 static Uint8
166 HIDAPI_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 
190 static void
191 HIDAPI_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 
229 static void
230 HIDAPI_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 
249 static SDL_bool
250 HIDAPI_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  return SDL_IsJoystickXbox360(vendor_id, product_id) || SDL_IsJoystickXboxOne(vendor_id, product_id);
258 #else
259  return SDL_IsJoystickXbox360(vendor_id, product_id);
260 #endif
261 }
262 
263 static const char *
264 HIDAPI_DriverXbox360_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
265 {
266  return HIDAPI_XboxControllerName(vendor_id, product_id);
267 }
268 
269 static SDL_bool SetSlotLED(hid_device *dev, Uint8 slot)
270 {
271  const Uint8 led_packet[] = { 0x01, 0x03, (2 + slot) };
272 
273  if (hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
274  return SDL_FALSE;
275  }
276  return SDL_TRUE;
277 }
278 
279 static SDL_bool
280 HIDAPI_DriverXbox360_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
281 {
282  SDL_DriverXbox360_Context *ctx;
283 
284  ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
285  if (!ctx) {
286  SDL_OutOfMemory();
287  return SDL_FALSE;
288  }
289 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
290  ctx->xinput_enabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE);
291  if (ctx->xinput_enabled && WIN_LoadXInputDLL() < 0) {
292  ctx->xinput_enabled = SDL_FALSE;
293  }
294  ctx->xinput_slot = XUSER_INDEX_ANY;
295 #endif
296 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
297  HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
298 #endif
299  *context = ctx;
300 
301  /* Set the controller LED */
302  SetSlotLED(dev, (joystick->instance_id % 4));
303 
304  /* Initialize the joystick capabilities */
305  joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
306  joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
307  joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
308 
309  return SDL_TRUE;
310 }
311 
312 static int
313 HIDAPI_DriverXbox360_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
314 {
315  SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
316 
317 #ifdef __WIN32__
318  SDL_bool rumbled = SDL_FALSE;
319 
320 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
321  if (!rumbled && ctx->gamepad) {
322  HRESULT hr;
323 
324  ctx->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
325  ctx->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
326  hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(ctx->gamepad, ctx->vibration);
327  if (SUCCEEDED(hr)) {
328  rumbled = SDL_TRUE;
329  }
330  }
331 #endif
332 
333 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
334  if (!rumbled && ctx->xinput_slot != XUSER_INDEX_ANY) {
335  XINPUT_VIBRATION XVibration;
336 
337  if (!XINPUTSETSTATE) {
338  return SDL_Unsupported();
339  }
340 
341  XVibration.wLeftMotorSpeed = low_frequency_rumble;
342  XVibration.wRightMotorSpeed = high_frequency_rumble;
343  if (XINPUTSETSTATE(ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) {
344  rumbled = SDL_TRUE;
345  } else {
346  return SDL_SetError("XInputSetState() failed");
347  }
348  }
349 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
350 
351 #else /* !__WIN32__ */
352 
353 #ifdef __MACOSX__
354  /* On Mac OS X the 360Controller driver uses this short report,
355  and we need to prefix it with a magic token so hidapi passes it through untouched
356  */
357  Uint8 rumble_packet[] = { 'M', 'A', 'G', 'I', 'C', '0', 0x00, 0x04, 0x00, 0x00 };
358 
359  rumble_packet[6+2] = (low_frequency_rumble >> 8);
360  rumble_packet[6+3] = (high_frequency_rumble >> 8);
361 #else
362  Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
363 
364  rumble_packet[3] = (low_frequency_rumble >> 8);
365  rumble_packet[4] = (high_frequency_rumble >> 8);
366 #endif
367 
368  if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
369  return SDL_SetError("Couldn't send rumble packet");
370  }
371 #endif /* __WIN32__ */
372 
373  if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
374  ctx->rumble_expiration = SDL_GetTicks() + duration_ms;
375  } else {
376  ctx->rumble_expiration = 0;
377  }
378  return 0;
379 }
380 
381 #ifdef __WIN32__
382  /* This is the packet format for Xbox 360 and Xbox One controllers on Windows,
383  however with this interface there is no rumble support, no guide button,
384  and the left and right triggers are tied together as a single axis.
385 
386  We use XInput and Windows.Gaming.Input to make up for these shortcomings.
387  */
388 static void
389 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
390 {
391  Sint16 axis;
392  SDL_bool has_trigger_data = SDL_FALSE;
393 
394  if (ctx->last_state[10] != data[10]) {
403  }
404 
405  if (ctx->last_state[11] != data[11]) {
406  SDL_bool dpad_up = SDL_FALSE;
407  SDL_bool dpad_down = SDL_FALSE;
408  SDL_bool dpad_left = SDL_FALSE;
409  SDL_bool dpad_right = SDL_FALSE;
410 
413 
414  switch (data[11] & 0x3C) {
415  case 4:
416  dpad_up = SDL_TRUE;
417  break;
418  case 8:
419  dpad_up = SDL_TRUE;
420  dpad_right = SDL_TRUE;
421  break;
422  case 12:
423  dpad_right = SDL_TRUE;
424  break;
425  case 16:
426  dpad_right = SDL_TRUE;
427  dpad_down = SDL_TRUE;
428  break;
429  case 20:
430  dpad_down = SDL_TRUE;
431  break;
432  case 24:
433  dpad_left = SDL_TRUE;
434  dpad_down = SDL_TRUE;
435  break;
436  case 28:
437  dpad_left = SDL_TRUE;
438  break;
439  case 32:
440  dpad_up = SDL_TRUE;
441  dpad_left = SDL_TRUE;
442  break;
443  default:
444  break;
445  }
450  }
451 
452  axis = (int)*(Uint16*)(&data[0]) - 0x8000;
454  axis = (int)*(Uint16*)(&data[2]) - 0x8000;
456  axis = (int)*(Uint16*)(&data[4]) - 0x8000;
458  axis = (int)*(Uint16*)(&data[6]) - 0x8000;
460 
461 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
462  if (ctx->gamepad_statics && !ctx->gamepad) {
463  Uint8 buttons = 0;
464 
465  if (data[10] & 0x01) {
466  buttons |= (1 << SDL_CONTROLLER_BUTTON_A);
467  }
468  if (data[10] & 0x02) {
469  buttons |= (1 << SDL_CONTROLLER_BUTTON_B);
470  }
471  if (data[10] & 0x04) {
472  buttons |= (1 << SDL_CONTROLLER_BUTTON_X);
473  }
474  if (data[10] & 0x08) {
475  buttons |= (1 << SDL_CONTROLLER_BUTTON_Y);
476  }
477  if (buttons != 0) {
478  HIDAPI_DriverXbox360_GuessGamepad(ctx, buttons);
479  }
480  }
481 
482  if (ctx->gamepad) {
483  HRESULT hr;
484  struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
485 
486  hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(ctx->gamepad, &state);
487  if (SUCCEEDED(hr)) {
489  SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)(state.LeftTrigger * SDL_MAX_UINT16)) - 32768);
490  SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)(state.RightTrigger * SDL_MAX_UINT16)) - 32768);
491  has_trigger_data = SDL_TRUE;
492  }
493  }
494 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
495 
496 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
497  if (ctx->xinput_enabled) {
498  if (ctx->xinput_slot == XUSER_INDEX_ANY && HIDAPI_DriverXbox360_MissingXInputSlot()) {
499  WORD wButtons = 0;
500 
501  if (data[10] & 0x01) {
502  wButtons |= XINPUT_GAMEPAD_A;
503  }
504  if (data[10] & 0x02) {
505  wButtons |= XINPUT_GAMEPAD_B;
506  }
507  if (data[10] & 0x04) {
508  wButtons |= XINPUT_GAMEPAD_X;
509  }
510  if (data[10] & 0x08) {
511  wButtons |= XINPUT_GAMEPAD_Y;
512  }
513  if (wButtons != 0) {
514  Uint8 xinput_slot = HIDAPI_DriverXbox360_GuessXInputSlot(wButtons);
515  if (xinput_slot != XUSER_INDEX_ANY) {
516  HIDAPI_DriverXbox360_MarkXInputSlotUsed(xinput_slot);
517  ctx->xinput_slot = xinput_slot;
518  }
519  }
520  }
521 
522  if (!has_trigger_data && ctx->xinput_slot != XUSER_INDEX_ANY) {
523  XINPUT_STATE_EX xinput_state;
524 
525  if (XINPUTGETSTATE(ctx->xinput_slot, &xinput_state) == ERROR_SUCCESS) {
526  SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (xinput_state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE) ? SDL_PRESSED : SDL_RELEASED);
527  SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)xinput_state.Gamepad.bLeftTrigger * 257) - 32768);
528  SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)xinput_state.Gamepad.bRightTrigger * 257) - 32768);
529  has_trigger_data = SDL_TRUE;
530  }
531  }
532  }
533 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
534 
535  if (!has_trigger_data) {
536  axis = (data[9] * 257) - 32768;
537  if (data[9] < 0x80) {
538  axis = -axis * 2 - 32769;
540  } else if (data[9] > 0x80) {
541  axis = axis * 2 - 32767;
543  } else {
546  }
547  }
548 
549  SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
550 }
551 #else
552 
553 static void
554 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
555 {
556  Sint16 axis;
557 #ifdef __MACOSX__
558  const SDL_bool invert_y_axes = SDL_FALSE;
559 #else
560  const SDL_bool invert_y_axes = SDL_TRUE;
561 #endif
562 
563  if (ctx->last_state[2] != data[2]) {
572  }
573 
574  if (ctx->last_state[3] != data[3]) {
582  }
583 
584  axis = ((int)data[4] * 257) - 32768;
586  axis = ((int)data[5] * 257) - 32768;
588  axis = *(Sint16*)(&data[6]);
590  axis = *(Sint16*)(&data[8]);
591  if (invert_y_axes) {
592  axis = ~axis;
593  }
595  axis = *(Sint16*)(&data[10]);
597  axis = *(Sint16*)(&data[12]);
598  if (invert_y_axes) {
599  axis = ~axis;
600  }
602 
603  SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
604 }
605 #endif /* __WIN32__ */
606 
607 #ifdef __MACOSX__
608 static void
609 HIDAPI_DriverXboxOneS_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
610 {
611  Sint16 axis;
612 
613  if (ctx->last_state[14] != data[14]) {
620  }
621 
622  if (ctx->last_state[15] != data[15]) {
626  }
627 
628  if (ctx->last_state[16] != data[16]) {
630  }
631 
632  if (ctx->last_state[13] != data[13]) {
633  SDL_bool dpad_up = SDL_FALSE;
634  SDL_bool dpad_down = SDL_FALSE;
635  SDL_bool dpad_left = SDL_FALSE;
636  SDL_bool dpad_right = SDL_FALSE;
637 
638  switch (data[13]) {
639  case 1:
640  dpad_up = SDL_TRUE;
641  break;
642  case 2:
643  dpad_up = SDL_TRUE;
644  dpad_right = SDL_TRUE;
645  break;
646  case 3:
647  dpad_right = SDL_TRUE;
648  break;
649  case 4:
650  dpad_right = SDL_TRUE;
651  dpad_down = SDL_TRUE;
652  break;
653  case 5:
654  dpad_down = SDL_TRUE;
655  break;
656  case 6:
657  dpad_left = SDL_TRUE;
658  dpad_down = SDL_TRUE;
659  break;
660  case 7:
661  dpad_left = SDL_TRUE;
662  break;
663  case 8:
664  dpad_up = SDL_TRUE;
665  dpad_left = SDL_TRUE;
666  break;
667  default:
668  break;
669  }
674  }
675 
676  axis = (int)*(Uint16*)(&data[1]) - 0x8000;
678  axis = (int)*(Uint16*)(&data[3]) - 0x8000;
680  axis = (int)*(Uint16*)(&data[5]) - 0x8000;
682  axis = (int)*(Uint16*)(&data[7]) - 0x8000;
684 
685  axis = ((int)*(Sint16*)(&data[9]) * 64) - 32768;
686  if (axis == 32704) {
687  axis = 32767;
688  }
690 
691  axis = ((int)*(Sint16*)(&data[11]) * 64) - 32768;
692  if (axis == 32704) {
693  axis = 32767;
694  }
696 
697  SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
698 }
699 
700 static void
701 HIDAPI_DriverXboxOneS_HandleGuidePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
702 {
704 }
705 #endif /* __MACOSX__ */
706 
707 static SDL_bool
708 HIDAPI_DriverXbox360_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
709 {
710  SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
711  Uint8 data[USB_PACKET_LENGTH];
712  int size;
713 
714  while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
715 #ifdef __WIN32__
716  HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
717 #else
718  switch (data[0]) {
719  case 0x00:
720  HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
721  break;
722 #ifdef __MACOSX__
723  case 0x01:
724  HIDAPI_DriverXboxOneS_HandleStatePacket(joystick, dev, ctx, data, size);
725  break;
726  case 0x02:
727  HIDAPI_DriverXboxOneS_HandleGuidePacket(joystick, dev, ctx, data, size);
728  break;
729 #endif
730  default:
731 #ifdef DEBUG_JOYSTICK
732  SDL_Log("Unknown Xbox 360 packet, size = %d\n", size);
733  SDL_Log("%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
734  data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
735  data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16]);
736 #endif
737  break;
738  }
739 #endif /* __WIN32__ */
740  }
741 
742  if (ctx->rumble_expiration) {
743  Uint32 now = SDL_GetTicks();
744  if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
745  HIDAPI_DriverXbox360_Rumble(joystick, dev, context, 0, 0, 0);
746  }
747  }
748 
749  return (size >= 0);
750 }
751 
752 static void
753 HIDAPI_DriverXbox360_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
754 {
755 #if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
756  SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
757 #endif
758 
759 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
760  if (ctx->xinput_enabled) {
761  HIDAPI_DriverXbox360_MarkXInputSlotFree(ctx->xinput_slot);
762  WIN_UnloadXInputDLL();
763  }
764 #endif
765 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
766  HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
767 #endif
768  SDL_free(context);
769 }
770 
772 {
774  SDL_TRUE,
775  HIDAPI_DriverXbox360_IsSupportedDevice,
776  HIDAPI_DriverXbox360_GetDeviceName,
777  HIDAPI_DriverXbox360_Init,
778  HIDAPI_DriverXbox360_Rumble,
779  HIDAPI_DriverXbox360_Update,
780  HIDAPI_DriverXbox360_Quit
781 };
782 
783 #endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
784 
785 #endif /* SDL_JOYSTICK_HIDAPI */
786 
787 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
GLsizei const GLchar *const * string
struct xkb_state * state
static screen_context_t context
Definition: video.c:25
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:961
uint16_t Uint16
Definition: SDL_stdinc.h:191
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_Texture * axis
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.
Definition: hid.cpp:1028
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:828
SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor, Uint16 product)
#define SDL_GetHintBoolean
#define SDL_HINT_XINPUT_ENABLED
A variable that lets you disable the detection and use of Xinput gamepad devices. ...
Definition: SDL_hints.h:418
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.
Definition: hid.cpp:1040
#define FAILED(x)
Definition: SDL_directx.h:54
#define SDL_Log
#define SDL_memcpy
const char * HIDAPI_XboxControllerName(Uint16 vendor_id, Uint16 product_id)
#define SDL_HINT_JOYSTICK_HIDAPI_XBOX
A variable controlling whether the HIDAPI driver for XBox controllers should be used.
Definition: SDL_hints.h:546
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
#define SDL_wcslen
HRESULT WIN_CoInitialize(void)
uint8_t Uint8
Definition: SDL_stdinc.h:179
#define SDL_free
GLsizeiptr size
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:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:161
void WIN_CoUninitialize(void)
static NativeWindowFactory * factory
Definition: testnative.c:37
#define SUCCEEDED(x)
Definition: SDL_directx.h:51
#define SDL_SetError
#define SDL_MIN_SINT16
Definition: SDL_stdinc.h:184
#define SDL_calloc
#define SDL_MAX_UINT16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:189
SDL_bool SDL_IsJoystickXbox360(Uint16 vendor, Uint16 product)
uint32_t Uint32
Definition: SDL_stdinc.h:203
#define SDL_PRESSED
Definition: SDL_events.h:50
GLuint GLsizei GLsizei * length
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
#define SDL_RELEASED
Definition: SDL_events.h:49
static struct @63 buttons[NUM_DRUMS]
#define SDL_Unsupported()
Definition: SDL_error.h:53
int16_t Sint16
Definition: SDL_stdinc.h:185
EGLContext ctx
Definition: eglext.h:208