src/joystick/hidapi/SDL_hidapi_xbox360.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 16 Feb 2020 00:08:36 -0800
changeset 13532 fab2cd7dee5b
parent 13481 2f70560af6d4
permissions -rw-r--r--
Further improvements for bug 4128 - CMAKE: Generated target import file contains incorrect include path

Mohamed

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