src/joystick/hidapi/SDL_hidapi_xboxone.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 09 Dec 2019 16:52:11 -0800
changeset 13324 b46a94bb2ab0
parent 13323 a8804daa1c3d
child 13330 c88765bcf1da
permissions -rw-r--r--
Fixed rumble after Xbox controller initialization
When we initialize the controller it has an internal rumble sequence number, and if our rumble sequence number doesn't match that, rumble won't happen. To fix that we cycle through the range of sequence numbers, and at some point we'll match up with the controller's sequence number and it'll roll forward until it matches our next rumble sequence number.
slouken@12088
     1
/*
slouken@12088
     2
  Simple DirectMedia Layer
slouken@12503
     3
  Copyright (C) 1997-2019 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_XBOXONE
slouken@12088
    36
slouken@12088
    37
#define USB_PACKET_LENGTH   64
slouken@12088
    38
slouken@13274
    39
/* The amount of time to wait after hotplug to send controller init sequence */
slouken@13274
    40
#define CONTROLLER_INIT_DELAY_MS    100
slouken@13274
    41
slouken@13300
    42
/* This is the full init sequence for the Xbox One Elite Series 2 controller.
slouken@13300
    43
   Normally it isn't needed, but this switches the controller back to wired report mode after being in Bluetooth mode.
slouken@13300
    44
*/
slouken@13300
    45
static const Uint8 xboxone_elite_init0[] = {
slouken@13300
    46
    0x04, 0x20, 0x01, 0x00
slouken@13300
    47
};
slouken@13300
    48
static const Uint8 xboxone_elite_init1[] = {
slouken@13300
    49
    0x01, 0x20, 0x28, 0x09, 0x00, 0x04, 0x20, 0x3A,
slouken@13300
    50
    0x00, 0x00, 0x00, 0x31, 0x01
slouken@13300
    51
};
slouken@13300
    52
static const Uint8 xboxone_elite_init2[] = {
slouken@13300
    53
    0x01, 0x20, 0x28, 0x09, 0x00, 0x04, 0x20, 0x6B,
slouken@13300
    54
    0x01, 0x00, 0x00, 0x00, 0x00
slouken@13300
    55
};
slouken@13300
    56
static const Uint8 xboxone_elite_init3[] = {
slouken@13300
    57
    0x05, 0x20, 0x02, 0x0F, 0x06, 0x00, 0x00, 0x00,
slouken@13300
    58
    0x00, 0x00, 0x00, 0x55, 0x53, 0x00, 0x00, 0x00,
slouken@13300
    59
    0x00, 0x00, 0x00
slouken@13300
    60
};
slouken@13300
    61
static const Uint8 xboxone_elite_init4[] = {
slouken@13300
    62
    0x05, 0x20, 0x03, 0x01, 0x00
slouken@13300
    63
};
slouken@13300
    64
static const Uint8 xboxone_elite_init5[] = {
slouken@13300
    65
    0x0A, 0x20, 0x04, 0x03, 0x00, 0x01, 0x14
slouken@13300
    66
};
slouken@13300
    67
slouken@12088
    68
/*
slouken@12088
    69
 * This packet is required for all Xbox One pads with 2015
slouken@12088
    70
 * or later firmware installed (or present from the factory).
slouken@12088
    71
 */
slouken@12088
    72
static const Uint8 xboxone_fw2015_init[] = {
slouken@12088
    73
    0x05, 0x20, 0x00, 0x01, 0x00
slouken@12088
    74
};
slouken@12088
    75
slouken@12088
    76
/*
slouken@12088
    77
 * This packet is required for the Titanfall 2 Xbox One pads
slouken@12088
    78
 * (0x0e6f:0x0165) to finish initialization and for Hori pads
slouken@12088
    79
 * (0x0f0d:0x0067) to make the analog sticks work.
slouken@12088
    80
 */
slouken@12088
    81
