src/joystick/windows/SDL_xinputjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 25 Oct 2018 16:53:14 -0700
changeset 12359 691c32a30fb9
parent 12357 40f09c8c517b
child 12503 806492103856
permissions -rw-r--r--
Generalized the XInput user index into a player index
slouken@8972
     1
/*
slouken@8972
     2
  Simple DirectMedia Layer
slouken@11811
     3
  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
slouken@8972
     4
slouken@8972
     5
  This software is provided 'as-is', without any express or implied
slouken@8972
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@8972
     7
  arising from the use of this software.
slouken@8972
     8
slouken@8972
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@8972
    10
  including commercial applications, and to alter it and redistribute it
slouken@8972
    11
  freely, subject to the following restrictions:
slouken@8972
    12
slouken@8972
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@8972
    14
     claim that you wrote the original software. If you use this software
slouken@8972
    15
     in a product, an acknowledgment in the product documentation would be
slouken@8972
    16
     appreciated but is not required.
slouken@8972
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@8972
    18
     misrepresented as being the original software.
slouken@8972
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@8972
    20
*/
slouken@8972
    21
#include "../../SDL_internal.h"
slouken@8972
    22
icculus@9659
    23
#include "../SDL_sysjoystick.h"
icculus@9659
    24
icculus@9658
    25
#if SDL_JOYSTICK_XINPUT
icculus@9658
    26
slouken@8972
    27
#include "SDL_assert.h"
slouken@8972
    28
#include "SDL_hints.h"
slouken@12088
    29
#include "SDL_timer.h"
slouken@8972
    30
#include "SDL_windowsjoystick_c.h"
slouken@8972
    31
#include "SDL_xinputjoystick_c.h"
slouken@12088
    32
#include "../hidapi/SDL_hidapijoystick_c.h"
slouken@8972
    33
slouken@8972
    34
/*
slouken@8972
    35
 * Internal stuff.
slouken@8972
    36
 */
slouken@8972
    37
static SDL_bool s_bXInputEnabled = SDL_TRUE;
slouken@10872
    38
static char *s_arrXInputDevicePath[XUSER_MAX_COUNT];
slouken@8972
    39
slouken@8972
    40
slouken@8972
    41
static SDL_bool
slouken@8972
    42
SDL_XInputUseOldJoystickMapping()
slouken@8972
    43
{
dludwig@10697
    44
#ifdef __WINRT__
dludwig@10697
    45
    /* TODO: remove this __WINRT__ block, but only after integrating with UWP/WinRT's HID API */
flibitijibibo@11887
    46
    /* FIXME: Why are Win8/10 different here? -flibit */
flibitijibibo@11887
    47
    return (NTDDI_VERSION < NTDDI_WIN10);
dludwig@10697
    48
#else
slouken@8972
    49
    static int s_XInputUseOldJoystickMapping = -1;
slouken@8972
    50
    if (s_XInputUseOldJoystickMapping < 0) {
slouken@10499
    51
        s_XInputUseOldJoystickMapping = SDL_GetHintBoolean(SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING, SDL_FALSE);
slouken@8972
    52
    }
slouken@8972
    53
    return (s_XInputUseOldJoystickMapping > 0);
dludwig@10697
    54
#endif
slouken@8972
    55
}
slouken@8972
    56
slouken@8972
    57
SDL_bool SDL_XINPUT_Enabled(void)
slouken@8972
    58
{
slouken@8972
    59
    return s_bXInputEnabled;
slouken@8972
    60
}
slouken@8972
    61
slouken@8972
    62
int
slouken@8972
    63
SDL_XINPUT_JoystickInit(void)
slouken@8972
    64
{
slouken@10499
    65
    s_bXInputEnabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE);
slouken@8972
    66
slouken@8972
    67
    if (s_bXInputEnabled && WIN_LoadXInputDLL() < 0) {
slouken@8972
    68
        s_bXInputEnabled = SDL_FALSE;  /* oh well. */
slouken@8972
    69
    }
slouken@8972
    70
    return 0;
slouken@8972
    71
}
slouken@8972
    72
slouken@8972
    73
static char *
slouken@8972
    74
