src/joystick/hidapi/SDL_hidapi_xbox360.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 29 Aug 2018 18:56:54 -0700
changeset 12161 12a877a0ccb5
parent 12119 648377d0e573
child 12168 a5459597367f
permissions -rw-r--r--
Fixed Xbox One S Bluetooth support on Mac OS X
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #ifdef SDL_JOYSTICK_HIDAPI
    24 
    25 #include "SDL_hints.h"
    26 #include "SDL_log.h"
    27 #include "SDL_events.h"
    28 #include "SDL_timer.h"
    29 #include "SDL_joystick.h"
    30 #include "SDL_gamecontroller.h"
    31 #include "../SDL_sysjoystick.h"
    32 #include "SDL_hidapijoystick_c.h"
    33 
    34 
    35 #ifdef SDL_JOYSTICK_HIDAPI_XBOX360
    36 
    37 #ifdef __WIN32__
    38 #include "../../core/windows/SDL_xinput.h"
    39 #endif
    40 
    41 #define USB_PACKET_LENGTH   64
    42 
    43 
    44 typedef struct {
    45     Uint8 last_state[USB_PACKET_LENGTH];
    46     Uint32 rumble_expiration;
    47 #ifdef __WIN32__
    48     SDL_bool xinput_enabled;
    49     Uint8 xinput_slot;
    50 #endif
    51 } SDL_DriverXbox360_Context;
    52 
    53 
    54 #ifdef __WIN32__
    55 static Uint8 xinput_slots;
    56 
    57 static void
    58 HIDAPI_DriverXbox360_MarkXInputSlotUsed(Uint8 xinput_slot)
    59 {
    60     if (xinput_slot != XUSER_INDEX_ANY) {
    61         xinput_slots |= (0x01 << xinput_slot);
    62     }
    63 }
    64 
    65 static void
    66 HIDAPI_DriverXbox360_MarkXInputSlotFree(Uint8 xinput_slot)
    67 {
    68     if (xinput_slot != XUSER_INDEX_ANY) {
    69         xinput_slots &= ~(0x01 << xinput_slot);
    70     }
    71 }
    72 
    73 static SDL_bool
    74 HIDAPI_DriverXbox360_MissingXInputSlot()
    75 {
    76     return xinput_slots != 0x0F;
    77 }
    78 
    79 static Uint8
    80 HIDAPI_DriverXbox360_GuessXInputSlot(WORD wButtons)
    81 {
    82     DWORD user_index;
    83     int match_count;
    84     Uint8 match_slot;
    85 
    86     if (!XINPUTGETSTATE) {
    87         return XUSER_INDEX_ANY;
    88     }
    89 
    90     match_count = 0;
    91     for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) {
    92         XINPUT_STATE_EX xinput_state;
    93 
    94         if (XINPUTGETSTATE(user_index, &xinput_state) == ERROR_SUCCESS) {
    95             if (xinput_state.Gamepad.wButtons == wButtons) {
    96                 ++match_count;
    97                 match_slot = (Uint8)user_index;
    98             }
    99         }
   100     }
   101     if (match_count == 1) {
   102         return match_slot;
   103     }
   104     return XUSER_INDEX_ANY;
   105 }
   106 
   107 #endif /* __WIN32__ */
   108 
   109 static SDL_bool
   110 HIDAPI_DriverXbox360_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, Uint16 usage_page, Uint16 usage)
   111 {
   112 #if defined(__MACOSX__) || defined(__WIN32__)
   113     if (vendor_id == 0x045e && product_id == 0x028e && version == 1) {
   114         /* This is the Steam Virtual Gamepad, which isn't supported by this driver */
   115         return SDL_FALSE;
   116     }
   117     return SDL_IsJoystickXbox360(vendor_id, product_id) || SDL_IsJoystickXboxOne(vendor_id, product_id);
   118 #else
   119     return SDL_IsJoystickXbox360(vendor_id, product_id);
   120 #endif
   121 }
   122 
   123 static const char *
   124 HIDAPI_DriverXbox360_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
   125 {
   126     return HIDAPI_XboxControllerName(vendor_id, product_id);
   127 }
   128 
   129 static SDL_bool SetSlotLED(hid_device *dev, Uint8 slot)
   130 {
   131     const Uint8 led_packet[] = { 0x01, 0x03, (2 + slot) };
   132 
   133     if (hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
   134         return SDL_FALSE;
   135     }
   136     return SDL_TRUE;
   137 }
   138 
   139 static SDL_bool
   140 HIDAPI_DriverXbox360_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
   141 {
   142     SDL_DriverXbox360_Context *ctx;
   143 
   144     ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
   145     if (!ctx) {
   146         SDL_OutOfMemory();
   147         return SDL_FALSE;
   148     }
   149 #ifdef __WIN32__
   150     ctx->xinput_enabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE);
   151     if (ctx->xinput_enabled && WIN_LoadXInputDLL() < 0) {
   152         ctx->xinput_enabled = SDL_FALSE;
   153     }
   154     ctx->xinput_slot = XUSER_INDEX_ANY;
   155 #endif
   156     *context = ctx;
   157 
   158     /* Set the controller LED */
   159     SetSlotLED(dev, (joystick->instance_id % 4));
   160 
   161     /* Initialize the joystick capabilities */
   162     joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
   163     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
   164     joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
   165 
   166     return SDL_TRUE;
   167 }
   168 
   169 static int
   170 HIDAPI_DriverXbox360_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   171 {
   172     SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
   173 #ifdef __WIN32__
   174     if (ctx->xinput_slot != XUSER_INDEX_ANY) {
   175         XINPUT_VIBRATION XVibration;
   176 
   177         if (!XINPUTSETSTATE) {
   178             return SDL_Unsupported();
   179         }
   180 
   181         XVibration.wLeftMotorSpeed = low_frequency_rumble;
   182         XVibration.wRightMotorSpeed = high_frequency_rumble;
   183         if (XINPUTSETSTATE(ctx->xinput_slot, &XVibration) != ERROR_SUCCESS) {
   184             return SDL_SetError("XInputSetState() failed");
   185         }
   186     }
   187 #else
   188 #ifdef __MACOSX__
   189     /* On Mac OS X the 360Controller driver uses this short report,
   190        and we need to prefix it with a magic token so hidapi passes it through untouched
   191      */
   192     Uint8 rumble_packet[] = { 'M', 'A', 'G', 'I', 'C', '0', 0x00, 0x04, 0x00, 0x00 };
   193 
   194     rumble_packet[6+2] = (low_frequency_rumble >> 8);
   195     rumble_packet[6+3] = (high_frequency_rumble >> 8);
   196 #else
   197     Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
   198 
   199     rumble_packet[3] = (low_frequency_rumble >> 8);
   200     rumble_packet[4] = (high_frequency_rumble >> 8);
   201 #endif
   202 
   203     if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
   204         return SDL_SetError("Couldn't send rumble packet");
   205     }
   206 #endif /* __WIN32__ */
   207 
   208     if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
   209         ctx->rumble_expiration = SDL_GetTicks() + duration_ms;
   210     } else {
   211         ctx->rumble_expiration = 0;
   212     }
   213     return 0;
   214 }
   215 
   216 #ifdef __WIN32__
   217  /* This is the packet format for Xbox 360 and Xbox One controllers on Windows,
   218     however with this interface there is no rumble support, no guide button,
   219     and the left and right triggers are tied together as a single axis.
   220   */
   221 static void
   222 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
   223 {
   224     Sint16 axis;
   225 
   226     if (ctx->last_state[10] != data[10]) {
   227         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[10] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   228         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[10] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   229         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[10] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   230         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[10] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   231         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[10] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   232         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[10] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   233         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[10] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   234         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[10] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   235     }
   236 
   237     if (ctx->last_state[11] != data[11]) {
   238         SDL_bool dpad_up = SDL_FALSE;
   239         SDL_bool dpad_down = SDL_FALSE;
   240         SDL_bool dpad_left = SDL_FALSE;
   241         SDL_bool dpad_right = SDL_FALSE;
   242 
   243         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[11] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   244         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[11] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   245 
   246         switch (data[11] & 0x3C) {
   247         case 4:
   248             dpad_up = SDL_TRUE;
   249             break;
   250         case 8:
   251             dpad_up = SDL_TRUE;
   252             dpad_right = SDL_TRUE;
   253             break;
   254         case 12:
   255             dpad_right = SDL_TRUE;
   256             break;
   257         case 16:
   258             dpad_right = SDL_TRUE;
   259             dpad_down = SDL_TRUE;
   260             break;
   261         case 20:
   262             dpad_down = SDL_TRUE;
   263             break;
   264         case 24:
   265             dpad_left = SDL_TRUE;
   266             dpad_down = SDL_TRUE;
   267             break;
   268         case 28:
   269             dpad_left = SDL_TRUE;
   270             break;
   271         case 32:
   272             dpad_up = SDL_TRUE;
   273             dpad_left = SDL_TRUE;
   274             break;
   275         default:
   276             break;
   277         }
   278         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
   279         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
   280         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
   281         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
   282     }
   283 
   284     axis = (int)*(Uint16*)(&data[0]) - 0x8000;
   285     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   286     axis = (int)*(Uint16*)(&data[2]) - 0x8000;
   287     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   288     axis = (int)*(Uint16*)(&data[4]) - 0x8000;
   289     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   290     axis = (int)*(Uint16*)(&data[6]) - 0x8000;
   291     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   292 
   293     if (ctx->xinput_slot == XUSER_INDEX_ANY && HIDAPI_DriverXbox360_MissingXInputSlot()) {
   294         WORD wButtons = 0;
   295 
   296         if (data[10] & 0x01) {
   297             wButtons |= XINPUT_GAMEPAD_A;
   298         }
   299         if (data[10] & 0x02) {
   300             wButtons |= XINPUT_GAMEPAD_B;
   301         }
   302         if (data[10] & 0x04) {
   303             wButtons |= XINPUT_GAMEPAD_X;
   304         }
   305         if (data[10] & 0x08) {
   306             wButtons |= XINPUT_GAMEPAD_Y;
   307         }
   308         if (wButtons != 0) {
   309             Uint8 xinput_slot = HIDAPI_DriverXbox360_GuessXInputSlot(wButtons);
   310             if (xinput_slot != XUSER_INDEX_ANY) {
   311                 HIDAPI_DriverXbox360_MarkXInputSlotUsed(xinput_slot);
   312                 ctx->xinput_slot = xinput_slot;
   313             }
   314         }
   315     }
   316 
   317     if (ctx->xinput_slot == XUSER_INDEX_ANY) {
   318         axis = (data[9] * 257) - 32768;
   319         if (data[9] < 0x80) {
   320             axis = -axis * 2 - 32769;
   321             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   322         } else if (data[9] > 0x80) {
   323             axis = axis * 2 - 32767;
   324             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   325         } else {
   326             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_MIN_SINT16);
   327             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, SDL_MIN_SINT16);
   328         }
   329     } else {
   330         XINPUT_STATE_EX xinput_state;
   331 
   332         if (XINPUTGETSTATE(ctx->xinput_slot, &xinput_state) == ERROR_SUCCESS) {
   333             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (xinput_state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE) ? SDL_PRESSED : SDL_RELEASED);
   334             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, ((int)xinput_state.Gamepad.bLeftTrigger * 257) - 32768);
   335             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ((int)xinput_state.Gamepad.bRightTrigger * 257) - 32768);
   336         }
   337     }
   338 
   339     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   340 }
   341 #else
   342 
   343 static void
   344 HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
   345 {
   346     Sint16 axis;
   347 #ifdef __MACOSX__
   348     const SDL_bool invert_y_axes = SDL_FALSE;
   349 #else
   350     const SDL_bool invert_y_axes = SDL_TRUE;
   351 #endif
   352 
   353     if (ctx->last_state[2] != data[2]) {
   354         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   355         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   356         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[2] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   357         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[2] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   358         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[2] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   359         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[2] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   360         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[2] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   361         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[2] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   362     }
   363 
   364     if (ctx->last_state[3] != data[3]) {
   365         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[3] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   366         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[3] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   367         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[3] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   368         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[3] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   369         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[3] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   370         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[3] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   371         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[3] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   372     }
   373 
   374     axis = ((int)data[4] * 257) - 32768;
   375     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   376     axis = ((int)data[5] * 257) - 32768;
   377     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   378     axis = *(Sint16*)(&data[6]);
   379     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   380     axis = *(Sint16*)(&data[8]);
   381     if (invert_y_axes) {
   382         axis = ~axis;
   383     }
   384     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   385     axis = *(Sint16*)(&data[10]);
   386     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   387     axis = *(Sint16*)(&data[12]);
   388     if (invert_y_axes) {
   389         axis = ~axis;
   390     }
   391     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   392 
   393     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   394 }
   395 #endif /* __WIN32__ */
   396 
   397 #ifdef __MACOSX__
   398 static void
   399 HIDAPI_DriverXboxOneS_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
   400 {
   401     Sint16 axis;
   402 
   403     if (ctx->last_state[14] != data[14]) {
   404         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[14] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   405         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[14] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   406         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[14] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   407         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[14] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   408         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[14] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   409         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[14] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   410     }
   411 
   412     if (ctx->last_state[15] != data[15]) {
   413         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[15] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   414         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[15] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   415         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[15] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   416     }
   417 
   418     if (ctx->last_state[16] != data[16]) {
   419         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   420     }
   421 
   422     if (ctx->last_state[13] != data[13]) {
   423         SDL_bool dpad_up = SDL_FALSE;
   424         SDL_bool dpad_down = SDL_FALSE;
   425         SDL_bool dpad_left = SDL_FALSE;
   426         SDL_bool dpad_right = SDL_FALSE;
   427 
   428         switch (data[13]) {
   429         case 1:
   430             dpad_up = SDL_TRUE;
   431             break;
   432         case 2:
   433             dpad_up = SDL_TRUE;
   434             dpad_right = SDL_TRUE;
   435             break;
   436         case 3:
   437             dpad_right = SDL_TRUE;
   438             break;
   439         case 4:
   440             dpad_right = SDL_TRUE;
   441             dpad_down = SDL_TRUE;
   442             break;
   443         case 5:
   444             dpad_down = SDL_TRUE;
   445             break;
   446         case 6:
   447             dpad_left = SDL_TRUE;
   448             dpad_down = SDL_TRUE;
   449             break;
   450         case 7:
   451             dpad_left = SDL_TRUE;
   452             break;
   453         case 8:
   454             dpad_up = SDL_TRUE;
   455             dpad_left = SDL_TRUE;
   456             break;
   457         default:
   458             break;
   459         }
   460         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
   461         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
   462         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
   463         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
   464     }
   465 
   466     axis = (int)*(Uint16*)(&data[1]) - 0x8000;
   467     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   468     axis = (int)*(Uint16*)(&data[3]) - 0x8000;
   469     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   470     axis = (int)*(Uint16*)(&data[5]) - 0x8000;
   471     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   472     axis = (int)*(Uint16*)(&data[7]) - 0x8000;
   473     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   474 
   475     axis = ((int)*(Sint16*)(&data[9]) * 64) - 32768;
   476     if (axis == 32704) {
   477         axis = 32767;
   478     }
   479     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   480 
   481     axis = ((int)*(Sint16*)(&data[11]) * 64) - 32768;
   482     if (axis == 32704) {
   483         axis = 32767;
   484     }
   485     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   486 
   487     SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
   488 }
   489 
   490 static void
   491 HIDAPI_DriverXboxOneS_HandleGuidePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
   492 {
   493     SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   494 }
   495 #endif /* __MACOSX__ */
   496 
   497 static SDL_bool
   498 HIDAPI_DriverXbox360_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
   499 {
   500     SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
   501     Uint8 data[USB_PACKET_LENGTH];
   502     int size;
   503 
   504     while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
   505 #ifdef __WIN32__
   506         HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
   507 #else
   508         switch (data[0]) {
   509         case 0x00:
   510             HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
   511             break;
   512 #ifdef __MACOSX__
   513         case 0x01:
   514             HIDAPI_DriverXboxOneS_HandleStatePacket(joystick, dev, ctx, data, size);
   515             break;
   516         case 0x02:
   517             HIDAPI_DriverXboxOneS_HandleGuidePacket(joystick, dev, ctx, data, size);
   518             break;
   519 #endif
   520         default:
   521 #ifdef DEBUG_JOYSTICK
   522             SDL_Log("Unknown Xbox 360 packet, size = %d\n", size);
   523             SDL_Log("%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
   524                 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
   525                 data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16]);
   526 #endif
   527             break;
   528         }
   529 #endif /* __WIN32__ */
   530     }
   531 
   532     if (ctx->rumble_expiration) {
   533         Uint32 now = SDL_GetTicks();
   534         if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
   535             HIDAPI_DriverXbox360_Rumble(joystick, dev, context, 0, 0, 0);
   536         }
   537     }
   538 
   539     return (size >= 0);
   540 }
   541 
   542 static void
   543 HIDAPI_DriverXbox360_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
   544 {
   545 #ifdef __WIN32__
   546     SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
   547 
   548     if (ctx->xinput_enabled) {
   549         HIDAPI_DriverXbox360_MarkXInputSlotFree(ctx->xinput_slot);
   550         WIN_UnloadXInputDLL();
   551     }
   552 #endif
   553     SDL_free(context);
   554 }
   555 
   556 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 =
   557 {
   558     SDL_HINT_JOYSTICK_HIDAPI_XBOX,
   559     SDL_TRUE,
   560     HIDAPI_DriverXbox360_IsSupportedDevice,
   561     HIDAPI_DriverXbox360_GetDeviceName,
   562     HIDAPI_DriverXbox360_Init,
   563     HIDAPI_DriverXbox360_Rumble,
   564     HIDAPI_DriverXbox360_Update,
   565     HIDAPI_DriverXbox360_Quit
   566 };
   567 
   568 #endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
   569 
   570 #endif /* SDL_JOYSTICK_HIDAPI */
   571 
   572 /* vi: set ts=4 sw=4 expandtab: */