static const Uint8 xboxone_hori_init[] = {
slouken@12088
    82
    0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a,
slouken@12088
    83
    0x00, 0x00, 0x00, 0x80, 0x00
slouken@12088
    84
};
slouken@12088
    85
slouken@12088
    86
/*
slouken@12088
    87
 * This packet is required for some of the PDP pads to start
slouken@12088
    88
 * sending input reports. These pads include: (0x0e6f:0x02ab),
slouken@12088
    89
 * (0x0e6f:0x02a4).
slouken@12088
    90
 */
slouken@12088
    91
static const Uint8 xboxone_pdp_init1[] = {
slouken@12088
    92
    0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
slouken@12088
    93
};
slouken@12088
    94
slouken@12088
    95
/*
slouken@12088
    96
 * This packet is required for some of the PDP pads to start
slouken@12088
    97
 * sending input reports. These pads include: (0x0e6f:0x02ab),
slouken@12088
    98
 * (0x0e6f:0x02a4).
slouken@12088
    99
 */
slouken@12088
   100
static const Uint8 xboxone_pdp_init2[] = {
slouken@12088
   101
    0x06, 0x20, 0x00, 0x02, 0x01, 0x00
slouken@12088
   102
};
slouken@12088
   103
slouken@12088
   104
/*
slouken@12088
   105
 * A specific rumble packet is required for some PowerA pads to start
slouken@12088
   106
 * sending input reports. One of those pads is (0x24c6:0x543a).
slouken@12088
   107
 */
slouken@12088
   108
static const Uint8 xboxone_rumblebegin_init[] = {
slouken@12088
   109
    0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
slouken@12088
   110
    0x1D, 0x1D, 0xFF, 0x00, 0x00
slouken@12088
   111
};
slouken@12088
   112
slouken@12088
   113
/*
slouken@12088
   114
 * A rumble packet with zero FF intensity will immediately
slouken@12088
   115
 * terminate the rumbling required to init PowerA pads.
slouken@12088
   116
 * This should happen fast enough that the motors don't
slouken@12088
   117
 * spin up to enough speed to actually vibrate the gamepad.
slouken@12088
   118
 */
slouken@12088
   119
static const Uint8 xboxone_rumbleend_init[] = {
slouken@12088
   120
    0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
slouken@12088
   121
    0x00, 0x00, 0x00, 0x00, 0x00
slouken@12088
   122
};
slouken@12088
   123
slouken@12088
   124
/*
slouken@12088
   125
 * This specifies the selection of init packets that a gamepad
slouken@12088
   126
 * will be sent on init *and* the order in which they will be
slouken@12088
   127
 * sent. The correct sequence number will be added when the
slouken@12088
   128
 * packet is going to be sent.
slouken@12088
   129
 */
slouken@12088
   130
typedef struct {
slouken@12088
   131
    Uint16 vendor_id;
slouken@12088
   132
    Uint16 product_id;
slouken@12088
   133
    const Uint8 *data;
slouken@12088
   134
    int size;
slouken@12088
   135
} SDL_DriverXboxOne_InitPacket;
slouken@12088
   136
slouken@13300
   137
slouken@12088
   138