GetXInputName(const Uint8 userid, BYTE SubType)
slouken@8972
    75
{
slouken@8972
    76
    char name[32];
slouken@8972
    77
slouken@8972
    78
    if (SDL_XInputUseOldJoystickMapping()) {
slouken@8972
    79
        SDL_snprintf(name, sizeof(name), "X360 Controller #%u", 1 + userid);
slouken@8972
    80
    } else {
slouken@8972
    81
        switch (SubType) {
slouken@8972
    82
        case XINPUT_DEVSUBTYPE_GAMEPAD:
slouken@8972
    83
            SDL_snprintf(name, sizeof(name), "XInput Controller #%u", 1 + userid);
slouken@8972
    84
            break;
slouken@8972
    85
        case XINPUT_DEVSUBTYPE_WHEEL:
slouken@8972
    86
            SDL_snprintf(name, sizeof(name), "XInput Wheel #%u", 1 + userid);
slouken@8972
    87
            break;
slouken@8972
    88
        case XINPUT_DEVSUBTYPE_ARCADE_STICK:
slouken@8972
    89
            SDL_snprintf(name, sizeof(name), "XInput ArcadeStick #%u", 1 + userid);
slouken@8972
    90
            break;
slouken@8972
    91
        case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
slouken@8972
    92
            SDL_snprintf(name, sizeof(name), "XInput FlightStick #%u", 1 + userid);
slouken@8972
    93
            break;
slouken@8972
    94
        case XINPUT_DEVSUBTYPE_DANCE_PAD:
slouken@8972
    95
            SDL_snprintf(name, sizeof(name), "XInput DancePad #%u", 1 + userid);
slouken@8972
    96
            break;
slouken@8972
    97
        case XINPUT_DEVSUBTYPE_GUITAR:
slouken@8972
    98
        case XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE:
slouken@8972
    99
        case XINPUT_DEVSUBTYPE_GUITAR_BASS:
slouken@8972
   100
            SDL_snprintf(name, sizeof(name), "XInput Guitar #%u", 1 + userid);
slouken@8972
   101
            break;
slouken@8972
   102
        case XINPUT_DEVSUBTYPE_DRUM_KIT:
slouken@8972
   103
            SDL_snprintf(name, sizeof(name), "XInput DrumKit #%u", 1 + userid);
slouken@8972
   104
            break;
slouken@8972
   105
        case XINPUT_DEVSUBTYPE_ARCADE_PAD:
slouken@8972
   106
            SDL_snprintf(name, sizeof(name), "XInput ArcadePad #%u", 1 + userid);
slouken@8972
   107
            break;
slouken@8972
   108
        default:
slouken@8972
   109
            SDL_snprintf(name, sizeof(name), "XInput Device #%u", 1 + userid);
slouken@8972
   110
            break;
slouken@8972
   111
        }
slouken@8972
   112
    }
slouken@8972
   113
    return SDL_strdup(name);
slouken@8972
   114
}
slouken@8972
   115
slouken@10648
   116
/* We can't really tell what device is being used for XInput, but we can guess
slouken@10648
   117
   and we'll be correct for the case where only one device is connected.
slouken@10648
   118
 */
slouken@8972
   119
static void
slouken@10872
   120
GuessXInputDevice(Uint8 userid, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersion)
slouken@10648
   121
{
dludwig@10697
   122
#ifndef __WINRT__   /* TODO: remove this ifndef __WINRT__ block, but only after integrating with UWP/WinRT's HID API */
dludwig@10697
   123
slouken@10648
   124
    PRAWINPUTDEVICELIST devices = NULL;
philipp@10875
   125
    UINT i, j, device_count = 0;
slouken@10648
   126
slouken@10648
   127
    if ((GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) || (!device_count)) {
slouken@10648
   128
        return;  /* oh well. */
slouken@10648
   129
    }
slouken@10648
   130
slouken@10648
   131
    devices = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * device_count);
slouken@10648
   132
    if (devices == NULL) {
slouken@10648
   133
        return;
slouken@10648
   134
    }
slouken@10648
   135
