SDL  2.0
SDL_hidapi_xbox360.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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 #include "SDL_hidapi_rumble.h"
34 
35 
36 #ifdef SDL_JOYSTICK_HIDAPI_XBOX360
37 
38 #ifdef __WIN32__
39 #define SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
40 /* This requires the Windows 10 SDK to build */
41 /*#define SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT*/
42 #endif
43 
44 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
45 #include "../../core/windows/SDL_xinput.h"
46 #endif
47 
48 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
49 #include "../../core/windows/SDL_windows.h"
50 #define COBJMACROS
51 #include "windows.gaming.input.h"
52 #endif
53 
54 
55 typedef struct {
56  Uint8 last_state[USB_PACKET_LENGTH];
57 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
58  SDL_bool xinput_enabled;
59  Uint8 xinput_slot;
60 #endif
61 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
62  SDL_bool coinitialized;
63  __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics;
64  __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
65  struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
66 #endif
67 } SDL_DriverXbox360_Context;
68 
69 
70 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
71 static Uint8 xinput_slots;
72 
73 static void
74 HIDAPI_DriverXbox360_MarkXInputSlotUsed(Uint8 xinput_slot)
75 {
76  if (xinput_slot != XUSER_INDEX_ANY) {
77  xinput_slots |= (0x01 << xinput_slot);
78  }
79 }
80 
81 static void
82 HIDAPI_DriverXbox360_MarkXInputSlotFree(Uint8 xinput_slot)
83 {
84  if (xinput_slot != XUSER_INDEX_ANY) {
85  xinput_slots &= ~(0x01 << xinput_slot);
86  }
87 }
88 
89 static SDL_bool
90 HIDAPI_DriverXbox360_MissingXInputSlot()
91 {
92  return xinput_slots != 0x0F;
93 }
94 
95 static Uint8
96 HIDAPI_DriverXbox360_GuessXInputSlot(WORD wButtons)
97 {
98  DWORD user_index;
99  int match_count;
100  Uint8 match_slot;
101 
102  if (!XINPUTGETSTATE) {
103  return XUSER_INDEX_ANY;
104  }
105 
106  match_count = 0;
107  for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) {
108  XINPUT_STATE_EX xinput_state;
109 
110  if (XINPUTGETSTATE(user_index, &xinput_state) == ERROR_SUCCESS) {
111  if (xinput_state.Gamepad.wButtons == wButtons) {
112  ++match_count;
113  match_slot = (Uint8)user_index;
114  }
115  }
116  }
117  if (match_count == 1) {
118  return match_slot;
119  }
120  return XUSER_INDEX_ANY;
121 }
122 
123 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
124 
125 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
126 
127 static void
128 HIDAPI_DriverXbox360_InitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
129 {
130  /* I think this takes care of RoInitialize() in a way that is compatible with the rest of SDL */
131  if (FAILED(WIN_CoInitialize())) {
132  return;
133  }
134  ctx->coinitialized = SDL_TRUE;
135 
136  {
137  static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } };
138  HRESULT hr;
139  HMODULE hModule = LoadLibraryA("combase.dll");
140  if (hModule != NULL) {
141  typedef HRESULT (WINAPI *WindowsCreateString_t)(PCNZWCH sourceString, UINT32 length, HSTRING* string);
142  typedef HRESULT (WINAPI *WindowsDeleteString_t)(HSTRING string);
143  typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory);
144 
145  WindowsCreateString_t WindowsCreateStringFunc = (WindowsCreateString_t)GetProcAddress(hModule, "WindowsCreateString");
146  WindowsDeleteString_t WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule, "WindowsDeleteString");
147  RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory");
148  if (WindowsCreateStringFunc && WindowsDeleteStringFunc && RoGetActivationFactoryFunc) {
149  LPTSTR pNamespace = L"Windows.Gaming.Input.Gamepad";
150  HSTRING hNamespaceString;
151 
152  hr = WindowsCreateStringFunc(pNamespace, SDL_wcslen(pNamespace), &hNamespaceString);
153  if (SUCCEEDED(hr)) {
154  RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, &ctx->gamepad_statics);
155  WindowsDeleteStringFunc(hNamespaceString);
156  }
157  }
158  FreeLibrary(hModule);
159  }
160  }
161 }
162 
163 static Uint8
164 HIDAPI_DriverXbox360_GetGamepadButtonsForMatch(__x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad)
165 {
166  HRESULT hr;
167  struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
168  Uint8 buttons = 0;
169 
170  hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(gamepad, &state);
171  if (SUCCEEDED(hr)) {
172  if (state.Buttons & GamepadButtons_A) {
173  buttons |= (1 << SDL_CONTROLLER_BUTTON_A);
174  }
175  if (state.Buttons & GamepadButtons_B) {
176  buttons |= (1 << SDL_CONTROLLER_BUTTON_B);
177  }
178  if (state.Buttons & GamepadButtons_X) {
179  buttons |= (1 << SDL_CONTROLLER_BUTTON_X);
180  }
181  if (state.Buttons & GamepadButtons_Y) {
182  buttons |= (1 << SDL_CONTROLLER_BUTTON_Y);
183  }
184  }
185  return buttons;
186 }
187 
188 static void
189 HIDAPI_DriverXbox360_GuessGamepad(SDL_DriverXbox360_Context *ctx, Uint8 buttons)
190 {
191  HRESULT hr;
192  __FIVectorView_1_Windows__CGaming__CInput__CGamepad *gamepads;
193 
194  hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_get_Gamepads(ctx->gamepad_statics, &gamepads);
195  if (SUCCEEDED(hr)) {
196  unsigned int i, num_gamepads;
197 
198  hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_get_Size(gamepads, &num_gamepads);
199  if (SUCCEEDED(hr)) {
200  int match_count;
201  unsigned int match_slot;
202 
203  match_count = 0;
204  for (i = 0; i < num_gamepads; ++i) {
205  __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
206 
207  hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, i, &gamepad);
208  if (SUCCEEDED(hr)) {
209  Uint8 gamepad_buttons = HIDAPI_DriverXbox360_GetGamepadButtonsForMatch(gamepad);
210  if (buttons == gamepad_buttons) {
211  ++match_count;
212  match_slot = i;
213  }
214  __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
215  }
216  }
217  if (match_count == 1) {
218  hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, match_slot, &ctx->gamepad);
219  if (SUCCEEDED(hr)) {
220  }
221  }
222  }
223  __FIVectorView_1_Windows__CGaming__CInput__CGamepad_Release(gamepads);
224  }
225 }
226 
227 static void
228 HIDAPI_DriverXbox360_QuitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
229 {
230  if (ctx->gamepad_statics) {
231  __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(ctx->gamepad_statics);
232  ctx->gamepad_statics = NULL;
233  }
234  if (ctx->gamepad) {
235  __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(ctx->gamepad);
236  ctx->gamepad = NULL;
237  }
238 
239  if (ctx->coinitialized) {
241  ctx->coinitialized = SDL_FALSE;
242  }
243 }
244 
245 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
246 
247 #if defined(__MACOSX__)
248 static SDL_bool
249 IsBluetoothXboxOneController(Uint16 vendor_id, Uint16 product_id)
250 {
251  /* Check to see if it's the Xbox One S or Xbox One Elite Series 2 in Bluetooth mode */
252  if (vendor_id == USB_VENDOR_MICROSOFT) {
253  if (product_id == USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH ||
256  return SDL_TRUE;
257  }
258  }
259  return SDL_FALSE;
260 }
261 #endif
262 
263 static SDL_bool
264 HIDAPI_DriverXbox360_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
265 {
266  const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */
267 
268  if (vendor_id == USB_VENDOR_NVIDIA) {
269  /* This is the NVIDIA Shield controller which doesn't talk Xbox controller protocol */
270  return SDL_FALSE;
271  }
272  if ((vendor_id == USB_VENDOR_MICROSOFT && (product_id == 0x0291 || product_id == 0x0719)) ||
273  (type == SDL_CONTROLLER_TYPE_XBOX360 && interface_protocol == XB360W_IFACE_PROTOCOL)) {
274  /* This is the wireless dongle, which talks a different protocol */
275  return SDL_FALSE;
276  }
277  if (interface_number > 0) {
278  /* This is the chatpad or other input interface, not the Xbox 360 interface */
279  return SDL_FALSE;
280  }
281 #if defined(__MACOSX__) || defined(__WIN32__)
282  if (vendor_id == USB_VENDOR_MICROSOFT && product_id == 0x028e && version == 1) {
283  /* This is the Steam Virtual Gamepad, which isn't supported by this driver */
284  return SDL_FALSE;
285  }
286 #if defined(__MACOSX__)
287  /* Wired Xbox One controllers are handled by this driver, interfacing with
288  the 360Controller driver available from:
289  https://github.com/360Controller/360Controller/releases
290 
291  Bluetooth Xbox One controllers are handled by the SDL Xbox One driver
292  */
293  if (IsBluetoothXboxOneController(vendor_id, product_id)) {
294  return SDL_FALSE;
295  }
296 #endif
298 #else
299  return (type == SDL_CONTROLLER_TYPE_XBOX360);
300 #endif
301 }
302 
303 static const char *
304 HIDAPI_DriverXbox360_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
305 {
306  return NULL;
307 }
308 
309 static SDL_bool SetSlotLED(hid_device *dev, Uint8 slot)
310 {
311  Uint8 mode = 0x02 + slot;
312  const Uint8 led_packet[] = { 0x01, 0x03, mode };
313 
314  if (hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
315  return SDL_FALSE;
316  }
317  return SDL_TRUE;
318 }
319 
320 static SDL_bool
321 HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *device)
322 {
324 }
325 
326 static int
327 HIDAPI_DriverXbox360_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
328 {
329  return -1;
330 }
331 
332 static void
333 HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
334 {
335  if (device->dev) {
336  SetSlotLED(device->dev, (player_index % 4));
337  }
338 }
339 
340 static SDL_bool
341 HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
342 {
343  SDL_DriverXbox360_Context *ctx;
344  int player_index;
345 
346  ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
347  if (!ctx) {
348  SDL_OutOfMemory();
349  return SDL_FALSE;
350  }
351 
352  device->dev = hid_open_path(device->path, 0);
353  if (!device->dev) {
354  SDL_free(ctx);
355  SDL_SetError("Couldn't open %s", device->path);
356  return SDL_FALSE;
357  }
358  device->context = ctx;
359 
360 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
362  if (ctx->xinput_enabled && WIN_LoadXInputDLL() < 0) {
363  ctx->xinput_enabled = SDL_FALSE;
364  }
365  ctx->xinput_slot = XUSER_INDEX_ANY;
366 #endif
367 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
368  HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
369 #endif
370 
371  /* Set the controller LED */
372  player_index = SDL_JoystickGetPlayerIndex(joystick);
373  if (player_index >= 0) {
374  SetSlotLED(device->dev, (player_index % 4));
375  }
376 
377  /* Initialize the joystick capabilities */
378  joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
379  joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
380  joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
381 
382  return SDL_TRUE;
383 }
384 
385 static int
386 HIDAPI_DriverXbox360_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
387 {
388 #if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT)
389  SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
390 #endif
391 
392 #ifdef __WIN32__
393  SDL_bool rumbled = SDL_FALSE;
394 
395 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
396  if (!rumbled && ctx->gamepad) {
397  HRESULT hr;
398 
399  ctx->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
400  ctx->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
401  hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(ctx->gamepad, ctx->vibration);
402  if (SUCCEEDED(hr)) {
403  rumbled = SDL_TRUE;
404  }
405  }
406 #endif
407 
408 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
409  if (!rumbled && ctx->xinput_slot != XUSER_INDEX_ANY) {
410  XINPUT_VIBRATION XVibration;
411 
412  if (!XINPUTSETSTATE) {
413  return SDL_Unsupported();
414  }
415 
416  XVibration.wLeftMotorSpeed = low_frequency_rumble;
417  XVibration.wRightMotorSpeed = high_frequency_rumble;
418  if (XINPUTSETSTATE(ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) {
419  rumbled = SDL_TRUE;
420  } else {
421  return SDL_SetError("XInputSetState() failed");
422  }
423  }
424 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
425 
426 #else /* !__WIN32__ */
427 
428 #ifdef __MACOSX__
429  if (IsBluetoothXboxOneController(device->vendor_id, device->product_id)) {
430  Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00 };
431 
432  rumble_packet[4] = (low_frequency_rumble >> 8);
433  rumble_packet[5] = (high_frequency_rumble >> 8);
434 
435  if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
436  return SDL_SetError("Couldn't send rumble packet");
437  }
438  } else {
439  /* On Mac OS X the 360Controller driver uses this short report,
440  and we need to prefix it with a magic token so hidapi passes it through untouched
441  */
442  Uint8 rumble_packet[] = { 'M', 'A', 'G', 'I', 'C', '0', 0x00, 0x04, 0x00, 0x00 };
443 
444  rumble_packet[6+2] = (low_frequency_rumble >> 8);
445  rumble_packet[6+3] = (high_frequency_rumble >> 8);
446 
447  if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
448  return SDL_SetError("Couldn't send rumble packet");
449  }
450  }
451 #else
452  Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
453 
454  rumble_packet[3] = (low_frequency_rumble >> 8);
455  rumble_packet[4] = (high_frequency_rumble >> 8);
456 
457  if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
458  return SDL_SetError("Couldn't send rumble packet");
459  }
460 #endif
461 #endif /* __WIN32__ */
462 
463  return 0;
464 }
465 
466 #ifdef __WIN32__
467  /* This is the packet format for Xbox 360 and Xbox One controllers on Windows,
468  however with this interface there is no rumble support, no guide button,
469  and the left and right triggers are tied together as a single axis.
470 
471  We use XInput and Windows.Gaming.Input to make up for these shortcomings.
472  */
473 static void
474 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
475 {
476  Sint16 axis;
477  SDL_bool has_trigger_data = SDL_FALSE;
478 
479  if (ctx->last_state[10] != data[10]) {
488  }
489 
490  if (ctx->last_state[11] != data[11]) {
491  SDL_bool dpad_up = SDL_FALSE;
492  SDL_bool dpad_down = SDL_FALSE;
493  SDL_bool dpad_left = SDL_FALSE;
494  SDL_bool dpad_right = SDL_FALSE;
495 
498 
499  switch (data[11] & 0x3C) {
500  case 4:
501  dpad_up = SDL_TRUE;
502  break;
503  case 8:
504  dpad_up = SDL_TRUE;
505  dpad_right = SDL_TRUE;
506  break;
507  case 12:
508  dpad_right = SDL_TRUE;
509  break;
510  case 16:
511  dpad_right = SDL_TRUE;
512  dpad_down = SDL_TRUE;
513  break;
514  case 20:
515  dpad_down = SDL_TRUE;
516  break;
517  case 24:
518  dpad_left = SDL_TRUE;
519  dpad_down = SDL_TRUE;
520  break;
521  case 28:
522  dpad_left = SDL_TRUE;
523  break;
524  case 32:
525  dpad_up = SDL_TRUE;
526  dpad_left = SDL_TRUE;
527  break;
528  default:
529  break;
530  }
535  }
536 
537  axis = (int)*(Uint16*)(&data[0]) - 0x8000;
539  axis = (int)*(Uint16*)(&data[2]) - 0x8000;
541  axis = (int)*(Uint16*)(&data[4]) - 0x8000;
543  axis = (int)*(Uint16*)(&data[6]) - 0x8000;
545 
546 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
547  if (ctx->gamepad_statics && !ctx->gamepad) {
548  Uint8 buttons = 0;
549 
550  if (data[10] & 0x01) {
551  buttons |= (1 << SDL_CONTROLLER_BUTTON_A);
552  }
553  if (data[10] & 0x02) {
554  buttons |= (1 << SDL_CONTROLLER_BUTTON_B);
555  }
556  if (data[10] & 0x04) {
557  buttons |= (1 << SDL_CONTROLLER_BUTTON_X);
558  }
559  if (data[10] & 0x08) {
560  buttons |= (1 << SDL_CONTROLLER_BUTTON_Y);
561  }
562  if (buttons != 0) {
563  HIDAPI_DriverXbox360_GuessGamepad(ctx, buttons);
564  }
565  }
566 
567  if (ctx->gamepad) {
568  HRESULT hr;
569  struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
570 
571  hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(ctx->gamepad, &state);
572  if (SUCCEEDED(hr)) {
574  SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)(state.LeftTrigger * SDL_MAX_UINT16)) - 32768);
575  SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)(state.RightTrigger * SDL_MAX_UINT16)) - 32768);
576  has_trigger_data = SDL_TRUE;
577  }
578  }
579 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
580 
581 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
582  if (ctx->xinput_enabled) {
583  if (ctx->xinput_slot == XUSER_INDEX_ANY && HIDAPI_DriverXbox360_MissingXInputSlot()) {
584  WORD wButtons = 0;
585 
586  if (data[10] & 0x01) {
587  wButtons |= XINPUT_GAMEPAD_A;
588  }
589  if (data[10] & 0x02) {
590  wButtons |= XINPUT_GAMEPAD_B;
591  }
592  if (data[10] & 0x04) {
593  wButtons |= XINPUT_GAMEPAD_X;
594  }
595  if (data[10] & 0x08) {
596  wButtons |= XINPUT_GAMEPAD_Y;
597  }
598  if (wButtons != 0) {
599  Uint8 xinput_slot = HIDAPI_DriverXbox360_GuessXInputSlot(wButtons);
600  if (xinput_slot != XUSER_INDEX_ANY) {
601  HIDAPI_DriverXbox360_MarkXInputSlotUsed(xinput_slot);
602  ctx->xinput_slot = xinput_slot;
603  }
604  }
605  }
606 
607  if (!has_trigger_data && ctx->xinput_slot != XUSER_INDEX_ANY) {
608  XINPUT_STATE_EX xinput_state;
609 
610  if (XINPUTGETSTATE(ctx->xinput_slot, &xinput_state) == ERROR_SUCCESS) {
611  SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (xinput_state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE) ? SDL_PRESSED : SDL_RELEASED);
612  SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)xinput_state.Gamepad.bLeftTrigger * 257) - 32768);
613  SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)xinput_state.Gamepad.bRightTrigger * 257) - 32768);
614  has_trigger_data = SDL_TRUE;
615  }
616  }
617  }
618 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
619 
620  if (!has_trigger_data) {
621  axis = (data[9] * 257) - 32768;
622  if (data[9] < 0x80) {
623  axis = -axis * 2 - 32769;
625  } else if (data[9] > 0x80) {
626  axis = axis * 2 - 32767;
628  } else {
631  }
632  }
633 
634  SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
635 }
636 #else
637 
638 static void
639 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
640 {
641  Sint16 axis;
642 #ifdef __MACOSX__
643  const SDL_bool invert_y_axes = SDL_FALSE;
644 #else
645  const SDL_bool invert_y_axes = SDL_TRUE;
646 #endif
647 
648  if (ctx->last_state[2] != data[2]) {
657  }
658 
659  if (ctx->last_state[3] != data[3]) {
667  }
668 
669  axis = ((int)data[4] * 257) - 32768;
671  axis = ((int)data[5] * 257) - 32768;
673  axis = *(Sint16*)(&data[6]);
675  axis = *(Sint16*)(&data[8]);
676  if (invert_y_axes) {
677  axis = ~axis;
678  }
680  axis = *(Sint16*)(&data[10]);
682  axis = *(Sint16*)(&data[12]);
683  if (invert_y_axes) {
684  axis = ~axis;
685  }
687 
688  SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
689 }
690 #endif /* __WIN32__ */
691 
692 static SDL_bool
693 HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
694 {
695  SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
696  SDL_Joystick *joystick = NULL;
698  int size;
699 
700  if (device->num_joysticks > 0) {
701  joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
702  }
703  if (!joystick) {
704  return SDL_FALSE;
705  }
706 
707  while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
708  HIDAPI_DriverXbox360_HandleStatePacket(joystick, device->dev, ctx, data, size);
709  }
710 
711  if (size < 0) {
712  /* Read error, device is disconnected */
713  HIDAPI_JoystickDisconnected(device, joystick->instance_id);
714  }
715  return (size >= 0);
716 }
717 
718 static void
719 HIDAPI_DriverXbox360_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
720 {
721 #if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
722  SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
723 #endif
724 
725 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
726  if (ctx->xinput_enabled) {
727  HIDAPI_DriverXbox360_MarkXInputSlotFree(ctx->xinput_slot);
728  WIN_UnloadXInputDLL();
729  }
730 #endif
731 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
732  HIDAPI_DriverXbox360_QuitWindowsGamingInput(ctx);
733 #endif
734 
735  hid_close(device->dev);
736  device->dev = NULL;
737 
738  SDL_free(device->context);
739  device->context = NULL;
740 }
741 
742 static void
743 HIDAPI_DriverXbox360_FreeDevice(SDL_HIDAPI_Device *device)
744 {
745 }
746 
748 {
750  SDL_TRUE,
751  HIDAPI_DriverXbox360_IsSupportedDevice,
752  HIDAPI_DriverXbox360_GetDeviceName,
753  HIDAPI_DriverXbox360_InitDevice,
754  HIDAPI_DriverXbox360_GetDevicePlayerIndex,
755  HIDAPI_DriverXbox360_SetDevicePlayerIndex,
756  HIDAPI_DriverXbox360_UpdateDevice,
757  HIDAPI_DriverXbox360_OpenJoystick,
758  HIDAPI_DriverXbox360_RumbleJoystick,
759  HIDAPI_DriverXbox360_CloseJoystick,
760  HIDAPI_DriverXbox360_FreeDevice
761 };
762 
763 #endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
764 
765 #endif /* SDL_JOYSTICK_HIDAPI */
766 
767 /* vi: set ts=4 sw=4 expandtab: */
SDL_CONTROLLER_BUTTON_DPAD_LEFT
@ SDL_CONTROLLER_BUTTON_DPAD_LEFT
Definition: SDL_gamecontroller.h:362
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179
SDL_CONTROLLER_AXIS_RIGHTX
@ SDL_CONTROLLER_AXIS_RIGHTX
Definition: SDL_gamecontroller.h:307
SDL_events.h
Uint16
uint16_t Uint16
Definition: SDL_stdinc.h:191
if
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
Definition: pixman-arm-neon-asm.h:469
hid_write
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.
NULL
#define NULL
Definition: begin_code.h:167
SDL_timer.h
endif
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld endif[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld_src SRC pixld MASK if DST_R else pixld DST_R endif if
Definition: pixman-arm-neon-asm.h:549
HIDAPI_JoystickConnected
SDL_bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID)
SDL_joystick.h
USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH
#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH
Definition: usb_ids.h:45
SDL_JoystickID
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
mode
GLenum mode
Definition: SDL_opengl_glext.h:1125
hid_close
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device)
Close a HID device.
SDL_log.h
USB_VENDOR_MICROSOFT
#define USB_VENDOR_MICROSOFT
Definition: usb_ids.h:28
SDL_MAX_UINT16
#define SDL_MAX_UINT16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:189
__WIN32__
#define __WIN32__
Definition: SDL_platform.h:155
SDL_hidapi_rumble.h
SDL_CONTROLLER_BUTTON_RIGHTSTICK
@ SDL_CONTROLLER_BUTTON_RIGHTSTICK
Definition: SDL_gamecontroller.h:357
USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH
#define USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH
Definition: usb_ids.h:47
SDL_CONTROLLER_AXIS_LEFTX
@ SDL_CONTROLLER_AXIS_LEFTX
Definition: SDL_gamecontroller.h:305
SDL_HIDAPI_Device
Definition: SDL_hidapijoystick_c.h:64
USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH
#define USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH
Definition: usb_ids.h:46
SDL_RELEASED
#define SDL_RELEASED
Definition: SDL_events.h:49
length
GLuint GLsizei GLsizei * length
Definition: SDL_opengl_glext.h:672
ctx
EGLContext ctx
Definition: eglext.h:208
SDL_CONTROLLER_BUTTON_B
@ SDL_CONTROLLER_BUTTON_B
Definition: SDL_gamecontroller.h:350
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_CONTROLLER_BUTTON_MAX
@ SDL_CONTROLLER_BUTTON_MAX
Definition: SDL_gamecontroller.h:364
SDL_JoystickGetPlayerIndex
#define SDL_JoystickGetPlayerIndex
Definition: SDL_dynapi_overrides.h:702
SDL_PrivateJoystickAxis
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:1023
factory
static NativeWindowFactory * factory
Definition: testnative.c:37
SDL_hidapijoystick_c.h
SDL_CONTROLLER_BUTTON_BACK
@ SDL_CONTROLLER_BUTTON_BACK
Definition: SDL_gamecontroller.h:353
SDL_CONTROLLER_BUTTON_LEFTSHOULDER
@ SDL_CONTROLLER_BUTTON_LEFTSHOULDER
Definition: SDL_gamecontroller.h:358
SDL_PRESSED
#define SDL_PRESSED
Definition: SDL_events.h:50
Sint16
int16_t Sint16
Definition: SDL_stdinc.h:185
SDL_HIDAPI_DriverXbox360
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360
SDL_memcpy
#define SDL_memcpy
Definition: SDL_dynapi_overrides.h:387
SDL_GetHintBoolean
#define SDL_GetHintBoolean
Definition: SDL_dynapi_overrides.h:608
SDL_HINT_XINPUT_ENABLED
#define SDL_HINT_XINPUT_ENABLED
A variable that lets you disable the detection and use of Xinput gamepad devices.
Definition: SDL_hints.h:460
SDL_HINT_JOYSTICK_HIDAPI_XBOX
#define SDL_HINT_JOYSTICK_HIDAPI_XBOX
A variable controlling whether the HIDAPI driver for XBox controllers should be used.
Definition: SDL_hints.h:639
SDL_CONTROLLER_AXIS_TRIGGERLEFT
@ SDL_CONTROLLER_AXIS_TRIGGERLEFT
Definition: SDL_gamecontroller.h:309
SDL_JoystickFromInstanceID
#define SDL_JoystickFromInstanceID
Definition: SDL_dynapi_overrides.h:595
WIN_CoUninitialize
void WIN_CoUninitialize(void)
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
hid_read_timeout
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.
SUCCEEDED
#define SUCCEEDED(x)
Definition: SDL_directx.h:51
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:663
SDL_JOYSTICK_POWER_WIRED
@ SDL_JOYSTICK_POWER_WIRED
Definition: SDL_joystick.h:104
SDL_HIDAPI_DeviceDriver
Definition: SDL_hidapijoystick_c.h:93
SDL_PrivateJoystickButton
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:1162
SDL_CONTROLLER_AXIS_MAX
@ SDL_CONTROLLER_AXIS_MAX
Definition: SDL_gamecontroller.h:311
SDL_wcslen
#define SDL_wcslen
Definition: SDL_dynapi_overrides.h:390
SDL_min
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
SDL_gamecontroller.h
SDL_MIN_SINT16
#define SDL_MIN_SINT16
Definition: SDL_stdinc.h:184
SDL_CONTROLLER_BUTTON_START
@ SDL_CONTROLLER_BUTTON_START
Definition: SDL_gamecontroller.h:355
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
hid_open_path
HID_API_EXPORT hid_device *HID_API_CALL hid_open_path(const char *path, int bExclusive)
Open a HID device by its path name.
axis
SDL_Texture * axis
Definition: testgamecontroller.c:67
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
size
GLsizeiptr size
Definition: SDL_opengl_glext.h:540
WIN_CoInitialize
HRESULT WIN_CoInitialize(void)
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
@ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
Definition: SDL_gamecontroller.h:359
SDL_CONTROLLER_BUTTON_Y
@ SDL_CONTROLLER_BUTTON_Y
Definition: SDL_gamecontroller.h:352
HIDAPI_JoystickDisconnected
void HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID)
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_GameControllerType
SDL_GameControllerType
Definition: SDL_gamecontroller.h:61
USB_PACKET_LENGTH
#define USB_PACKET_LENGTH
Definition: SDL_hidapijoystick_c.h:58
SDL_hints.h
SDL_CONTROLLER_AXIS_LEFTY
@ SDL_CONTROLLER_AXIS_LEFTY
Definition: SDL_gamecontroller.h:306
SDL_CONTROLLER_BUTTON_LEFTSTICK
@ SDL_CONTROLLER_BUTTON_LEFTSTICK
Definition: SDL_gamecontroller.h:356
FAILED
#define FAILED(x)
Definition: SDL_directx.h:54
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:162
SDL_CONTROLLER_TYPE_XBOX360
@ SDL_CONTROLLER_TYPE_XBOX360
Definition: SDL_gamecontroller.h:63
SDL_CONTROLLER_BUTTON_DPAD_DOWN
@ SDL_CONTROLLER_BUTTON_DPAD_DOWN
Definition: SDL_gamecontroller.h:361
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_CONTROLLER_BUTTON_DPAD_UP
@ SDL_CONTROLLER_BUTTON_DPAD_UP
Definition: SDL_gamecontroller.h:360
SDL_Unsupported
#define SDL_Unsupported()
Definition: SDL_error.h:53
string
GLsizei const GLchar *const * string
Definition: SDL_opengl_glext.h:691
SDL_CONTROLLER_AXIS_TRIGGERRIGHT
@ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
Definition: SDL_gamecontroller.h:310
hid_device
struct hid_device_ hid_device
Definition: hidapi.h:54
SDL_CONTROLLER_AXIS_RIGHTY
@ SDL_CONTROLLER_AXIS_RIGHTY
Definition: SDL_gamecontroller.h:308
SDL_CONTROLLER_BUTTON_X
@ SDL_CONTROLLER_BUTTON_X
Definition: SDL_gamecontroller.h:351
device
static SDL_AudioDeviceID device
Definition: loopwave.c:37
SDL_CONTROLLER_BUTTON_A
@ SDL_CONTROLLER_BUTTON_A
Definition: SDL_gamecontroller.h:349
SDL_CONTROLLER_TYPE_XBOXONE
@ SDL_CONTROLLER_TYPE_XBOXONE
Definition: SDL_gamecontroller.h:64
type
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
state
struct xkb_state * state
Definition: SDL_waylandsym.h:114
i
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
USB_VENDOR_NVIDIA
#define USB_VENDOR_NVIDIA
Definition: usb_ids.h:30
SDL_CONTROLLER_BUTTON_DPAD_RIGHT
@ SDL_CONTROLLER_BUTTON_DPAD_RIGHT
Definition: SDL_gamecontroller.h:363
SDL_CONTROLLER_BUTTON_GUIDE
@ SDL_CONTROLLER_BUTTON_GUIDE
Definition: SDL_gamecontroller.h:354