static const SDL_DriverXboxOne_InitPacket xboxone_init_packets[] = {
slouken@12088
   139
    { 0x0e6f, 0x0165, xboxone_hori_init, sizeof(xboxone_hori_init) },
slouken@12088
   140
    { 0x0f0d, 0x0067, xboxone_hori_init, sizeof(xboxone_hori_init) },
slouken@13300
   141
    { 0x045e, 0x0b00, xboxone_elite_init0, sizeof(xboxone_elite_init0) },
slouken@13300
   142
    { 0x045e, 0x0b00, xboxone_elite_init1, sizeof(xboxone_elite_init1) },
slouken@13300
   143
    { 0x045e, 0x0b00, xboxone_elite_init2, sizeof(xboxone_elite_init2) },
slouken@13300
   144
    { 0x045e, 0x0b00, xboxone_elite_init3, sizeof(xboxone_elite_init3) },
slouken@13300
   145
    { 0x045e, 0x0b00, xboxone_elite_init4, sizeof(xboxone_elite_init4) },
slouken@13300
   146
    { 0x045e, 0x0b00, xboxone_elite_init5, sizeof(xboxone_elite_init5) },
slouken@12088
   147
    { 0x0000, 0x0000, xboxone_fw2015_init, sizeof(xboxone_fw2015_init) },
slouken@13274
   148
    { 0x0e6f, 0x0000, xboxone_pdp_init1, sizeof(xboxone_pdp_init1) },
slouken@13274
   149
    { 0x0e6f, 0x0000, xboxone_pdp_init2, sizeof(xboxone_pdp_init2) },
slouken@12088
   150
    { 0x24c6, 0x541a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
slouken@12088
   151
    { 0x24c6, 0x542a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
slouken@12088
   152
    { 0x24c6, 0x543a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
slouken@12088
   153
    { 0x24c6, 0x541a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
slouken@12088
   154
    { 0x24c6, 0x542a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
slouken@12088
   155
    { 0x24c6, 0x543a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
slouken@12088
   156
};
slouken@12088
   157
slouken@12088
   158
typedef struct {
slouken@13274
   159
    Uint16 vendor_id;
slouken@13274
   160
    Uint16 product_id;
slouken@13274
   161
    Uint32 start_time;
slouken@13274
   162
    SDL_bool initialized;
slouken@12088
   163
    Uint8 sequence;
slouken@12088
   164
    Uint8 last_state[USB_PACKET_LENGTH];
slouken@12088
   165
    Uint32 rumble_expiration;
slouken@12088
   166
} SDL_DriverXboxOne_Context;
slouken@12088
   167
slouken@12088
   168
slouken@12088
   169
static SDL_bool
slouken@13255
   170
IsBluetoothXboxOneController(Uint16 vendor_id, Uint16 product_id)
slouken@13255
   171
{
slouken@13255
   172
    /* Check to see if it's the Xbox One S or Xbox One Elite Series 2 in Bluetooth mode */
slouken@13255
   173
    const Uint16 USB_VENDOR_MICROSOFT = 0x045e;
slouken@13303
   174
    const Uint16 USB_PRODUCT_XBOX_ONE_S_REV1 = 0x02e0;
slouken@13303
   175
    const Uint16 USB_PRODUCT_XBOX_ONE_S_REV2 = 0x02fd;
slouken@13255
   176
    const Uint16 USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 = 0x0b05;
slouken@13255
   177
slouken@13303
   178
    if (vendor_id == USB_VENDOR_MICROSOFT) {
slouken@13303
   179
        if (product_id == USB_PRODUCT_XBOX_ONE_S_REV1 ||
slouken@13303
   180
            product_id == USB_PRODUCT_XBOX_ONE_S_REV2 ||
slouken@13303
   181
            product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2) {
slouken@13303
   182
            return SDL_TRUE;
slouken@13303
   183
        }
slouken@13255
   184
    }
slouken@13255
   185
    return SDL_FALSE;
slouken@13255
   186
}
slouken@13255
   187
slouken@13255
   188
static SDL_bool
slouken@13274
   189
SendControllerInit(hid_device *dev, SDL_DriverXboxOne_Context *ctx)
slouken@13274
   190
{
slouken@13274
   191
    Uint16 vendor_id = ctx->vendor_id;
slouken@13274
   192
    Uint16 product_id = ctx->product_id;
slouken@13274
   193
slouken@13274
   194
    if (!IsBluetoothXboxOneController(vendor_id, product_id)) {
slouken@13324
   195
        int i, j;
slouken@13274
   196
        Uint8 init_packet[USB_PACKET_LENGTH];
slouken@13274
   197
slouken@13274
   198
        for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
slouken@13274
   199
            const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i];
slouken@13274
   200
slouken@13274
   201
            if (packet->vendor_id && (vendor_id != packet->vendor_id)) {
slouken@13274
   202
                continue;
slouken@13274
   203
            }
slouken@13274
   204
slouken@13274
   205
            if (packet->product_id && (product_id != packet->product_id)) {
slouken@13274
   206
                continue;
slouken@13274
   207
            }
slouken@13274
   208
slouken@13274
   209
            SDL_memcpy(init_packet, packet->data, packet->size);
slouken@13274
   210
            init_packet[2] = ctx->sequence++;
slouken@13274
   211
            if (hid_write(dev, init_packet, packet->size) != packet->size) {
slouken@13274
   212
                SDL_SetError("Couldn't write Xbox One initialization packet");
slouken@13274
   213
                return SDL_FALSE;
slouken@13274
   214
            }
slouken@13324
   215
slouken@13324
   216
            /* After the init we need to sync up the rumble sequence */
slouken@13324
   217
            if (packet->data == xboxone_fw2015_init) {
slouken@13324
   218
                for (j = 0; j < 255; ++j) {
slouken@13324
   219
                    if (hid_write(dev, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init)) != sizeof(xboxone_rumbleend_init)) {
slouken@13324
   220
                        SDL_SetError("Couldn't write Xbox One initialization packet");
slouken@13324
   221
                        return SDL_FALSE;
slouken@13324
   222
                    }
slouken@13324
   223
                }
slouken@13324
   224
            }
slouken@13274
   225
        }
slouken@13274
   226
    }
slouken@13274
   227
    return SDL_TRUE;
slouken@13274
   228
}
slouken@13274
   229
slouken@13274
   230
slouken@13274
   231
static SDL_bool
slouken@13160
   232
HIDAPI_DriverXboxOne_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, const char *name)
slouken@12088
   233
{
slouken@13248
   234
#ifdef __LINUX__
slouken@13255
   235
    if (IsBluetoothXboxOneController(vendor_id, product_id)) {
slouken@13248
   236
        /* We can't do rumble on this device, hid_write() fails, so don't try to open it here */
slouken@13248
   237
        return SDL_FALSE;
slouken@13248
   238
    }
slouken@13323
   239
    if (vendor_id == 0x24c6 && product_id == 0x541a) {
slouken@13324
   240
        /* The PowerA Mini controller, model 1240245-01, blocks while writing feature reports */
slouken@13323
   241
        return SDL_FALSE;
slouken@13323
   242
    }
slouken@13248
   243
#endif
slouken@13277
   244
    return (SDL_GetJoystickGameControllerType(vendor_id, product_id, name) == SDL_CONTROLLER_TYPE_XBOXONE);
slouken@12088
   245
}
slouken@12088
   246
slouken@12088
   247
static const char *
slouken@12088
   248
HIDAPI_DriverXboxOne_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
slouken@12088
   249
{
slouken@12117
   250
    return HIDAPI_XboxControllerName(vendor_id, product_id);
slouken@12088
   251
}
slouken@12088
   252
slouken@12088
   253
static SDL_bool
slouken@12896
   254
HIDAPI_DriverXboxOne_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
slouken@12088
   255
{
slouken@12088
   256
    SDL_DriverXboxOne_Context *ctx;
slouken@12088
   257
slouken@12088
   258
    ctx = (SDL_DriverXboxOne_Context *)SDL_calloc(1, sizeof(*ctx));
slouken@12088
   259
    if (!ctx) {
slouken@12088
   260
        SDL_OutOfMemory();
slouken@12088
   261
        return SDL_FALSE;
slouken@12088
   262
    }
slouken@12896
   263
    *context = ctx;
slouken@12088
   264
slouken@13274
   265
    ctx->vendor_id = vendor_id;
slouken@13274
   266
    ctx->product_id = product_id;
slouken@13274
   267
    ctx->start_time = SDL_GetTicks();
slouken@12088
   268
slouken@12088
   269
    /* Initialize the joystick capabilities */
slouken@12088
   270
    joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
slouken@12088
   271
    joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
slouken@12088
   272
    joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
slouken@12088
   273
slouken@12088
   274
    return SDL_TRUE;
slouken@12088
   275
}
slouken@12088
   276
slouken@12896
   277
static int
slouken@12896
   278
HIDAPI_DriverXboxOne_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
flibitijibibo@12641
   279
{
slouken@12896
   280
    SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
slouken@12088
   281
    Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF };
slouken@12088
   282
slouken@13274
   283
    if (!ctx->initialized) {
slouken@13274
   284
        return 0;
slouken@13274
   285
    }
slouken@13274
   286
slouken@13247
   287
    /* Magnitude is 1..100 so scale the 16-bit input here */
slouken@12088
   288
    rumble_packet[2] = ctx->sequence++;
slouken@13247
   289
    rumble_packet[8] = low_frequency_rumble / 655;
slouken@13247
   290
    rumble_packet[9] = high_frequency_rumble / 655;
slouken@12088
   291
slouken@12896
   292
    if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
slouken@12088
   293
        return SDL_SetError("Couldn't send rumble packet");
slouken@12088
   294
    }
slouken@12088
   295
slouken@12088
   296
    if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
slouken@12088
   297
        ctx->rumble_expiration = SDL_GetTicks() + duration_ms;
slouken@12088
   298
    } else {
slouken@12088
   299
        ctx->rumble_expiration = 0;
slouken@12088
   300
    }