slouken@10648
   136
    if (GetRawInputDeviceList(devices, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) {
slouken@10648
   137
        SDL_free(devices);
slouken@10648
   138
        return;  /* oh well. */
slouken@10648
   139
    }
slouken@10648
   140
slouken@10648
   141
    for (i = 0; i < device_count; i++) {
slouken@10648
   142
        RID_DEVICE_INFO rdi;
slouken@10648
   143
        char devName[128];
slouken@10648
   144
        UINT rdiSize = sizeof(rdi);
slouken@10648
   145
        UINT nameSize = SDL_arraysize(devName);
slouken@10648
   146
slouken@10648
   147
        rdi.cbSize = sizeof(rdi);
slouken@10648
   148
        if ((devices[i].dwType == RIM_TYPEHID) &&
slouken@10648
   149
            (GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
slouken@10648
   150
            (GetRawInputDeviceInfoA(devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
slouken@10648
   151
            (SDL_strstr(devName, "IG_") != NULL)) {
slouken@10872
   152
            SDL_bool found = SDL_FALSE;
slouken@10872
   153
            for (j = 0; j < SDL_arraysize(s_arrXInputDevicePath); ++j) {
slouken@10872
   154
                if (j == userid) {
slouken@10872
   155
                    continue;
slouken@10872
   156
                }
slouken@10872
   157
                if (!s_arrXInputDevicePath[j]) {
slouken@10872
   158
                    continue;
slouken@10872
   159
                }
slouken@10872
   160
                if (SDL_strcmp(devName, s_arrXInputDevicePath[j]) == 0) {
slouken@10872
   161
                    found = SDL_TRUE;
slouken@10872
   162
                    break;
slouken@10872
   163
                }
slouken@10872
   164
            }
slouken@10872
   165
            if (found) {
slouken@10872
   166
                /* We already have this device in our XInput device list */
slouken@10872
   167
                continue;
slouken@10872
   168
            }
slouken@10872
   169
slouken@10872
   170
            /* We don't actually know if this is the right device for this
slouken@10872
   171
             * userid, but we'll record it so we'll at least be consistent
slouken@10872
   172
             * when the raw device list changes.
slouken@10872
   173
             */
slouken@10648
   174
            *pVID = (Uint16)rdi.hid.dwVendorId;
slouken@10648
   175
            *pPID = (Uint16)rdi.hid.dwProductId;
slouken@10648
   176
            *pVersion = (Uint16)rdi.hid.dwVersionNumber;
slouken@10872
   177
            if (s_arrXInputDevicePath[userid]) {
slouken@10872
   178
                SDL_free(s_arrXInputDevicePath[userid]);
slouken@10648
   179
            }
slouken@10872
   180
            s_arrXInputDevicePath[userid] = SDL_strdup(devName);
slouken@10872
   181
            break;
slouken@10648
   182
        }
slouken@10648
   183
    }
slouken@10648
   184
    SDL_free(devices);
dludwig@10697
   185
#endif  /* ifndef __WINRT__ */
slouken@10648
   186
}
slouken@10648
   187
slouken@10648
   188
static void
slouken@10648
   189
AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pContext)
slouken@8972
   190
{
slouken@12088
   191
    Uint16 vendor = 0;
slouken@12088
   192
    Uint16 product = 0;
slouken@12088
   193
    Uint16 version = 0;
slouken@8972
   194
    JoyStick_DeviceData *pPrevJoystick = NULL;
slouken@8972
   195
    JoyStick_DeviceData *pNewJoystick = *pContext;
slouken@8972
   196
slouken@8972
   197
    if (SDL_XInputUseOldJoystickMapping() && SubType != XINPUT_DEVSUBTYPE_GAMEPAD)
slouken@8972
   198
        return;
slouken@8972
   199
slouken@8972
   200
    if (SubType == XINPUT_DEVSUBTYPE_UNKNOWN)
slouken@8972
   201
        return;
slouken@8972
   202
slouken@8972
   203
    while (pNewJoystick) {
slouken@8972
   204
        if (pNewJoystick->bXInputDevice && (pNewJoystick->XInputUserId == userid) && (pNewJoystick->SubType == SubType)) {
slouken@8972
   205
            /* if we are replacing the front of the list then update it */
slouken@8972
   206
            if (pNewJoystick == *pContext) {
slouken@8972
   207
                *pContext = pNewJoystick->pNext;
slouken@8972
   208
            } else if (pPrevJoystick) {
slouken@8972
   209
                pPrevJoystick->pNext = pNewJoystick->pNext;
slouken@8972
   210
            }
slouken@8972
   211
slouken@8972
   212
            pNewJoystick->pNext = SYS_Joystick;
slouken@8972
   213
            SYS_Joystick = pNewJoystick;
slouken@8972
   214
            return;   /* already in the list. */
slouken@8972
   215
        }
slouken@8972
   216
slouken@8972
   217
        pPrevJoystick = pNewJoystick;
slouken@8972
   218
        pNewJoystick = pNewJoystick->pNext;
slouken@8972
   219
    }
slouken@8972
   220
slouken@8972
   221
    pNewJoystick = (JoyStick_DeviceData *)SDL_malloc(sizeof(JoyStick_DeviceData));
slouken@8972
   222
    if (!pNewJoystick) {
slouken@8972
   223
        return; /* better luck next time? */
slouken@8972
   224
    }
slouken@8972
   225
    SDL_zerop(pNewJoystick);
slouken@8972
   226
slouken@8972
   227
    pNewJoystick->joystickname = GetXInputName(userid, SubType);
slouken@8972
   228
    if (!pNewJoystick->joystickname) {
slouken@8972
   229
        SDL_free(pNewJoystick);
slouken@8972
   230
        return; /* better luck next time? */
slouken@8972
   231
    }
slouken@8972
   232
slouken@8972
   233
    pNewJoystick->bXInputDevice = SDL_TRUE;
slouken@8972
   234
    if (SDL_XInputUseOldJoystickMapping()) {
slouken@8972
   235
        SDL_zero(pNewJoystick->guid);
slouken@8972
   236
    } else {
slouken@10648
   237
        Uint16 *guid16 = (Uint16 *)pNewJoystick->guid.data;
slouken@10648
   238
slouken@10648
   239
        GuessXInputDevice(userid, &vendor, &product, &version);
slouken@10648
   240
slouken@12088
   241
        *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB);
slouken@10648
   242
        *guid16++ = 0;
slouken@10648
   243
        *guid16++ = SDL_SwapLE16(vendor);
slouken@10648
   244
        *guid16++ = 0;
slouken@10648
   245
        *guid16++ = SDL_SwapLE16(product);
slouken@10648
   246
        *guid16++ = 0;
slouken@10648
   247
        *guid16++ = SDL_SwapLE16(version);
slouken@10648
   248
        *guid16++ = 0;
slouken@10648
   249
slouken@10648
   250
        /* Note that this is an XInput device and what subtype it is */
slouken@10648
   251
        pNewJoystick->guid.data[14] = 'x';
slouken@10648
   252
        pNewJoystick->guid.data[15] = SubType;
slouken@8972
   253
    }
slouken@8972
   254
    pNewJoystick->SubType = SubType;
slouken@8972
   255
    pNewJoystick->XInputUserId = userid;
slouken@11201
   256
slouken@12088
   257
    if (SDL_ShouldIgnoreJoystick(pNewJoystick->joystickname, pNewJoystick->guid)) {
slouken@11201
   258
        SDL_free(pNewJoystick);
slouken@11201
   259
        return;
slouken@11201
   260
    }
slouken@11201
   261
slouken@12088
   262
#ifdef SDL_JOYSTICK_HIDAPI
slouken@12115
   263
    if (HIDAPI_IsDevicePresent(vendor, product, version)) {
slouken@12088
   264
        /* The HIDAPI driver is taking care of this device */
slouken@12088
   265
        SDL_free(pNewJoystick);
slouken@12088
   266
        return;
slouken@12088
   267
    }
slouken@12088
   268
#endif
slouken@12088
   269
slouken@12088
   270
    WINDOWS_AddJoystickDevice(pNewJoystick);
slouken@8972
   271
}
slouken@8972
   272
slouken@12090
   273
static void
slouken@12090
   274
DelXInputDevice(Uint8 userid)
slouken@12090
   275
{
slouken@12090
   276
    if (s_arrXInputDevicePath[userid]) {
slouken@12090
   277
        SDL_free(s_arrXInputDevicePath[userid]);
slouken@12090
   278
        s_arrXInputDevicePath[userid] = NULL;
slouken@12090
   279
    }
slouken@12090
   280
}
slouken@12090
   281
slouken@8972
   282
void
slouken@8972
   283
SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
slouken@8972
   284
{
slouken@8972
   285
    int iuserid;
slouken@8972
   286
slouken@8972
   287
    if (!s_bXInputEnabled) {
slouken@8972
   288
        return;
slouken@8972
   289
    }
slouken@8972
   290
slouken@8972
   291
    /* iterate in reverse, so these are in the final list in ascending numeric order. */
slouken@8972
   292
    for (iuserid = XUSER_MAX_COUNT - 1; iuserid >= 0; iuserid--) {
slouken@8972
   293
        const Uint8 userid = (Uint8)iuserid;
slouken@8972
   294
        XINPUT_CAPABILITIES capabilities;
slouken@8972
   295
        if (XINPUTGETCAPABILITIES(userid, XINPUT_FLAG_GAMEPAD, &capabilities) == ERROR_SUCCESS) {
slouken@8972
   296
            AddXInputDevice(userid, capabilities.SubType, pContext);
slouken@12090
   297
        } else {
slouken@12090
   298
            DelXInputDevice(userid);
slouken@8972
   299
        }
slouken@8972
   300
    }
slouken@8972
   301
}
slouken@8972
   302
slouken@8972
   303
int
slouken@8972
   304
SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
slouken@8972
   305
{
slouken@8972
   306
    const Uint8 userId = joystickdevice->XInputUserId;
slouken@8972
   307
    XINPUT_CAPABILITIES capabilities;
slouken@8972
   308
    XINPUT_VIBRATION state;
slouken@8972
   309
slouken@8972
   310
    SDL_assert(s_bXInputEnabled);
slouken@8972
   311
    SDL_assert(XINPUTGETCAPABILITIES);
slouken@8972
   312
    SDL_assert(XINPUTSETSTATE);
slouken@8972
   313
    SDL_assert(userId < XUSER_MAX_COUNT);
slouken@8972
   314
slouken@12359
   315
    joystick->player_index = userId;
slouken@12359
   316
slouken@8972
   317
    joystick->hwdata->bXInputDevice = SDL_TRUE;
slouken@8972
   318
slouken@8972
   319
    if (XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities) != ERROR_SUCCESS) {
slouken@8972
   320
        SDL_free(joystick->hwdata);
slouken@8972
   321
        joystick->hwdata = NULL;
slouken@8972
   322
        return SDL_SetError("Failed to obtain XInput device capabilities. Device disconnected?");
slouken@8972
   323
    }
slouken@8972
   324
    SDL_zero(state);
slouken@8972
   325
    joystick->hwdata->bXInputHaptic = (XINPUTSETSTATE(userId, &state) == ERROR_SUCCESS);
slouken@8972
   326
    joystick->hwdata->userid = userId;
slouken@8972
   327
slouken@8972
   328
    /* The XInput API has a hard coded button/axis mapping, so we just match it */
slouken@8972
   329
    if (SDL_XInputUseOldJoystickMapping()) {
slouken@8972
   330
        joystick->naxes = 6;
slouken@8972
   331
        joystick->nbuttons = 15;
slouken@8972
   332
    } else {
slouken@8972
   333
        joystick->naxes = 6;
slouken@8972
   334
        joystick->nbuttons = 11;
slouken@8972
   335
        joystick->nhats = 1;
slouken@8972
   336
    }
slouken@8972
   337
    return 0;
slouken@8972
   338
}
slouken@8972
   339
