src/joystick/hidapi/SDL_hidapi_xbox360.c
author Sam Lantinga
Mon, 16 Dec 2019 10:20:03 -0800
changeset 13348 448528dc13da
parent 13337 9cbbe45952a4
child 13350 a9ce6aa098b6
permissions -rw-r--r--
Fixed bug 4898 - No rumble because of integer overflow in SDL_JoystickRumble

meyraud705

On a Dualshock 4 controller using hidapi driver, calling SDL_JoystickRumble with a duration too long (SDL_HAPTIC_INFINITY for example) causes the rumble to stop immediately.

This happens because of integer overflow on line 301 of SDL_hidapi_ps4.c
(https://hg.libsdl.org/SDL/file/99ecd178999f/src/joystick/hidapi/SDL_hidapi_ps4.c#l301), which sets expiration time in the past.
     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"
    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) {
   242         WIN_CoUninitialize();
   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, const char *name)
   251 {
   252     SDL_GameControllerType type = SDL_GetJoystickGameControllerType(vendor_id, product_id, name);
   253 
   254     if (vendor_id == 0x0955) {
   255         /* This is the NVIDIA Shield controller which doesn't talk Xbox controller protocol */
   256         return SDL_FALSE;
   257     }
   258 #if defined(__MACOSX__) || defined(__WIN32__)
   259     if (vendor_id == 0x045e && product_id == 0x028e && version == 1) {
   260         /* This is the Steam Virtual Gamepad, which isn't supported by this driver */
   261         return SDL_FALSE;
   262     }
   263     if (vendor_id == 0x045e && product_id == 0x02e0) {
   264         /* This is the old Bluetooth Xbox One S firmware, which isn't supported by this driver */
   265         return SDL_FALSE;
   266     }
   267     return (type == SDL_CONTROLLER_TYPE_XBOX360 || type == SDL_CONTROLLER_TYPE_XBOXONE);
   268 #else
   269     return (type == SDL_CONTROLLER_TYPE_XBOX360);
   270 #endif
   271 }
   272 
   273 static const char *
   274 HIDAPI_DriverXbox360_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
   275 {
   276     return NULL;
   277 }
   278 
   279 static SDL_bool SetSlotLED(hid_device *dev, Uint8 slot)
   280 {
   281     const Uint8 led_packet[] = { 0x01, 0x03, (2 + slot) };
   282 
   283     if (hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
   284         return SDL_FALSE;
   285     }
   286     return SDL_TRUE;
   287 }
   288 
   289 static SDL_bool
   290 HIDAPI_DriverXbox360_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
   291 {
   292     SDL_DriverXbox360_Context *ctx;
   293 
   294     ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
   295     if (!ctx) {
   296         SDL_OutOfMemory();
   297         return SDL_FALSE;
   298     }
   299 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
   300     ctx->xinput_enabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE);
   301     if (ctx->xinput_enabled && WIN_LoadXInputDLL() < 0) {
   302         ctx->xinput_enabled = SDL_FALSE;
   303     }
   304     ctx->xinput_slot = XUSER_INDEX_ANY;
   305 #endif
   306 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
   307     HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
   308 #endif
   309     *context = ctx;
   310 
   311     /* Set the controller LED */
   312     SetSlotLED(dev, (joystick->instance_id % 4));
   313 
   314     /* Initialize the joystick capabilities */
   315     joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
   316     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
   317     joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
   318 
   319     return SDL_TRUE;
   320 }
   321 
   322 static int
   323 HIDAPI_DriverXbox360_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   324 {
   325     SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
   326 
   327 #ifdef __WIN32__
   328     SDL_bool rumbled = SDL_FALSE;
   329 
   330 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
   331     if (!rumbled && ctx->gamepad) {
   332         HRESULT hr;
   333 
   334         ctx->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
   335         ctx->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
   336         hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(ctx->gamepad, ctx->vibration);
   337         if (SUCCEEDED(hr)) {
   338             rumbled = SDL_TRUE;
   339         }
   340     }
   341 #endif
   342 
   343 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
   344     if (!rumbled && ctx->xinput_slot != XUSER_INDEX_ANY) {
   345         XINPUT_VIBRATION XVibration;
   346 
   347         if (!XINPUTSETSTATE) {
   348             return SDL_Unsupported();
   349         }
   350 
   351         XVibration.wLeftMotorSpeed = low_frequency_rumble;
   352         XVibration.wRightMotorSpeed = high_frequency_rumble;
   353         if (XINPUTSETSTATE(ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) {
   354             rumbled = SDL_TRUE;
   355         } else {
   356             return SDL_SetError("XInputSetState() failed");
   357         }
   358     }
   359 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
   360 
   361 #else /* !__WIN32__ */
   362 
   363 #ifdef __MACOSX__
   364     /* On Mac OS X the 360Controller driver uses this short report,
   365        and we need to prefix it with a magic token so hidapi passes it through untouched
   366      */
   367     Uint8 rumble_packet[] = { 'M', 'A', 'G', 'I', 'C', '0', 0x00, 0x04, 0x00, 0x00 };
   368 
   369     rumble_packet[6+2] = (low_frequency_rumble >> 8);
   370     rumble_packet[6+3] = (high_frequency_rumble >> 8);
   371 #else
   372     Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
   373 
   374     rumble_packet[3] = (low_frequency_rumble >> 8);
   375     rumble_packet[4] = (high_frequency_rumble >> 8);
   376 #endif
   377 
   378     if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   379         return SDL_SetError("Couldn't send rumble packet");
   380     }
   381 #endif /* __WIN32__ */
   382 
   383     if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
   384         ctx->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
   385     } else {
   386         ctx->rumble_expiration = 0;
   387     }
   388     return 0;
   389 }
   390 
   391 #ifdef __WIN32__
   392  /* This is the packet format for Xbox 360 and Xbox One controllers on Windows,
   393     however with this interface there is no rumble support, no guide button,
   394     and the left and right triggers are tied together as a single axis.
   395 
   396     We use XInput and Windows.Gaming.Input to make up for these shortcomings.
   397   */
   398 static void
   399 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
   400 {
   401     Sint16 axis;
   402     SDL_bool has_trigger_data = SDL_FALSE;
   403 
   404     if (ctx->last_state[10] != data[10]) {
   405         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[10] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   406         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[10] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   407         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[10] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   408         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[10] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   409         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[10] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   410         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[10] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   411         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[10] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   412         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[10] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   413     }
   414 
   415     if (ctx->last_state[11] != data[11]) {
   416         SDL_bool dpad_up = SDL_FALSE;
   417         SDL_bool dpad_down = SDL_FALSE;
   418         SDL_bool dpad_left = SDL_FALSE;
   419         SDL_bool dpad_right = SDL_FALSE;
   420 
   421         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[11] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   422         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[11] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   423 
   424         switch (data[11] & 0x3C) {
   425         case 4:
   426             dpad_up = SDL_TRUE;
   427             break;
   428         case 8:
   429             dpad_up = SDL_TRUE;
   430             dpad_right = SDL_TRUE;
   431             break;
   432         case 12:
   433             dpad_right = SDL_TRUE;
   434             break;
   435         case 16:
   436             dpad_right = SDL_TRUE;
   437             dpad_down = SDL_TRUE;
   438             break;
   439         case 20:
   440             dpad_down = SDL_TRUE;
   441             break;
   442         case 24:
   443             dpad_left = SDL_TRUE;
   444             dpad_down = SDL_TRUE;
   445             break;
   446         case 28:
   447             dpad_left = SDL_TRUE;
   448             break;
   449         case 32:
   450             dpad_up = SDL_TRUE;
   451             dpad_left = SDL_TRUE;
   452             break;
   453         default:
   454             break;
   455         }
   456         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
   457         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
   458         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
   459         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
   460     }
   461 
   462     axis = (int)*(Uint16*)(&data[0]) - 0x8000;
   463     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   464     axis = (int)*(Uint16*)(&data[2]) - 0x8000;
   465     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   466     axis = (int)*(Uint16*)(&data[4]) - 0x8000;
   467     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   468     axis = (int)*(Uint16*)(&data[6]) - 0x8000;
   469     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   470 
   471 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
   472     if (ctx->gamepad_statics && !ctx->gamepad) {
   473         Uint8 buttons = 0;
   474 
   475         if (data[10] & 0x01) {
   476             buttons |= (1 << SDL_CONTROLLER_BUTTON_A);
   477         }
   478         if (data[10] & 0x02) {
   479             buttons |= (1 << SDL_CONTROLLER_BUTTON_B);
   480         }
   481         if (data[10] & 0x04) {
   482             buttons |= (1 << SDL_CONTROLLER_BUTTON_X);
   483         }
   484         if (data[10] & 0x08) {
   485             buttons |= (1 << SDL_CONTROLLER_BUTTON_Y);
   486         }
   487         if (buttons != 0) {
   488             HIDAPI_DriverXbox360_GuessGamepad(ctx, buttons);
   489         }
   490     }
   491 
   492     if (ctx->gamepad) {
   493         HRESULT hr;
   494         struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
   495         
   496         hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(ctx->gamepad, &state);
   497         if (SUCCEEDED(hr)) {
   498             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (state.Buttons & 0x40000000) ? SDL_PRESSED : SDL_RELEASED);
   499             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)(state.LeftTrigger * SDL_MAX_UINT16)) - 32768);
   500             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)(state.RightTrigger * SDL_MAX_UINT16)) - 32768);
   501             has_trigger_data = SDL_TRUE;
   502         }
   503     }
   504 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
   505 
   506 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
   507     if (ctx->xinput_enabled) {
   508         if (ctx->xinput_slot == XUSER_INDEX_ANY && HIDAPI_DriverXbox360_MissingXInputSlot()) {
   509             WORD wButtons = 0;
   510 
   511             if (data[10] & 0x01) {
   512                 wButtons |= XINPUT_GAMEPAD_A;
   513             }
   514             if (data[10] & 0x02) {
   515                 wButtons |= XINPUT_GAMEPAD_B;
   516             }
   517             if (data[10] & 0x04) {
   518                 wButtons |= XINPUT_GAMEPAD_X;
   519             }
   520             if (data[10] & 0x08) {
   521                 wButtons |= XINPUT_GAMEPAD_Y;
   522             }
   523             if (wButtons != 0) {
   524                 Uint8 xinput_slot = HIDAPI_DriverXbox360_GuessXInputSlot(wButtons);
   525                 if (xinput_slot != XUSER_INDEX_ANY) {
   526                     HIDAPI_DriverXbox360_MarkXInputSlotUsed(xinput_slot);
   527                     ctx->xinput_slot = xinput_slot;
   528                 }
   529             }
   530         }
   531 
   532         if (!has_trigger_data && ctx->xinput_slot != XUSER_INDEX_ANY) {
   533             XINPUT_STATE_EX xinput_state;
   534 
   535             if (XINPUTGETSTATE(ctx->xinput_slot, &xinput_state) == ERROR_SUCCESS) {
   536                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (xinput_state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE) ? SDL_PRESSED : SDL_RELEASED);
   537                 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)xinput_state.Gamepad.bLeftTrigger * 257) - 32768);
   538                 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)xinput_state.Gamepad.bRightTrigger * 257) - 32768);
   539                 has_trigger_data = SDL_TRUE;
   540             }
   541         }
   542     }
   543 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
   544 
   545     if (!has_trigger_data) {
   546         axis = (data[9] * 257) - 32768;
   547         if (data[9] < 0x80) {
   548             axis = -axis * 2 - 32769;
   549             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   550         } else if (data[9] > 0x80) {
   551             axis = axis * 2 - 32767;
   552             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   553         } else {
   554             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_MIN_SINT16);
   555             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, SDL_MIN_SINT16);
   556         }
   557     }
   558 
   559     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   560 }
   561 #else
   562 
   563 static void
   564 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
   565 {
   566     Sint16 axis;
   567 #ifdef __MACOSX__
   568     const SDL_bool invert_y_axes = SDL_FALSE;
   569 #else
   570     const SDL_bool invert_y_axes = SDL_TRUE;
   571 #endif
   572 
   573     if (ctx->last_state[2] != data[2]) {
   574         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   575         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   576         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[2] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   577         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[2] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   578         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[2] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   579         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[2] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   580         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[2] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   581         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[2] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   582     }
   583 
   584     if (ctx->last_state[3] != data[3]) {
   585         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[3] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   586         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[3] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   587         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[3] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   588         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[3] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   589         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[3] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   590         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[3] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   591         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[3] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   592     }
   593 
   594     axis = ((int)data[4] * 257) - 32768;
   595     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   596     axis = ((int)data[5] * 257) - 32768;
   597     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   598     axis = *(Sint16*)(&data[6]);
   599     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   600     axis = *(Sint16*)(&data[8]);
   601     if (invert_y_axes) {
   602         axis = ~axis;
   603     }
   604     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   605     axis = *(Sint16*)(&data[10]);
   606     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   607     axis = *(Sint16*)(&data[12]);
   608     if (invert_y_axes) {
   609         axis = ~axis;
   610     }
   611     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   612 
   613     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   614 }
   615 #endif /* __WIN32__ */
   616 
   617 #ifdef __MACOSX__
   618 static void
   619 HIDAPI_DriverXboxOneS_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
   620 {
   621     Sint16 axis;
   622 
   623     if (ctx->last_state[14] != data[14]) {
   624         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[14] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   625         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[14] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   626         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[14] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   627         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[14] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   628         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[14] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   629         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[14] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   630     }
   631 
   632     if (ctx->last_state[15] != data[15]) {
   633         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[15] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   634         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[15] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   635         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[15] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   636     }
   637 
   638     if (ctx->last_state[16] != data[16]) {
   639         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   640     }
   641 
   642     if (ctx->last_state[13] != data[13]) {
   643         SDL_bool dpad_up = SDL_FALSE;
   644         SDL_bool dpad_down = SDL_FALSE;
   645         SDL_bool dpad_left = SDL_FALSE;
   646         SDL_bool dpad_right = SDL_FALSE;
   647 
   648         switch (data[13]) {
   649         case 1:
   650             dpad_up = SDL_TRUE;
   651             break;
   652         case 2:
   653             dpad_up = SDL_TRUE;
   654             dpad_right = SDL_TRUE;
   655             break;
   656         case 3:
   657             dpad_right = SDL_TRUE;
   658             break;
   659         case 4:
   660             dpad_right = SDL_TRUE;
   661             dpad_down = SDL_TRUE;
   662             break;
   663         case 5:
   664             dpad_down = SDL_TRUE;
   665             break;
   666         case 6:
   667             dpad_left = SDL_TRUE;
   668             dpad_down = SDL_TRUE;
   669             break;
   670         case 7:
   671             dpad_left = SDL_TRUE;
   672             break;
   673         case 8:
   674             dpad_up = SDL_TRUE;
   675             dpad_left = SDL_TRUE;
   676             break;
   677         default:
   678             break;
   679         }
   680         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
   681         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
   682         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
   683         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
   684     }
   685 
   686     axis = (int)*(Uint16*)(&data[1]) - 0x8000;
   687     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   688     axis = (int)*(Uint16*)(&data[3]) - 0x8000;
   689     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   690     axis = (int)*(Uint16*)(&data[5]) - 0x8000;
   691     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   692     axis = (int)*(Uint16*)(&data[7]) - 0x8000;
   693     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   694 
   695     axis = ((int)*(Sint16*)(&data[9]) * 64) - 32768;
   696     if (axis == 32704) {
   697         axis = 32767;
   698     }
   699     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   700 
   701     axis = ((int)*(Sint16*)(&data[11]) * 64) - 32768;
   702     if (axis == 32704) {
   703         axis = 32767;
   704     }
   705     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   706 
   707     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   708 }
   709 
   710 static void
   711 HIDAPI_DriverXboxOneS_HandleGuidePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
   712 {
   713     SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   714 }
   715 #endif /* __MACOSX__ */
   716 
   717 static SDL_bool
   718 HIDAPI_DriverXbox360_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
   719 {
   720     SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
   721     Uint8 data[USB_PACKET_LENGTH];
   722     int size;
   723 
   724     while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
   725 #ifdef __WIN32__
   726         HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
   727 #else
   728         switch (data[0]) {
   729         case 0x00:
   730             HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
   731             break;
   732 #ifdef __MACOSX__
   733         case 0x01:
   734             HIDAPI_DriverXboxOneS_HandleStatePacket(joystick, dev, ctx, data, size);
   735             break;
   736         case 0x02:
   737             HIDAPI_DriverXboxOneS_HandleGuidePacket(joystick, dev, ctx, data, size);
   738             break;
   739 #endif
   740         default:
   741 #ifdef DEBUG_JOYSTICK
   742             SDL_Log("Unknown Xbox 360 packet, size = %d\n", size);
   743             SDL_Log("%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
   744                 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
   745                 data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16]);
   746 #endif
   747             break;
   748         }
   749 #endif /* __WIN32__ */
   750     }
   751 
   752     if (ctx->rumble_expiration) {
   753         Uint32 now = SDL_GetTicks();
   754         if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
   755             HIDAPI_DriverXbox360_Rumble(joystick, dev, context, 0, 0, 0);
   756         }
   757     }
   758 
   759     return (size >= 0);
   760 }
   761 
   762 static void
   763 HIDAPI_DriverXbox360_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
   764 {
   765 #if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
   766     SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
   767 #endif
   768 
   769 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
   770     if (ctx->xinput_enabled) {
   771         HIDAPI_DriverXbox360_MarkXInputSlotFree(ctx->xinput_slot);
   772         WIN_UnloadXInputDLL();
   773     }
   774 #endif
   775 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
   776     HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
   777 #endif
   778     SDL_free(context);
   779 }
   780 
   781 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 =
   782 {
   783     SDL_HINT_JOYSTICK_HIDAPI_XBOX,
   784     SDL_TRUE,
   785     HIDAPI_DriverXbox360_IsSupportedDevice,
   786     HIDAPI_DriverXbox360_GetDeviceName,
   787     HIDAPI_DriverXbox360_Init,
   788     HIDAPI_DriverXbox360_Rumble,
   789     HIDAPI_DriverXbox360_Update,
   790     HIDAPI_DriverXbox360_Quit
   791 };
   792 
   793 #endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
   794 
   795 #endif /* SDL_JOYSTICK_HIDAPI */
   796 
   797 /* vi: set ts=4 sw=4 expandtab: */