slouken@12088
   301
    return 0;
slouken@12088
   302
}
slouken@12088
   303
slouken@12088
   304
static void
slouken@12088
   305
HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
slouken@12088
   306
{
slouken@12088
   307
    Sint16 axis;
slouken@12088
   308
slouken@12088
   309
    if (ctx->last_state[4] != data[4]) {
slouken@12088
   310
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[4] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   311
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[4] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   312
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[4] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   313
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[4] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   314
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[4] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   315
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[4] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   316
    }
slouken@12088
   317
slouken@12088
   318
    if (ctx->last_state[5] != data[5]) {
slouken@12088
   319
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[5] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   320
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[5] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   321
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[5] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   322
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[5] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   323
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   324
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   325
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[5] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   326
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[5] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   327
    }
slouken@12088
   328
slouken@12088
   329
    axis = ((int)*(Sint16*)(&data[6]) * 64) - 32768;
slouken@12161
   330
    if (axis == 32704) {
slouken@12161
   331
        axis = 32767;
slouken@12161
   332
    }
slouken@12088
   333
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
slouken@12088
   334
    axis = ((int)*(Sint16*)(&data[8]) * 64) - 32768;
slouken@12161
   335
    if (axis == 32704) {
slouken@12161
   336
        axis = 32767;
slouken@12161
   337
    }
slouken@12088
   338
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
slouken@12088
   339
    axis = *(Sint16*)(&data[10]);
slouken@12088
   340
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
slouken@12088
   341
    axis = *(Sint16*)(&data[12]);
slouken@12088
   342
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
slouken@12088
   343
    axis = *(Sint16*)(&data[14]);
slouken@12088
   344
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
slouken@12088
   345
    axis = *(Sint16*)(&data[16]);
slouken@12088
   346
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
slouken@12088
   347
slouken@12088
   348
    SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
slouken@12088
   349
}
slouken@12088
   350