slouken@9884
   340
static void 
dludwig@9918
   341
UpdateXInputJoystickBatteryInformation(SDL_Joystick * joystick, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation)
slouken@9884
   342
{
slouken@10872
   343
    if (pBatteryInformation->BatteryType != BATTERY_TYPE_UNKNOWN) {
slouken@9884
   344
        SDL_JoystickPowerLevel ePowerLevel = SDL_JOYSTICK_POWER_UNKNOWN;
slouken@9884
   345
        if (pBatteryInformation->BatteryType == BATTERY_TYPE_WIRED) {
slouken@9884
   346
            ePowerLevel = SDL_JOYSTICK_POWER_WIRED;
slouken@9884
   347
        } else {
slouken@10872
   348
            switch (pBatteryInformation->BatteryLevel) {
slouken@9884
   349
            case BATTERY_LEVEL_EMPTY:
slouken@9884
   350
                ePowerLevel = SDL_JOYSTICK_POWER_EMPTY;
slouken@9884
   351
                break;
slouken@9884
   352
            case BATTERY_LEVEL_LOW:
slouken@9884
   353
                ePowerLevel = SDL_JOYSTICK_POWER_LOW;
slouken@9884
   354
                break;
slouken@9884
   355
            case BATTERY_LEVEL_MEDIUM:
slouken@9884
   356
                ePowerLevel = SDL_JOYSTICK_POWER_MEDIUM;
slouken@9884
   357
                break;
slouken@9884
   358
            default:
slouken@9884
   359
            case BATTERY_LEVEL_FULL:
slouken@9884
   360
                ePowerLevel = SDL_JOYSTICK_POWER_FULL;
slouken@9884
   361
                break;
slouken@9884
   362
            }
slouken@9884
   363
        }
slouken@9884
   364
slouken@10872
   365
        SDL_PrivateJoystickBatteryLevel(joystick, ePowerLevel);
slouken@9884
   366
    }
slouken@9884
   367
}
slouken@9884
   368
