src/joystick/hidapi/SDL_hidapi_xbox360.c
author Ethan Lee <flibitijibibo@flibitijibibo.com>
Tue, 12 Mar 2019 20:27:54 -0400
changeset 12641 64597a7e8771
parent 12503 806492103856
child 12769 096f2f3c4bdc
permissions -rw-r--r--
hidapi: Add support for Wii U/Switch USB GameCube controller adapter.

Note that a single USB device is responsible for all 4 joysticks, so a large
rewrite of the DeviceDriver functions was necessary to allow a single device to
produce multiple joysticks.
     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     SDL_JoystickID joystickID;
    58     Uint8 last_state[USB_PACKET_LENGTH];
    59     Uint32 rumble_expiration;
    60 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
    61     SDL_bool xinput_enabled;
    62     Uint8 xinput_slot;
    63 #endif
    64 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
    65     SDL_bool coinitialized;
    66     __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics;
    67     __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
    68     struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
    69 #endif
    70 } SDL_DriverXbox360_Context;
    71 
    72 
    73 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
    74 static Uint8 xinput_slots;
    75 
    76 static void
    77 HIDAPI_DriverXbox360_MarkXInputSlotUsed(Uint8 xinput_slot)
    78 {
    79     if (xinput_slot != XUSER_INDEX_ANY) {
    80         xinput_slots |= (0x01 << xinput_slot);
    81     }
    82 }
    83 
    84 static void
    85 HIDAPI_DriverXbox360_MarkXInputSlotFree(Uint8 xinput_slot)
    86 {
    87     if (xinput_slot != XUSER_INDEX_ANY) {
    88         xinput_slots &= ~(0x01 << xinput_slot);
    89     }
    90 }
    91 
    92 static SDL_bool
    93 HIDAPI_DriverXbox360_MissingXInputSlot()
    94 {
    95     return xinput_slots != 0x0F;
    96 }
    97 
    98 static Uint8
    99 HIDAPI_DriverXbox360_GuessXInputSlot(WORD wButtons)
   100 {
   101     DWORD user_index;
   102     int match_count;
   103     Uint8 match_slot;
   104 
   105     if (!XINPUTGETSTATE) {
   106         return XUSER_INDEX_ANY;
   107     }
   108 
   109     match_count = 0;
   110     for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) {
   111         XINPUT_STATE_EX xinput_state;
   112 
   113         if (XINPUTGETSTATE(user_index, &xinput_state) == ERROR_SUCCESS) {
   114             if (xinput_state.Gamepad.wButtons == wButtons) {
   115                 ++match_count;
   116                 match_slot = (Uint8)user_index;
   117             }
   118         }
   119     }
   120     if (match_count == 1) {
   121         return match_slot;
   122     }
   123     return XUSER_INDEX_ANY;
   124 }
   125 
   126 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
   127 
   128 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
   129 
   130 static void
   131 HIDAPI_DriverXbox360_InitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
   132 {
   133     /* I think this takes care of RoInitialize() in a way that is compatible with the rest of SDL */
   134     if (FAILED(WIN_CoInitialize())) {
   135         return;
   136     }
   137     ctx->coinitialized = SDL_TRUE;
   138 
   139     {
   140         static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } };
   141         HRESULT hr;
   142         HMODULE hModule = LoadLibraryA("combase.dll");
   143         if (hModule != NULL) {
   144             typedef HRESULT (WINAPI *WindowsCreateString_t)(PCNZWCH sourceString, UINT32 length, HSTRING* string);
   145             typedef HRESULT (WINAPI *WindowsDeleteString_t)(HSTRING string);
   146             typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory);
   147 
   148             WindowsCreateString_t WindowsCreateStringFunc = (WindowsCreateString_t)GetProcAddress(hModule, "WindowsCreateString");
   149             WindowsDeleteString_t WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule, "WindowsDeleteString");
   150             RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory");
   151             if (WindowsCreateStringFunc && WindowsDeleteStringFunc && RoGetActivationFactoryFunc) {
   152                 LPTSTR pNamespace = L"Windows.Gaming.Input.Gamepad";
   153                 HSTRING hNamespaceString;
   154 
   155                 hr = WindowsCreateStringFunc(pNamespace, SDL_wcslen(pNamespace), &hNamespaceString);
   156                 if (SUCCEEDED(hr)) {
   157                     RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, &ctx->gamepad_statics);
   158                     WindowsDeleteStringFunc(hNamespaceString);
   159                 }
   160             }
   161             FreeLibrary(hModule);
   162         }
   163     }
   164 }
   165 
   166 static Uint8
   167 HIDAPI_DriverXbox360_GetGamepadButtonsForMatch(__x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad)
   168 {
   169     HRESULT hr;
   170     struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
   171     Uint8 buttons = 0;
   172 
   173     hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(gamepad, &state);
   174     if (SUCCEEDED(hr)) {
   175         if (state.Buttons & GamepadButtons_A) {
   176             buttons |= (1 << SDL_CONTROLLER_BUTTON_A);
   177         }
   178         if (state.Buttons & GamepadButtons_B) {
   179             buttons |= (1 << SDL_CONTROLLER_BUTTON_B);
   180         }
   181         if (state.Buttons & GamepadButtons_X) {
   182             buttons |= (1 << SDL_CONTROLLER_BUTTON_X);
   183         }
   184         if (state.Buttons & GamepadButtons_Y) {
   185             buttons |= (1 << SDL_CONTROLLER_BUTTON_Y);
   186         }
   187     }
   188     return buttons;
   189 }
   190 
   191 static void
   192 HIDAPI_DriverXbox360_GuessGamepad(SDL_DriverXbox360_Context *ctx, Uint8 buttons)
   193 {
   194     HRESULT hr;
   195     __FIVectorView_1_Windows__CGaming__CInput__CGamepad *gamepads;
   196 
   197     hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_get_Gamepads(ctx->gamepad_statics, &gamepads);
   198     if (SUCCEEDED(hr)) {
   199         unsigned int i, num_gamepads;
   200 
   201         hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_get_Size(gamepads, &num_gamepads);
   202         if (SUCCEEDED(hr)) {
   203             int match_count;
   204             unsigned int match_slot;
   205 
   206             match_count = 0;
   207             for (i = 0; i < num_gamepads; ++i) {
   208                 __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
   209 
   210                 hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, i, &gamepad);
   211                 if (SUCCEEDED(hr)) {
   212                     Uint8 gamepad_buttons = HIDAPI_DriverXbox360_GetGamepadButtonsForMatch(gamepad);
   213                     if (buttons == gamepad_buttons) {
   214                         ++match_count;
   215                         match_slot = i;
   216                     }
   217                     __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
   218                 }
   219             }
   220             if (match_count == 1) {
   221                 hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, match_slot, &ctx->gamepad);
   222                 if (SUCCEEDED(hr)) {
   223                 }
   224             }
   225         }
   226         __FIVectorView_1_Windows__CGaming__CInput__CGamepad_Release(gamepads);
   227     }
   228 }
   229 
   230 static void
   231 HIDAPI_DriverXbox360_QuitWindowsGamingInput(SDL_DriverXbox360_Context *ctx)
   232 {
   233     if (ctx->gamepad_statics) {
   234         __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(ctx->gamepad_statics);
   235         ctx->gamepad_statics = NULL;
   236     }
   237     if (ctx->gamepad) {
   238         __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(ctx->gamepad);
   239         ctx->gamepad = NULL;
   240     }
   241 
   242     if (ctx->coinitialized) {
   243         WIN_CoUninitialize();
   244         ctx->coinitialized = SDL_FALSE;
   245     }
   246 }
   247 
   248 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
   249 
   250 static SDL_bool
   251 HIDAPI_DriverXbox360_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number)
   252 {
   253 #if defined(__MACOSX__) || defined(__WIN32__)
   254     if (vendor_id == 0x045e && product_id == 0x028e && version == 1) {
   255         /* This is the Steam Virtual Gamepad, which isn't supported by this driver */
   256         return SDL_FALSE;
   257     }
   258     return SDL_IsJoystickXbox360(vendor_id, product_id) || SDL_IsJoystickXboxOne(vendor_id, product_id);
   259 #else
   260     return SDL_IsJoystickXbox360(vendor_id, product_id);
   261 #endif
   262 }
   263 
   264 static const char *
   265 HIDAPI_DriverXbox360_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
   266 {
   267     return HIDAPI_XboxControllerName(vendor_id, product_id);
   268 }
   269 
   270 static SDL_bool SetSlotLED(hid_device *dev, Uint8 slot)
   271 {
   272     const Uint8 led_packet[] = { 0x01, 0x03, (2 + slot) };
   273 
   274     if (hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
   275         return SDL_FALSE;
   276     }
   277     return SDL_TRUE;
   278 }
   279 
   280 static SDL_bool
   281 HIDAPI_DriverXbox360_InitDriver(SDL_HIDAPI_DriverData *context, Uint16 vendor_id, Uint16 product_id, int *num_joysticks)
   282 {
   283     SDL_DriverXbox360_Context *ctx;
   284 
   285     ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
   286     if (!ctx) {
   287         SDL_OutOfMemory();
   288         return SDL_FALSE;
   289     }
   290 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
   291     ctx->xinput_enabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE);
   292     if (ctx->xinput_enabled && WIN_LoadXInputDLL() < 0) {
   293         ctx->xinput_enabled = SDL_FALSE;
   294     }
   295     ctx->xinput_slot = XUSER_INDEX_ANY;
   296 #endif
   297 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
   298     HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
   299 #endif
   300     context->context = ctx;
   301 
   302     ctx->joystickID = SDL_GetNextJoystickInstanceID();
   303     *num_joysticks += 1;
   304     SDL_PrivateJoystickAdded(ctx->joystickID);
   305 
   306     return SDL_TRUE;
   307 }
   308 
   309 static SDL_bool
   310 HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick)
   311 {
   312     /* Set the controller LED */
   313     SetSlotLED(context->device, (joystick->instance_id % 4));
   314 
   315     /* Initialize the joystick capabilities */
   316     joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
   317     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
   318     joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
   319 
   320     return SDL_TRUE;
   321 }
   322 
   323 static int
   324 HIDAPI_DriverXbox360_NumJoysticks(SDL_HIDAPI_DriverData *context)
   325 {
   326     return 1;
   327 }
   328 
   329 static SDL_JoystickID
   330 HIDAPI_DriverXbox360_InstanceIDForIndex(SDL_HIDAPI_DriverData *context, int index)
   331 {
   332     SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context->context;
   333     return ctx->joystickID;
   334 }
   335 
   336 static int
   337 HIDAPI_DriverXbox360_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   338 {
   339     SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context->context;
   340 
   341 #ifdef __WIN32__
   342     SDL_bool rumbled = SDL_FALSE;
   343 
   344 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
   345     if (!rumbled && ctx->gamepad) {
   346         HRESULT hr;
   347 
   348         ctx->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
   349         ctx->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
   350         hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(ctx->gamepad, ctx->vibration);
   351         if (SUCCEEDED(hr)) {
   352             rumbled = SDL_TRUE;
   353         }
   354     }
   355 #endif
   356 
   357 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
   358     if (!rumbled && ctx->xinput_slot != XUSER_INDEX_ANY) {
   359         XINPUT_VIBRATION XVibration;
   360 
   361         if (!XINPUTSETSTATE) {
   362             return SDL_Unsupported();
   363         }
   364 
   365         XVibration.wLeftMotorSpeed = low_frequency_rumble;
   366         XVibration.wRightMotorSpeed = high_frequency_rumble;
   367         if (XINPUTSETSTATE(ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) {
   368             rumbled = SDL_TRUE;
   369         } else {
   370             return SDL_SetError("XInputSetState() failed");
   371         }
   372     }
   373 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
   374 
   375 #else /* !__WIN32__ */
   376 
   377 #ifdef __MACOSX__
   378     /* On Mac OS X the 360Controller driver uses this short report,
   379        and we need to prefix it with a magic token so hidapi passes it through untouched
   380      */
   381     Uint8 rumble_packet[] = { 'M', 'A', 'G', 'I', 'C', '0', 0x00, 0x04, 0x00, 0x00 };
   382 
   383     rumble_packet[6+2] = (low_frequency_rumble >> 8);
   384     rumble_packet[6+3] = (high_frequency_rumble >> 8);
   385 #else
   386     Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
   387 
   388     rumble_packet[3] = (low_frequency_rumble >> 8);
   389     rumble_packet[4] = (high_frequency_rumble >> 8);
   390 #endif
   391 
   392     if (hid_write(context->device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   393         return SDL_SetError("Couldn't send rumble packet");
   394     }
   395 #endif /* __WIN32__ */
   396 
   397     if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
   398         ctx->rumble_expiration = SDL_GetTicks() + duration_ms;
   399     } else {
   400         ctx->rumble_expiration = 0;
   401     }
   402     return 0;
   403 }
   404 
   405 #ifdef __WIN32__
   406  /* This is the packet format for Xbox 360 and Xbox One controllers on Windows,
   407     however with this interface there is no rumble support, no guide button,
   408     and the left and right triggers are tied together as a single axis.
   409 
   410     We use XInput and Windows.Gaming.Input to make up for these shortcomings.
   411   */
   412 static void
   413 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
   414 {
   415     Sint16 axis;
   416     SDL_bool has_trigger_data = SDL_FALSE;
   417 
   418     if (ctx->last_state[10] != data[10]) {
   419         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[10] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   420         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[10] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   421         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[10] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   422         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[10] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   423         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[10] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   424         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[10] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   425         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[10] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   426         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[10] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   427     }
   428 
   429     if (ctx->last_state[11] != data[11]) {
   430         SDL_bool dpad_up = SDL_FALSE;
   431         SDL_bool dpad_down = SDL_FALSE;
   432         SDL_bool dpad_left = SDL_FALSE;
   433         SDL_bool dpad_right = SDL_FALSE;
   434 
   435         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[11] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   436         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[11] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   437 
   438         switch (data[11] & 0x3C) {
   439         case 4:
   440             dpad_up = SDL_TRUE;
   441             break;
   442         case 8:
   443             dpad_up = SDL_TRUE;
   444             dpad_right = SDL_TRUE;
   445             break;
   446         case 12:
   447             dpad_right = SDL_TRUE;
   448             break;
   449         case 16:
   450             dpad_right = SDL_TRUE;
   451             dpad_down = SDL_TRUE;
   452             break;
   453         case 20:
   454             dpad_down = SDL_TRUE;
   455             break;
   456         case 24:
   457             dpad_left = SDL_TRUE;
   458             dpad_down = SDL_TRUE;
   459             break;
   460         case 28:
   461             dpad_left = SDL_TRUE;
   462             break;
   463         case 32:
   464             dpad_up = SDL_TRUE;
   465             dpad_left = SDL_TRUE;
   466             break;
   467         default:
   468             break;
   469         }
   470         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
   471         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
   472         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
   473         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
   474     }
   475 
   476     axis = (int)*(Uint16*)(&data[0]) - 0x8000;
   477     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   478     axis = (int)*(Uint16*)(&data[2]) - 0x8000;
   479     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   480     axis = (int)*(Uint16*)(&data[4]) - 0x8000;
   481     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   482     axis = (int)*(Uint16*)(&data[6]) - 0x8000;
   483     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   484 
   485 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
   486     if (ctx->gamepad_statics && !ctx->gamepad) {
   487         Uint8 buttons = 0;
   488 
   489         if (data[10] & 0x01) {
   490             buttons |= (1 << SDL_CONTROLLER_BUTTON_A);
   491         }
   492         if (data[10] & 0x02) {
   493             buttons |= (1 << SDL_CONTROLLER_BUTTON_B);
   494         }
   495         if (data[10] & 0x04) {
   496             buttons |= (1 << SDL_CONTROLLER_BUTTON_X);
   497         }
   498         if (data[10] & 0x08) {
   499             buttons |= (1 << SDL_CONTROLLER_BUTTON_Y);
   500         }
   501         if (buttons != 0) {
   502             HIDAPI_DriverXbox360_GuessGamepad(ctx, buttons);
   503         }
   504     }
   505 
   506     if (ctx->gamepad) {
   507         HRESULT hr;
   508         struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
   509         
   510         hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(ctx->gamepad, &state);
   511         if (SUCCEEDED(hr)) {
   512             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (state.Buttons & 0x40000000) ? SDL_PRESSED : SDL_RELEASED);
   513             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)(state.LeftTrigger * SDL_MAX_UINT16)) - 32768);
   514             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)(state.RightTrigger * SDL_MAX_UINT16)) - 32768);
   515             has_trigger_data = SDL_TRUE;
   516         }
   517     }
   518 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT */
   519 
   520 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
   521     if (ctx->xinput_enabled) {
   522         if (ctx->xinput_slot == XUSER_INDEX_ANY && HIDAPI_DriverXbox360_MissingXInputSlot()) {
   523             WORD wButtons = 0;
   524 
   525             if (data[10] & 0x01) {
   526                 wButtons |= XINPUT_GAMEPAD_A;
   527             }
   528             if (data[10] & 0x02) {
   529                 wButtons |= XINPUT_GAMEPAD_B;
   530             }
   531             if (data[10] & 0x04) {
   532                 wButtons |= XINPUT_GAMEPAD_X;
   533             }
   534             if (data[10] & 0x08) {
   535                 wButtons |= XINPUT_GAMEPAD_Y;
   536             }
   537             if (wButtons != 0) {
   538                 Uint8 xinput_slot = HIDAPI_DriverXbox360_GuessXInputSlot(wButtons);
   539                 if (xinput_slot != XUSER_INDEX_ANY) {
   540                     HIDAPI_DriverXbox360_MarkXInputSlotUsed(xinput_slot);
   541                     ctx->xinput_slot = xinput_slot;
   542                 }
   543             }
   544         }
   545 
   546         if (!has_trigger_data && ctx->xinput_slot != XUSER_INDEX_ANY) {
   547             XINPUT_STATE_EX xinput_state;
   548 
   549             if (XINPUTGETSTATE(ctx->xinput_slot, &xinput_state) == ERROR_SUCCESS) {
   550                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (xinput_state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE) ? SDL_PRESSED : SDL_RELEASED);
   551                 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)xinput_state.Gamepad.bLeftTrigger * 257) - 32768);
   552                 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)xinput_state.Gamepad.bRightTrigger * 257) - 32768);
   553                 has_trigger_data = SDL_TRUE;
   554             }
   555         }
   556     }
   557 #endif /* SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT */
   558 
   559     if (!has_trigger_data) {
   560         axis = (data[9] * 257) - 32768;
   561         if (data[9] < 0x80) {
   562             axis = -axis * 2 - 32769;
   563             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   564         } else if (data[9] > 0x80) {
   565             axis = axis * 2 - 32767;
   566             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   567         } else {
   568             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_MIN_SINT16);
   569             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, SDL_MIN_SINT16);
   570         }
   571     }
   572 
   573     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   574 }
   575 #else
   576 
   577 static void
   578 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
   579 {
   580     Sint16 axis;
   581 #ifdef __MACOSX__
   582     const SDL_bool invert_y_axes = SDL_FALSE;
   583 #else
   584     const SDL_bool invert_y_axes = SDL_TRUE;
   585 #endif
   586 
   587     if (ctx->last_state[2] != data[2]) {
   588         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   589         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   590         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[2] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   591         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[2] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   592         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[2] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   593         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[2] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   594         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[2] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   595         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[2] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   596     }
   597 
   598     if (ctx->last_state[3] != data[3]) {
   599         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[3] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   600         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[3] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   601         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[3] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   602         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[3] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   603         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[3] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   604         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[3] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   605         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[3] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   606     }
   607 
   608     axis = ((int)data[4] * 257) - 32768;
   609     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   610     axis = ((int)data[5] * 257) - 32768;
   611     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   612     axis = *(Sint16*)(&data[6]);
   613     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   614     axis = *(Sint16*)(&data[8]);
   615     if (invert_y_axes) {
   616         axis = ~axis;
   617     }
   618     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   619     axis = *(Sint16*)(&data[10]);
   620     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   621     axis = *(Sint16*)(&data[12]);
   622     if (invert_y_axes) {
   623         axis = ~axis;
   624     }
   625     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   626 
   627     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   628 }
   629 #endif /* __WIN32__ */
   630 
   631 #ifdef __MACOSX__
   632 static void
   633 HIDAPI_DriverXboxOneS_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
   634 {
   635     Sint16 axis;
   636 
   637     if (ctx->last_state[14] != data[14]) {
   638         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[14] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   639         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[14] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   640         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[14] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   641         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[14] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   642         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[14] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   643         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[14] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   644     }
   645 
   646     if (ctx->last_state[15] != data[15]) {
   647         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[15] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   648         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[15] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   649         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[15] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   650     }
   651 
   652     if (ctx->last_state[16] != data[16]) {
   653         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   654     }
   655 
   656     if (ctx->last_state[13] != data[13]) {
   657         SDL_bool dpad_up = SDL_FALSE;
   658         SDL_bool dpad_down = SDL_FALSE;
   659         SDL_bool dpad_left = SDL_FALSE;
   660         SDL_bool dpad_right = SDL_FALSE;
   661 
   662         switch (data[13]) {
   663         case 1:
   664             dpad_up = SDL_TRUE;
   665             break;
   666         case 2:
   667             dpad_up = SDL_TRUE;
   668             dpad_right = SDL_TRUE;
   669             break;
   670         case 3:
   671             dpad_right = SDL_TRUE;
   672             break;
   673         case 4:
   674             dpad_right = SDL_TRUE;
   675             dpad_down = SDL_TRUE;
   676             break;
   677         case 5:
   678             dpad_down = SDL_TRUE;
   679             break;
   680         case 6:
   681             dpad_left = SDL_TRUE;
   682             dpad_down = SDL_TRUE;
   683             break;
   684         case 7:
   685             dpad_left = SDL_TRUE;
   686             break;
   687         case 8:
   688             dpad_up = SDL_TRUE;
   689             dpad_left = SDL_TRUE;
   690             break;
   691         default:
   692             break;
   693         }
   694         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
   695         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
   696         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
   697         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
   698     }
   699 
   700     axis = (int)*(Uint16*)(&data[1]) - 0x8000;
   701     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   702     axis = (int)*(Uint16*)(&data[3]) - 0x8000;
   703     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   704     axis = (int)*(Uint16*)(&data[5]) - 0x8000;
   705     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   706     axis = (int)*(Uint16*)(&data[7]) - 0x8000;
   707     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   708 
   709     axis = ((int)*(Sint16*)(&data[9]) * 64) - 32768;
   710     if (axis == 32704) {
   711         axis = 32767;
   712     }
   713     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   714 
   715     axis = ((int)*(Sint16*)(&data[11]) * 64) - 32768;
   716     if (axis == 32704) {
   717         axis = 32767;
   718     }
   719     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   720 
   721     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   722 }
   723 
   724 static void
   725 HIDAPI_DriverXboxOneS_HandleGuidePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
   726 {
   727     SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   728 }
   729 #endif /* __MACOSX__ */
   730 
   731 static SDL_bool
   732 HIDAPI_DriverXbox360_UpdateDriver(SDL_HIDAPI_DriverData *context, int *num_joysticks)
   733 {
   734     SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context->context;
   735     SDL_Joystick *joystick = SDL_JoystickFromInstanceID(ctx->joystickID);
   736     Uint8 data[USB_PACKET_LENGTH];
   737     int size;
   738 
   739     if (joystick == NULL) {
   740         return SDL_TRUE; /* Nothing to do right now! */
   741     }
   742 
   743     while ((size = hid_read_timeout(context->device, data, sizeof(data), 0)) > 0) {
   744 #ifdef __WIN32__
   745         HIDAPI_DriverXbox360_HandleStatePacket(joystick, context->device, ctx, data, size);
   746 #else
   747         switch (data[0]) {
   748         case 0x00:
   749             HIDAPI_DriverXbox360_HandleStatePacket(joystick, context->device, ctx, data, size);
   750             break;
   751 #ifdef __MACOSX__
   752         case 0x01:
   753             HIDAPI_DriverXboxOneS_HandleStatePacket(joystick, context->device, ctx, data, size);
   754             break;
   755         case 0x02:
   756             HIDAPI_DriverXboxOneS_HandleGuidePacket(joystick, context->device, ctx, data, size);
   757             break;
   758 #endif
   759         default:
   760 #ifdef DEBUG_JOYSTICK
   761             SDL_Log("Unknown Xbox 360 packet, size = %d\n", size);
   762             SDL_Log("%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
   763                 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
   764                 data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16]);
   765 #endif
   766             break;
   767         }
   768 #endif /* __WIN32__ */
   769     }
   770 
   771     if (ctx->rumble_expiration) {
   772         Uint32 now = SDL_GetTicks();
   773         if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
   774             HIDAPI_DriverXbox360_Rumble(context, joystick, 0, 0, 0);
   775         }
   776     }
   777 
   778     return (size >= 0);
   779 }
   780 
   781 static void
   782 HIDAPI_DriverXbox360_QuitDriver(SDL_HIDAPI_DriverData *context, SDL_bool send_event, int *num_joysticks)
   783 {
   784     SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context->context;
   785 
   786 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
   787     if (ctx->xinput_enabled) {
   788         HIDAPI_DriverXbox360_MarkXInputSlotFree(ctx->xinput_slot);
   789         WIN_UnloadXInputDLL();
   790     }
   791 #endif
   792 #ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
   793     HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
   794 #endif
   795     *num_joysticks -= 1;
   796     if (send_event) {
   797         SDL_PrivateJoystickRemoved(ctx->joystickID);
   798     }
   799     SDL_free(context->context);
   800 }
   801 
   802 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 =
   803 {
   804     SDL_HINT_JOYSTICK_HIDAPI_XBOX,
   805     SDL_TRUE,
   806     HIDAPI_DriverXbox360_IsSupportedDevice,
   807     HIDAPI_DriverXbox360_GetDeviceName,
   808     HIDAPI_DriverXbox360_InitDriver,
   809     HIDAPI_DriverXbox360_QuitDriver,
   810     HIDAPI_DriverXbox360_UpdateDriver,
   811     HIDAPI_DriverXbox360_NumJoysticks,
   812     HIDAPI_DriverXbox360_InstanceIDForIndex,
   813     HIDAPI_DriverXbox360_OpenJoystick,
   814     HIDAPI_DriverXbox360_Rumble
   815 };
   816 
   817 #endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
   818 
   819 #endif /* SDL_JOYSTICK_HIDAPI */
   820 
   821 /* vi: set ts=4 sw=4 expandtab: */