slouken@12088
   351
static void
slouken@12088
   352
HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
slouken@12088
   353
{
slouken@12088
   354
    if (data[1] == 0x30) {
slouken@12088
   355
        /* The Xbox One S controller needs acks for mode reports */
slouken@12088
   356
        const Uint8 seqnum = data[2];
slouken@12088
   357
        const Uint8 ack[] = { 0x01, 0x20, seqnum, 0x09, 0x00, 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
slouken@12088
   358
        hid_write(dev, ack, sizeof(ack));
slouken@12088
   359
    }
slouken@12088
   360
slouken@12088
   361
    SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   362
}
slouken@12088
   363
slouken@12111
   364
static SDL_bool
slouken@12896
   365
HIDAPI_DriverXboxOne_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
slouken@12088
   366
{
slouken@12896
   367
    SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
slouken@12088
   368
    Uint8 data[USB_PACKET_LENGTH];
slouken@12088
   369
    int size;
slouken@12088
   370
slouken@13274
   371
    if (!ctx->initialized) {
slouken@13274
   372
        if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->start_time + CONTROLLER_INIT_DELAY_MS)) {
slouken@13274
   373
            if (!SendControllerInit(dev, ctx)) {
slouken@13274
   374
                return SDL_FALSE;
slouken@13274
   375
            }
slouken@13274
   376
            ctx->initialized = SDL_TRUE;
slouken@13274
   377
        }
slouken@13274
   378
    }