slouken@8972
   369
static void
dludwig@9918
   370
UpdateXInputJoystickState_OLD(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation)
slouken@8972
   371
{
slouken@8972
   372
    static WORD s_XInputButtons[] = {
slouken@8972
   373
        XINPUT_GAMEPAD_DPAD_UP, XINPUT_GAMEPAD_DPAD_DOWN, XINPUT_GAMEPAD_DPAD_LEFT, XINPUT_GAMEPAD_DPAD_RIGHT,
slouken@8972
   374
        XINPUT_GAMEPAD_START, XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_LEFT_THUMB, XINPUT_GAMEPAD_RIGHT_THUMB,
slouken@8972
   375
        XINPUT_GAMEPAD_LEFT_SHOULDER, XINPUT_GAMEPAD_RIGHT_SHOULDER,
slouken@8972
   376
        XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, XINPUT_GAMEPAD_X, XINPUT_GAMEPAD_Y,
slouken@8972
   377
        XINPUT_GAMEPAD_GUIDE
slouken@8972
   378
    };
slouken@8972
   379
    WORD wButtons = pXInputState->Gamepad.wButtons;
slouken@8972
   380
    Uint8 button;
slouken@8972
   381
slouken@8972
   382
    SDL_PrivateJoystickAxis(joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX);
slouken@8972
   383
    SDL_PrivateJoystickAxis(joystick, 1, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbLY)));
