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