slouken@13274
   379
slouken@12896
   380
    while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
slouken@13247
   381
#ifdef DEBUG_XBOX_PROTOCOL
slouken@13247
   382
        SDL_Log("Xbox One packet: size = %d\n"
slouken@13247
   383
                "                 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n"
slouken@13247
   384
                "                 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n"
slouken@13247
   385
                "                 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n",
slouken@13247
   386
                    size,
slouken@13247
   387
                    data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
slouken@13247
   388
                    data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
slouken@13247
   389
                    data[16], data[17], data[18], data[19]);
slouken@13247
   390
#endif
slouken@12088
   391
        switch (data[0]) {
slouken@12088
   392
        case 0x20:
slouken@12896
   393
            HIDAPI_DriverXboxOne_HandleStatePacket(joystick, dev, ctx, data, size);
slouken@12088
   394
            break;
slouken@12088
   395
        case 0x07:
slouken@12896
   396
            HIDAPI_DriverXboxOne_HandleModePacket(joystick, dev, ctx, data, size);
slouken@12088
   397
            break;
slouken@12088
   398
        default:
slouken@12088
   399
#ifdef DEBUG_JOYSTICK
slouken@12088
   400
            SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
slouken@12088
   401
#endif
slouken@12088
   402
            break;
slouken@12088
   403
        }
slouken@12088
   404
    }
slouken@12088
   405
slouken@12088
   406
    if (ctx->rumble_expiration) {
slouken@12088
   407
        Uint32 now = SDL_GetTicks();
slouken@12088
   408
        if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
slouken@12896
   409
            HIDAPI_DriverXboxOne_Rumble(joystick, dev, context, 0, 0, 0);
slouken@12088
   410
        }
slouken@12088
   411
    }
slouken@12111
   412
slouken@12162
   413
    return (size >= 0);
slouken@12088
   414
}
slouken@12088
   415
slouken@12896
   416
static void
slouken@12896
   417
HIDAPI_DriverXboxOne_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
slouken@12896
   418
{
slouken@12896
   419
    SDL_free(context);
slouken@12896
   420
}
slouken@12896
   421
slouken@12088
   422
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
slouken@12088
   423
{
slouken@12119
   424
    SDL_HINT_JOYSTICK_HIDAPI_XBOX,
slouken@12088
   425
    SDL_TRUE,
slouken@12088
   426
    HIDAPI_DriverXboxOne_IsSupportedDevice,
slouken@12088
   427
    HIDAPI_DriverXboxOne_GetDeviceName,
slouken@12896
   428
    HIDAPI_DriverXboxOne_Init,
slouken@12896
   429
    HIDAPI_DriverXboxOne_Rumble,
slouken@12896
   430
    HIDAPI_DriverXboxOne_Update,
slouken@12896
   431
    HIDAPI_DriverXboxOne_Quit
slouken@12088
   432
};
slouken@12088
   433
slouken@12088
   434
#endif /* SDL_JOYSTICK_HIDAPI_XBOXONE */
slouken@12088
   435
slouken@12088
   436
#endif /* SDL_JOYSTICK_HIDAPI */
slouken@12088
   437
slouken@12088
   438
/* vi: set ts=4 sw=4 expandtab: */