slouken@8972
   384
    SDL_PrivateJoystickAxis(joystick, 2, (Sint16)pXInputState->Gamepad.sThumbRX);
slouken@8972
   385
    SDL_PrivateJoystickAxis(joystick, 3, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbRY)));
slouken@8972
   386
    SDL_PrivateJoystickAxis(joystick, 4, (Sint16)(((int)pXInputState->Gamepad.bLeftTrigger * 65535 / 255) - 32768));
slouken@8972
   387
    SDL_PrivateJoystickAxis(joystick, 5, (Sint16)(((int)pXInputState->Gamepad.bRightTrigger * 65535 / 255) - 32768));
slouken@8972
   388
slouken@8972
   389
    for (button = 0; button < SDL_arraysize(s_XInputButtons); ++button) {
slouken@8972
   390
        SDL_PrivateJoystickButton(joystick, button, (wButtons & s_XInputButtons[button]) ? SDL_PRESSED : SDL_RELEASED);
slouken@8972
   391
    }
slouken@9884
   392
slouken@10872
   393
    UpdateXInputJoystickBatteryInformation(joystick, pBatteryInformation);
slouken@8972
   394
}
slouken@8972
   395
slouken@8972
   396
static void
dludwig@9918
   397
UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState, XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation)
slouken@8972
   398
{
slouken@8972
   399
    static WORD s_XInputButtons[] = {
slouken@8972
   400
        XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, XINPUT_GAMEPAD_X, XINPUT_GAMEPAD_Y,
slouken@8972
   401
        XINPUT_GAMEPAD_LEFT_SHOULDER, XINPUT_GAMEPAD_RIGHT_SHOULDER, XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_START,
slouken@8972
   402
        XINPUT_GAMEPAD_LEFT_THUMB, XINPUT_GAMEPAD_RIGHT_THUMB,
slouken@8972
   403
        XINPUT_GAMEPAD_GUIDE
slouken@8972
   404
    };
slouken@8972
   405
    WORD wButtons = pXInputState->Gamepad.wButtons;
slouken@8972
   406
    Uint8 button;
slouken@8972
   407
    Uint8 hat = SDL_HAT_CENTERED;
slouken@8972
   408
slouken@12088
   409
    SDL_PrivateJoystickAxis(joystick, 0, pXInputState->Gamepad.sThumbLX);
slouken@12088
   410
    SDL_PrivateJoystickAxis(joystick, 1, ~pXInputState->Gamepad.sThumbLY);
slouken@12088
   411
    SDL_PrivateJoystickAxis(joystick, 2, ((int)pXInputState->Gamepad.bLeftTrigger * 257) - 32768);
slouken@12088
   412
    SDL_PrivateJoystickAxis(joystick, 3, pXInputState->Gamepad.sThumbRX);
slouken@12088
   413
    SDL_PrivateJoystickAxis(joystick, 4, ~pXInputState->Gamepad.sThumbRY);
slouken@12088
   414
    SDL_PrivateJoystickAxis(joystick, 5, ((int)pXInputState->Gamepad.bRightTrigger * 257) - 32768);
slouken@8972
   415
slouken@8972
   416
    for (button = 0; button < SDL_arraysize(s_XInputButtons); ++button) {
slouken@8972
   417
        SDL_PrivateJoystickButton(joystick, button, (wButtons & s_XInputButtons[button]) ? SDL_PRESSED : SDL_RELEASED);
slouken@8972
   418
    }
slouken@8972
   419
slouken@8972
   420
    if (wButtons & XINPUT_GAMEPAD_DPAD_UP) {
slouken@8972
   421
        hat |= SDL_HAT_UP;
slouken@8972
   422
    }
slouken@8972
   423
    if (wButtons & XINPUT_GAMEPAD_DPAD_DOWN) {
slouken@8972
   424
        hat |= SDL_HAT_DOWN;
slouken@8972
   425
    }
slouken@8972
   426
    if (wButtons & XINPUT_GAMEPAD_DPAD_LEFT) {
slouken@8972
   427
        hat |= SDL_HAT_LEFT;
slouken@8972
   428
    }
slouken@8972
   429
    if (wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) {
slouken@8972
   430
        hat |= SDL_HAT_RIGHT;
slouken@8972
   431
    }
slouken@8972
   432
    SDL_PrivateJoystickHat(joystick, 0, hat);
slouken@9884
   433
slouken@10872
   434
    UpdateXInputJoystickBatteryInformation(joystick, pBatteryInformation);
slouken@8972
   435
}
slouken@8972
   436
slouken@12088
   437
int
slouken@12088
   438
SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
slouken@12088
   439
{
slouken@12088
   440
    XINPUT_VIBRATION XVibration;
slouken@12088
   441
slouken@12088
   442
    if (!XINPUTSETSTATE) {
slouken@12088
   443
        return SDL_Unsupported();
slouken@12088
   444
    }
slouken@12088
   445
slouken@12088
   446
    XVibration.wLeftMotorSpeed = low_frequency_rumble;
slouken@12088
   447
    XVibration.wRightMotorSpeed = high_frequency_rumble;
slouken@12088
   448
    if (XINPUTSETSTATE(joystick->hwdata->userid, &XVibration) != ERROR_SUCCESS) {
slouken@12088
   449
        return SDL_SetError("XInputSetState() failed");
slouken@12088
   450
    }
slouken@12088
   451
slouken@12088
   452
    if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
slouken@12088
   453
        joystick->hwdata->rumble_expiration = SDL_GetTicks() + duration_ms;
slouken@12088
   454
    } else {
slouken@12088
   455
        joystick->hwdata->rumble_expiration = 0;
slouken@12088
   456
    }
slouken@12088
   457
    return 0;
slouken@12088
   458
}
slouken@12088
   459
slouken@8972
   460
void
slouken@8972
   461
SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick)
slouken@8972
   462
{
slouken@8972
   463
    HRESULT result;
slouken@8972
   464
    XINPUT_STATE_EX XInputState;
dludwig@9918
   465
    XINPUT_BATTERY_INFORMATION_EX XBatteryInformation;
slouken@8972
   466
slouken@8972
   467
    if (!XINPUTGETSTATE)
slouken@8972
   468
        return;
slouken@8972
   469
slouken@8972
   470
    result = XINPUTGETSTATE(joystick->hwdata->userid, &XInputState);
slouken@8972
   471
    if (result == ERROR_DEVICE_NOT_CONNECTED) {
slouken@8972
   472
        return;
slouken@8972
   473
    }
slouken@8972
   474
slouken@10872
   475
    SDL_zero(XBatteryInformation);
slouken@10872
   476
    if (XINPUTGETBATTERYINFORMATION) {
slouken@10872
   477
        result = XINPUTGETBATTERYINFORMATION(joystick->hwdata->userid, BATTERY_DEVTYPE_GAMEPAD, &XBatteryInformation);
slouken@9884
   478
    }
slouken@9884
   479
slouken@8972
   480
    /* only fire events if the data changed from last time */
slouken@8972
   481
    if (XInputState.dwPacketNumber && XInputState.dwPacketNumber != joystick->hwdata->dwPacketNumber) {
slouken@8972
   482
        if (SDL_XInputUseOldJoystickMapping()) {
slouken@9884
   483
            UpdateXInputJoystickState_OLD(joystick, &XInputState, &XBatteryInformation);
slouken@8972
   484
        } else {
slouken@9884
   485
            UpdateXInputJoystickState(joystick, &XInputState, &XBatteryInformation);
slouken@8972
   486
        }
slouken@8972
   487
        joystick->hwdata->dwPacketNumber = XInputState.dwPacketNumber;
slouken@8972
   488
    }
slouken@12088
   489
slouken@12088
   490
    if (joystick->hwdata->rumble_expiration) {
slouken@12088
   491
        Uint32 now = SDL_GetTicks();
slouken@12088
   492
        if (SDL_TICKS_PASSED(now, joystick->hwdata->rumble_expiration)) {
slouken@12088
   493
            SDL_XINPUT_JoystickRumble(joystick, 0, 0, 0);
slouken@12088
   494
        }
slouken@12088
   495
    }
slouken@8972
   496
}
slouken@8972
   497
slouken@8972
   498
void
slouken@8972
   499
SDL_XINPUT_JoystickClose(SDL_Joystick * joystick)
slouken@8972
   500
{
slouken@8972
   501
}
slouken@8972
   502
slouken@8972
   503
void
slouken@8972
   504
SDL_XINPUT_JoystickQuit(void)
slouken@8972
   505
{
slouken@8972
   506
    if (s_bXInputEnabled) {
slouken@8972
   507
        WIN_UnloadXInputDLL();
slouken@8972
   508
    }
slouken@8972
   509
}
slouken@8972
   510
slouken@8972
   511
#else /* !SDL_JOYSTICK_XINPUT */
slouken@8972
   512
icculus@9660
   513
typedef struct JoyStick_DeviceData JoyStick_DeviceData;
slouken@8972
   514
slouken@8972
   515
SDL_bool SDL_XINPUT_Enabled(void)
slouken@8972
   516
{
slouken@8972
   517
    return SDL_FALSE;
slouken@8972
   518
}
slouken@8972
   519
slouken@8972
   520
int
slouken@8972
   521
SDL_XINPUT_JoystickInit(void)
slouken@8972
   522
{
slouken@8972
   523
    return 0;
slouken@8972
   524
}
slouken@8972
   525
slouken@8972
   526
void
slouken@8972
   527
SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
slouken@8972
   528
{
slouken@8972
   529
}
slouken@8972
   530
slouken@8972
   531
int
slouken@8972
   532
SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
slouken@8972
   533
{
slouken@8972
   534
    return SDL_Unsupported();
slouken@8972
   535
}
slouken@8972
   536
slouken@12088
   537
int
slouken@12088
   538
SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
slouken@12088
   539
{
slouken@12088
   540
    return SDL_Unsupported();
slouken@12088
   541
}
slouken@12088
   542
slouken@8972
   543
void
slouken@8972
   544
SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick)
slouken@8972
   545
{
slouken@8972
   546
}
slouken@8972
   547
slouken@8972
   548
void
slouken@8972
   549
SDL_XINPUT_JoystickClose(SDL_Joystick * joystick)
slouken@8972
   550
{
slouken@8972
   551
}
slouken@8972
   552
slouken@8972
   553
void
slouken@8972
   554
SDL_XINPUT_JoystickQuit(void)
slouken@8972
   555
{
slouken@8972
   556
}
slouken@8972
   557
slouken@8972
   558
#endif /* SDL_JOYSTICK_XINPUT */
slouken@8972
   559
slouken@8972
   560
/* vi: set ts=4 sw=4 expandtab: */