src/joystick/hidapi/SDL_hidapi_xboxone.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 13 Mar 2020 19:00:24 -0700
changeset 13620 317366b2c172
parent 13606 6b0a65d1e16f
child 13633 340324c76848
permissions -rw-r--r--
Added support for the older Xbox One S Bluetooth controller report format
slouken@12088
     1
/*
slouken@12088
     2
  Simple DirectMedia Layer
slouken@13422
     3
  Copyright (C) 1997-2020 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@13481
    33
#include "SDL_hidapi_rumble.h"
slouken@12088
    34
slouken@12088
    35
slouken@12088
    36
#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
slouken@12088
    37
slouken@13420
    38
/* Define this if you want to log all packets from the controller */
slouken@13420
    39
/*#define DEBUG_XBOX_PROTOCOL*/
slouken@13420
    40
slouken@13274
    41
/* The amount of time to wait after hotplug to send controller init sequence */
slouken@13417
    42
#define CONTROLLER_INIT_DELAY_MS    1500 /* 475 for Xbox One S, 1275 for the PDP Battlefield 1 */
slouken@13274
    43
slouken@13417
    44
/* Connect controller */
slouken@13417
    45
static const Uint8 xboxone_init0[] = {
slouken@13417
    46
    0x04, 0x20, 0x00, 0x00
slouken@13300
    47
};
slouken@13432
    48
/* Initial ack */
slouken@13417
    49
static const Uint8 xboxone_init1[] = {
slouken@13417
    50
    0x01, 0x20, 0x01, 0x09, 0x00, 0x04, 0x20, 0x3a,
slouken@13417
    51
    0x00, 0x00, 0x00, 0x80, 0x00
slouken@13300
    52
};
slouken@13417
    53
/* Start controller - extended? */
slouken@13417
    54
static const Uint8 xboxone_init2[] = {
slouken@13417
    55
    0x05, 0x20, 0x00, 0x0F, 0x06, 0x00, 0x00, 0x00,
slouken@13300
    56
    0x00, 0x00, 0x00, 0x55, 0x53, 0x00, 0x00, 0x00,
slouken@13300
    57
    0x00, 0x00, 0x00
slouken@13300
    58
};
slouken@13417
    59
/* Start controller with input */
slouken@13417
    60
static const Uint8 xboxone_init3[] = {
slouken@13300
    61
    0x05, 0x20, 0x03, 0x01, 0x00
slouken@13300
    62
};
slouken@13417
    63
/* Enable LED */
slouken@13417
    64
static const Uint8 xboxone_init4[] = {
slouken@13417
    65
    0x0A, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
slouken@12088
    66
};
slouken@13417
    67
/* Start input reports? */
slouken@13417
    68
static const Uint8 xboxone_init5[] = {
slouken@13417
    69
    0x06, 0x20, 0x00, 0x02, 0x01, 0x00
slouken@13344
    70
};
slouken@13417
    71
/* Start rumble? */
slouken@13417
    72
static const Uint8 xboxone_init6[] = {
slouken@13417
    73
    0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
slouken@13417
    74
    0x00, 0x00, 0xFF, 0x00, 0xEB
slouken@12088
    75
};
slouken@12088
    76
slouken@12088
    77
/*
slouken@12088
    78
 * This specifies the selection of init packets that a gamepad
slouken@12088
    79
 * will be sent on init *and* the order in which they will be
slouken@12088
    80
 * sent. The correct sequence number will be added when the
slouken@12088
    81
 * packet is going to be sent.
slouken@12088
    82
 */
slouken@12088
    83
typedef struct {
slouken@12088
    84
    Uint16 vendor_id;
slouken@12088
    85
    Uint16 product_id;
slouken@13419
    86
    Uint16 exclude_vendor_id;
slouken@13419
    87
    Uint16 exclude_product_id;
slouken@12088
    88
    const Uint8 *data;
slouken@12088
    89
    int size;
slouken@13417
    90
    const Uint8 response[2];
slouken@12088
    91
} SDL_DriverXboxOne_InitPacket;
slouken@12088
    92
slouken@13300
    93
slouken@12088
    94
static const SDL_DriverXboxOne_InitPacket xboxone_init_packets[] = {
slouken@13419
    95
    { 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init0, sizeof(xboxone_init0), { 0x04, 0xf0 } },
slouken@13419
    96
    { 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init1, sizeof(xboxone_init1), { 0x04, 0xb0 } },
slouken@13419
    97
    { 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init2, sizeof(xboxone_init2), { 0x00, 0x00 } },
slouken@13419
    98
    { 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init3, sizeof(xboxone_init3), { 0x00, 0x00 } },
slouken@13419
    99
    { 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init4, sizeof(xboxone_init4), { 0x00, 0x00 } },
slouken@13420
   100
slouken@13419
   101
    /* These next packets are required for third party controllers (PowerA, PDP, HORI),
slouken@13420
   102
       but aren't the correct protocol for Microsoft Xbox controllers.
slouken@13419
   103
     */
slouken@13419
   104
    { 0x0000, 0x0000, 0x045e, 0x0000, xboxone_init5, sizeof(xboxone_init5), { 0x00, 0x00 } },
slouken@13419
   105
    { 0x0000, 0x0000, 0x045e, 0x0000, xboxone_init6, sizeof(xboxone_init6), { 0x00, 0x00 } },
slouken@12088
   106
};
slouken@12088
   107
slouken@13587
   108
typedef enum {
slouken@13587
   109
    XBOX_ONE_WIRELESS_PROTOCOL_UNKNOWN,
slouken@13587
   110
    XBOX_ONE_WIRELESS_PROTOCOL_V1,
slouken@13587
   111
    XBOX_ONE_WIRELESS_PROTOCOL_V2,
slouken@13587
   112
} SDL_XboxOneWirelessProtocol;
slouken@13587
   113
slouken@12088
   114
typedef struct {
slouken@13274
   115
    Uint16 vendor_id;
slouken@13274
   116
    Uint16 product_id;
slouken@13568
   117
    SDL_bool bluetooth;
slouken@13587
   118
    SDL_XboxOneWirelessProtocol wireless_protocol;
slouken@13568
   119
    SDL_bool initialized;
slouken@13274
   120
    Uint32 start_time;
slouken@12088
   121
    Uint8 sequence;
slouken@12088
   122
    Uint8 last_state[USB_PACKET_LENGTH];
slouken@13420
   123
    SDL_bool has_paddles;
slouken@12088
   124
} SDL_DriverXboxOne_Context;
slouken@12088
   125
slouken@12088
   126
slouken@13420
   127
#ifdef DEBUG_XBOX_PROTOCOL
slouken@13420
   128
static void
slouken@13420
   129
DumpPacket(const char *prefix, Uint8 *data, int size)
slouken@13420
   130
{
slouken@13420
   131
    int i;
slouken@13420
   132
    char buffer[5*USB_PACKET_LENGTH];
slouken@13420
   133
slouken@13420
   134
    SDL_snprintf(buffer, sizeof(buffer), prefix, size);
slouken@13420
   135
    for (i = 0; i < size; ++i) {
slouken@13420
   136
        if ((i % 8) == 0) {
slouken@13420
   137
            SDL_snprintf(&buffer[SDL_strlen(buffer)], sizeof(buffer) - SDL_strlen(buffer), "\n%.2d:      ", i);
slouken@13420
   138
        }
slouken@13420
   139
        SDL_snprintf(&buffer[SDL_strlen(buffer)], sizeof(buffer) - SDL_strlen(buffer), " 0x%.2x", data[i]);
slouken@13420
   140
    }
slouken@13420
   141
    SDL_strlcat(buffer, "\n", sizeof(buffer));
slouken@13420
   142
    SDL_Log("%s", buffer);
slouken@13420
   143
}
slouken@13420
   144
#endif /* DEBUG_XBOX_PROTOCOL */
slouken@13420
   145
slouken@12088
   146
static SDL_bool
slouken@13255
   147
IsBluetoothXboxOneController(Uint16 vendor_id, Uint16 product_id)
slouken@13255
   148
{
slouken@13255
   149
    /* Check to see if it's the Xbox One S or Xbox One Elite Series 2 in Bluetooth mode */
slouken@13303
   150
    if (vendor_id == USB_VENDOR_MICROSOFT) {
slouken@13408
   151
        if (product_id == USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH ||
slouken@13408
   152
            product_id == USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH ||
slouken@13408
   153
            product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH) {
slouken@13303
   154
            return SDL_TRUE;
slouken@13303
   155
        }
slouken@13255
   156
    }
slouken@13255
   157
    return SDL_FALSE;
slouken@13255
   158
}
slouken@13255
   159
slouken@13417
   160
static SDL_bool
slouken@13420
   161
ControllerHasPaddles(Uint16 vendor_id, Uint16 product_id)
slouken@13420
   162
{
slouken@13420
   163
    if (vendor_id == USB_VENDOR_MICROSOFT) {
slouken@13438
   164
        if (product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 ||
slouken@13438
   165
            product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2) {
slouken@13420
   166
            return SDL_TRUE;
slouken@13420
   167
        }
slouken@13420
   168
    }
slouken@13420
   169
    return SDL_FALSE;
slouken@13420
   170
}
slouken@13420
   171
slouken@13408
   172
/* Return true if this controller sends the 0x02 "waiting for init" packet */
slouken@13255
   173
static SDL_bool
slouken@13408
   174
ControllerSendsWaitingForInit(Uint16 vendor_id, Uint16 product_id)
slouken@13402
   175
{
slouken@13408
   176
    if (vendor_id == USB_VENDOR_HYPERKIN) {
slouken@13408
   177
        /* The Hyperkin controllers always send 0x02 when waiting for init,
slouken@13408
   178
           and the Hyperkin Duke plays an Xbox startup animation, so we want
slouken@13408
   179
           to make sure we don't send the init sequence if it isn't needed.
slouken@13408
   180
        */
slouken@13402
   181
        return SDL_TRUE;
slouken@13419
   182
    }
slouken@13419
   183
    if (vendor_id == USB_VENDOR_PDP) {
slouken@13419
   184
        /* The PDP Rock Candy (PID 0x0246) doesn't send 0x02 on Linux for some reason */
slouken@13408
   185
        return SDL_FALSE;
slouken@13402
   186
    }
slouken@13419
   187
slouken@13419
   188
    /* It doesn't hurt to reinit, especially if a driver has misconfigured the controller */
slouken@13419
   189
    /*return SDL_TRUE;*/
slouken@13419
   190
    return SDL_FALSE;
slouken@13402
   191
}
slouken@13402
   192
slouken@13402
   193
static SDL_bool
slouken@13481
   194
SendControllerInit(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
slouken@13274
   195
{
slouken@13274
   196
    Uint16 vendor_id = ctx->vendor_id;
slouken@13274
   197
    Uint16 product_id = ctx->product_id;
slouken@13568
   198
    int i;
slouken@13568
   199
    Uint8 init_packet[USB_PACKET_LENGTH];
slouken@13274
   200
slouken@13568
   201
    for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
slouken@13568
   202
        const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i];
slouken@13274
   203
slouken@13568
   204
        if (packet->vendor_id && (vendor_id != packet->vendor_id)) {
slouken@13568
   205
            continue;
slouken@13568
   206
        }
slouken@13274
   207
slouken@13568
   208
        if (packet->product_id && (product_id != packet->product_id)) {
slouken@13568
   209
            continue;
slouken@13568
   210
        }
slouken@13274
   211
slouken@13568
   212
        if (packet->exclude_vendor_id && (vendor_id == packet->exclude_vendor_id)) {
slouken@13568
   213
            continue;
slouken@13568
   214
        }
slouken@13419
   215
slouken@13568
   216
        if (packet->exclude_product_id && (product_id == packet->exclude_product_id)) {
slouken@13568
   217
            continue;
slouken@13568
   218
        }
slouken@13419
   219
slouken@13568
   220
        SDL_memcpy(init_packet, packet->data, packet->size);
slouken@13568
   221
        if (init_packet[0] != 0x01) {
slouken@13568
   222
            init_packet[2] = ctx->sequence++;
slouken@13568
   223
        }
slouken@13568
   224
        if (hid_write(device->dev, init_packet, packet->size) != packet->size) {
slouken@13568
   225
            SDL_SetError("Couldn't write Xbox One initialization packet");
slouken@13568
   226
            return SDL_FALSE;
slouken@13568
   227
        }
slouken@13324
   228
slouken@13568
   229
        if (packet->response[0]) {
slouken@13568
   230
            const Uint32 RESPONSE_TIMEOUT_MS = 50;
slouken@13568
   231
            Uint32 start = SDL_GetTicks();
slouken@13568
   232
            SDL_bool got_response = SDL_FALSE;
slouken@13417
   233
slouken@13568
   234
            while (!got_response && !SDL_TICKS_PASSED(SDL_GetTicks(), start + RESPONSE_TIMEOUT_MS)) {
slouken@13568
   235
                Uint8 data[USB_PACKET_LENGTH];
slouken@13568
   236
                int size;
slouken@13417
   237
slouken@13568
   238
                while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
slouken@13417
   239
#ifdef DEBUG_XBOX_PROTOCOL
slouken@13568
   240
                    DumpPacket("Xbox One INIT packet: size = %d", data, size);
slouken@13417
   241
#endif
slouken@13568
   242
                    if (size >= 2 && data[0] == packet->response[0] && data[1] == packet->response[1]) {
slouken@13568
   243
                        got_response = SDL_TRUE;
slouken@13324
   244
                    }
slouken@13324
   245
                }
slouken@13568
   246
            }
slouken@13417
   247
#ifdef DEBUG_XBOX_PROTOCOL
slouken@13568
   248
            SDL_Log("Init sequence %d got response: %s\n", i, got_response ? "TRUE" : "FALSE");
slouken@13417
   249
#endif
slouken@13274
   250
        }
slouken@13274
   251
    }
slouken@13274
   252
    return SDL_TRUE;
slouken@13274
   253
}
slouken@13274
   254
slouken@13274
   255
static SDL_bool
slouken@13431
   256
HIDAPI_DriverXboxOne_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
slouken@12088
   257
{
slouken@13248
   258
#ifdef __LINUX__
slouken@13568
   259
    if (vendor_id == USB_VENDOR_POWERA && product_id == 0x541a) {
slouken@13568
   260
        /* The PowerA Mini controller, model 1240245-01, blocks while writing feature reports */
slouken@13248
   261
        return SDL_FALSE;
slouken@13248
   262
    }
slouken@13568
   263
#endif
slouken@13568
   264
#ifdef __MACOSX__
slouken@13568
   265
    /* Wired Xbox One controllers are handled by the 360Controller driver */
slouken@13568
   266
    if (!IsBluetoothXboxOneController(vendor_id, product_id)) {
slouken@13323
   267
        return SDL_FALSE;
slouken@13323
   268
    }
slouken@13248
   269
#endif
slouken@13431
   270
    return (type == SDL_CONTROLLER_TYPE_XBOXONE);
slouken@12088
   271
}
slouken@12088
   272
slouken@12088
   273
static const char *
slouken@12088
   274
HIDAPI_DriverXboxOne_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
slouken@12088
   275
{
slouken@13330
   276
    return NULL;
slouken@12088
   277
}
slouken@12088
   278
slouken@12088
   279
static SDL_bool
slouken@13354
   280
HIDAPI_DriverXboxOne_InitDevice(SDL_HIDAPI_Device *device)
slouken@13354
   281
{
slouken@13354
   282
    return HIDAPI_JoystickConnected(device, NULL);
slouken@13354
   283
}
slouken@13354
   284
slouken@13369
   285
static int
slouken@13369
   286
HIDAPI_DriverXboxOne_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
slouken@13369
   287
{
slouken@13369
   288
    return -1;
slouken@13369
   289
}
slouken@13369
   290
slouken@13369
   291
static void
slouken@13369
   292
HIDAPI_DriverXboxOne_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
slouken@13369
   293
{
slouken@13369
   294
}
slouken@13369
   295
slouken@13354
   296
static SDL_bool
slouken@13354
   297
HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
slouken@12088
   298
{
slouken@12088
   299
    SDL_DriverXboxOne_Context *ctx;
slouken@12088
   300
slouken@12088
   301
    ctx = (SDL_DriverXboxOne_Context *)SDL_calloc(1, sizeof(*ctx));
slouken@12088
   302
    if (!ctx) {
slouken@12088
   303
        SDL_OutOfMemory();
slouken@12088
   304
        return SDL_FALSE;
slouken@12088
   305
    }
slouken@12088
   306
slouken@13354
   307
    device->dev = hid_open_path(device->path, 0);
slouken@13354
   308
    if (!device->dev) {
slouken@13354
   309
        SDL_free(ctx);
slouken@13354
   310
        SDL_SetError("Couldn't open %s", device->path);
slouken@13354
   311
        return SDL_FALSE;
slouken@13354
   312
    }
slouken@13354
   313
    device->context = ctx;
slouken@13354
   314
slouken@13354
   315
    ctx->vendor_id = device->vendor_id;
slouken@13354
   316
    ctx->product_id = device->product_id;
slouken@13568
   317
    ctx->bluetooth = IsBluetoothXboxOneController(device->vendor_id, device->product_id);
slouken@13568
   318
    ctx->initialized = ctx->bluetooth ? SDL_TRUE : SDL_FALSE;
slouken@13274
   319
    ctx->start_time = SDL_GetTicks();
slouken@13417
   320
    ctx->sequence = 1;
slouken@13420
   321
    ctx->has_paddles = ControllerHasPaddles(ctx->vendor_id, ctx->product_id);
slouken@12088
   322
slouken@12088
   323
    /* Initialize the joystick capabilities */
slouken@13420
   324
    joystick->nbuttons = ctx->has_paddles ? SDL_CONTROLLER_BUTTON_MAX : (SDL_CONTROLLER_BUTTON_MAX + 4);
slouken@12088
   325
    joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
slouken@12088
   326
    joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
slouken@12088
   327
slouken@12088
   328
    return SDL_TRUE;
slouken@12088
   329
}
slouken@12088
   330
slouken@12088
   331
static int
slouken@13480
   332
HIDAPI_DriverXboxOne_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
flibitijibibo@12641
   333
{
slouken@13568
   334
    SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
slouken@13568
   335
slouken@13568
   336
    if (ctx->bluetooth) {
slouken@13568
   337
        Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00 };
slouken@13568
   338
slouken@13568
   339
        rumble_packet[4] = (low_frequency_rumble >> 8);
slouken@13568
   340
        rumble_packet[5] = (high_frequency_rumble >> 8);
slouken@13490
   341
slouken@13568
   342
        if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
slouken@13568
   343
            return SDL_SetError("Couldn't send rumble packet");
slouken@13568
   344
        }
slouken@13568
   345
    } else {
slouken@13568
   346
        Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF };
slouken@12088
   347
slouken@13568
   348
        /* Magnitude is 1..100 so scale the 16-bit input here */
slouken@13568
   349
        rumble_packet[8] = low_frequency_rumble / 655;
slouken@13568
   350
        rumble_packet[9] = high_frequency_rumble / 655;
slouken@13568
   351
slouken@13568
   352
        if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
slouken@13568
   353
            return SDL_SetError("Couldn't send rumble packet");
slouken@13568
   354
        }
slouken@12088
   355
    }
slouken@12088
   356
    return 0;
slouken@12088
   357
}
slouken@12088
   358
slouken@12088
   359
static void
slouken@12088
   360
HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
slouken@12088
   361
{
slouken@12088
   362
    Sint16 axis;
slouken@12088
   363
slouken@12088
   364
    if (ctx->last_state[4] != data[4]) {
slouken@12088
   365
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[4] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   366
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[4] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   367
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[4] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   368
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[4] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   369
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[4] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   370
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[4] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   371
    }
slouken@12088
   372
slouken@12088
   373
    if (ctx->last_state[5] != data[5]) {
slouken@12088
   374
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[5] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   375
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[5] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   376
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[5] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   377
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[5] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   378
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   379
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   380
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[5] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   381
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[5] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   382
    }
slouken@12088
   383
slouken@13438
   384
    /* Xbox One S report is 18 bytes
slouken@13438
   385
       Xbox One Elite Series 1 report is 33 bytes, paddles in data[32], mode in data[32] & 0x10, both modes have mapped paddles by default
slouken@13438
   386
        Paddle bits:
slouken@13438
   387
            UL: 0x01 (A)    UR: 0x02 (B)
slouken@13438
   388
            LL: 0x04 (X)    LR: 0x08 (Y)
slouken@13438
   389
       Xbox One Elite Series 2 report is 38 bytes, paddles in data[18], mode in data[19], mode 0 has no mapped paddles by default
slouken@13438
   390
        Paddle bits:
slouken@13438
   391
            UL: 0x04 (A)    UR: 0x01 (B)
slouken@13438
   392
            LL: 0x08 (X)    LR: 0x02 (Y)
slouken@13438
   393
    */
slouken@13438
   394
    if (ctx->has_paddles && (size == 33 || size == 38)) {
slouken@13438
   395
        int paddle_index;
slouken@13438
   396
        int button1_bit;
slouken@13438
   397
        int button2_bit;
slouken@13438
   398
        int button3_bit;
slouken@13438
   399
        int button4_bit;
slouken@13438
   400
        SDL_bool paddles_mapped;
slouken@13438
   401
slouken@13438
   402
        if (size == 33) {
slouken@13438
   403
            /* XBox One Elite Series 1 */
slouken@13438
   404
            paddle_index = 32;
slouken@13438
   405
            button1_bit = 0x01;
slouken@13438
   406
            button2_bit = 0x02;
slouken@13438
   407
            button3_bit = 0x04;
slouken@13438
   408
            button4_bit = 0x08;
slouken@13438
   409
slouken@13438
   410
            /* The mapped controller state is at offset 4, the raw state is at offset 18, compare them to see if the paddles are mapped */
slouken@13438
   411
            paddles_mapped = (SDL_memcmp(&data[4], &data[18], 14) != 0);
slouken@13438
   412
slouken@13445
   413
        } else /* if (size == 38) */ {
slouken@13438
   414
            /* XBox One Elite Series 2 */
slouken@13438
   415
            paddle_index = 18;
slouken@13438
   416
            button1_bit = 0x04;
slouken@13438
   417
            button2_bit = 0x01;
slouken@13438
   418
            button3_bit = 0x08;
slouken@13438
   419
            button4_bit = 0x02;
slouken@13438
   420
            paddles_mapped = (data[19] != 0);
slouken@13420
   421
        }
slouken@13438
   422
#ifdef DEBUG_XBOX_PROTOCOL
slouken@13438
   423
        SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s\n",
slouken@13438
   424
            (data[paddle_index] & button1_bit) ? 1 : 0,
slouken@13438
   425
            (data[paddle_index] & button2_bit) ? 1 : 0,
slouken@13438
   426
            (data[paddle_index] & button3_bit) ? 1 : 0,
slouken@13438
   427
            (data[paddle_index] & button4_bit) ? 1 : 0,
slouken@13438
   428
            paddles_mapped ? "TRUE" : "FALSE"
slouken@13438
   429
        );
slouken@13438
   430
#endif
slouken@13438
   431
slouken@13438
   432
        if (paddles_mapped) {
slouken@13438
   433
            /* Respect that the paddles are being used for other controls and don't pass them on to the app */
slouken@13438
   434
            data[paddle_index] = 0;
slouken@13438
   435
        }
slouken@13438
   436
slouken@13438
   437
        if (ctx->last_state[paddle_index] != data[paddle_index]) {
slouken@13438
   438
            SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MAX+0, (data[paddle_index] & button1_bit) ? SDL_PRESSED : SDL_RELEASED);
slouken@13438
   439
            SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MAX+1, (data[paddle_index] & button2_bit) ? SDL_PRESSED : SDL_RELEASED);
slouken@13438
   440
            SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MAX+2, (data[paddle_index] & button3_bit) ? SDL_PRESSED : SDL_RELEASED);
slouken@13438
   441
            SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MAX+3, (data[paddle_index] & button4_bit) ? SDL_PRESSED : SDL_RELEASED);
slouken@13420
   442
        }
slouken@13420
   443
    }
slouken@13420
   444
slouken@12088
   445
    axis = ((int)*(Sint16*)(&data[6]) * 64) - 32768;
slouken@12161
   446
    if (axis == 32704) {
slouken@12161
   447
        axis = 32767;
slouken@12161
   448
    }
slouken@12088
   449
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
slouken@12088
   450
    axis = ((int)*(Sint16*)(&data[8]) * 64) - 32768;
slouken@12161
   451
    if (axis == 32704) {
slouken@12161
   452
        axis = 32767;
slouken@12161
   453
    }
slouken@12088
   454
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
slouken@12088
   455
    axis = *(Sint16*)(&data[10]);
slouken@12088
   456
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
slouken@12088
   457
    axis = *(Sint16*)(&data[12]);
slouken@12088
   458
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
slouken@12088
   459
    axis = *(Sint16*)(&data[14]);
slouken@12088
   460
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
slouken@12088
   461
    axis = *(Sint16*)(&data[16]);
slouken@12088
   462
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
slouken@12088
   463
slouken@12088
   464
    SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
slouken@12088
   465
}
slouken@12088
   466
slouken@12088
   467
static void
slouken@12088
   468
HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
slouken@12088
   469
{
slouken@12088
   470
    if (data[1] == 0x30) {
slouken@12088
   471
        /* The Xbox One S controller needs acks for mode reports */
slouken@12088
   472
        const Uint8 seqnum = data[2];
slouken@12088
   473
        const Uint8 ack[] = { 0x01, 0x20, seqnum, 0x09, 0x00, 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
slouken@12088
   474
        hid_write(dev, ack, sizeof(ack));
slouken@12088
   475
    }
slouken@12088
   476
slouken@12088
   477
    SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
slouken@12088
   478
}
slouken@12088
   479
slouken@13568
   480
static void
slouken@13620
   481
HIDAPI_DriverXboxOneBluetooth_HandleStatePacketV1(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
slouken@13620
   482
{
slouken@13620
   483
    Sint16 axis;
slouken@13620
   484
slouken@13620
   485
    if (ctx->last_state[14] != data[14]) {
slouken@13620
   486
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[14] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
slouken@13620
   487
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[14] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
slouken@13620
   488
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[14] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
slouken@13620
   489
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[14] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
slouken@13620
   490
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[14] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
slouken@13620
   491
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[14] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
slouken@13620
   492
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[14] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
slouken@13620
   493
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[14] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
slouken@13620
   494
    }
slouken@13620
   495
slouken@13620
   496
    if (ctx->last_state[15] != data[15]) {
slouken@13620
   497
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[15] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
slouken@13620
   498
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[15] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
slouken@13620
   499
    }
slouken@13620
   500
slouken@13620
   501
    if (ctx->last_state[13] != data[13]) {
slouken@13620
   502
        SDL_bool dpad_up = SDL_FALSE;
slouken@13620
   503
        SDL_bool dpad_down = SDL_FALSE;
slouken@13620
   504
        SDL_bool dpad_left = SDL_FALSE;
slouken@13620
   505
        SDL_bool dpad_right = SDL_FALSE;
slouken@13620
   506
slouken@13620
   507
        switch (data[13]) {
slouken@13620
   508
        case 1:
slouken@13620
   509
            dpad_up = SDL_TRUE;
slouken@13620
   510
            break;
slouken@13620
   511
        case 2:
slouken@13620
   512
            dpad_up = SDL_TRUE;
slouken@13620
   513
            dpad_right = SDL_TRUE;
slouken@13620
   514
            break;
slouken@13620
   515
        case 3:
slouken@13620
   516
            dpad_right = SDL_TRUE;
slouken@13620
   517
            break;
slouken@13620
   518
        case 4:
slouken@13620
   519
            dpad_right = SDL_TRUE;
slouken@13620
   520
            dpad_down = SDL_TRUE;
slouken@13620
   521
            break;
slouken@13620
   522
        case 5:
slouken@13620
   523
            dpad_down = SDL_TRUE;
slouken@13620
   524
            break;
slouken@13620
   525
        case 6:
slouken@13620
   526
            dpad_left = SDL_TRUE;
slouken@13620
   527
            dpad_down = SDL_TRUE;
slouken@13620
   528
            break;
slouken@13620
   529
        case 7:
slouken@13620
   530
            dpad_left = SDL_TRUE;
slouken@13620
   531
            break;
slouken@13620
   532
        case 8:
slouken@13620
   533
            dpad_up = SDL_TRUE;
slouken@13620
   534
            dpad_left = SDL_TRUE;
slouken@13620
   535
            break;
slouken@13620
   536
        default:
slouken@13620
   537
            break;
slouken@13620
   538
        }
slouken@13620
   539
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
slouken@13620
   540
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
slouken@13620
   541
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
slouken@13620
   542
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
slouken@13620
   543
    }
slouken@13620
   544
slouken@13620
   545
    axis = (int)*(Uint16*)(&data[1]) - 0x8000;
slouken@13620
   546
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
slouken@13620
   547
    axis = (int)*(Uint16*)(&data[3]) - 0x8000;
slouken@13620
   548
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
slouken@13620
   549
    axis = (int)*(Uint16*)(&data[5]) - 0x8000;
slouken@13620
   550
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
slouken@13620
   551
    axis = (int)*(Uint16*)(&data[7]) - 0x8000;
slouken@13620
   552
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
slouken@13620
   553
slouken@13620
   554
    axis = ((int)*(Sint16*)(&data[9]) * 64) - 32768;
slouken@13620
   555
    if (axis == 32704) {
slouken@13620
   556
        axis = 32767;
slouken@13620
   557
    }
slouken@13620
   558
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
slouken@13620
   559
slouken@13620
   560
    axis = ((int)*(Sint16*)(&data[11]) * 64) - 32768;
slouken@13620
   561
    if (axis == 32704) {
slouken@13620
   562
        axis = 32767;
slouken@13620
   563
    }
slouken@13620
   564
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
slouken@13620
   565
slouken@13620
   566
    SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
slouken@13620
   567
}
slouken@13620
   568
slouken@13620
   569
static void
slouken@13620
   570
HIDAPI_DriverXboxOneBluetooth_HandleStatePacketV2(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
slouken@13568
   571
{
slouken@13568
   572
    Sint16 axis;
slouken@13568
   573
slouken@13568
   574
    if (ctx->last_state[14] != data[14]) {
slouken@13568
   575
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[14] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
slouken@13568
   576
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[14] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
slouken@13568
   577
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[14] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
slouken@13568
   578
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[14] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
slouken@13568
   579
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[14] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
slouken@13568
   580
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[14] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
slouken@13568
   581
    }
slouken@13568
   582
slouken@13568
   583
    if (ctx->last_state[15] != data[15]) {
slouken@13568
   584
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[15] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
slouken@13568
   585
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[15] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
slouken@13568
   586
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[15] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
slouken@13587
   587
        if (ctx->wireless_protocol == XBOX_ONE_WIRELESS_PROTOCOL_UNKNOWN)
slouken@13587
   588
        {
slouken@13587
   589
            if (data[15] & 0x10) {
slouken@13587
   590
                ctx->wireless_protocol = XBOX_ONE_WIRELESS_PROTOCOL_V2;
slouken@13587
   591
            }
slouken@13587
   592
        }
slouken@13587
   593
        if (ctx->wireless_protocol == XBOX_ONE_WIRELESS_PROTOCOL_V2)
slouken@13587
   594
        {
slouken@13587
   595
            SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[15] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
slouken@13587
   596
        }
slouken@13568
   597
    }
slouken@13568
   598
slouken@13568
   599
    if (ctx->last_state[16] != data[16]) {
slouken@13568
   600
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
slouken@13568
   601
    }
slouken@13568
   602
slouken@13568
   603
    if (ctx->last_state[13] != data[13]) {
slouken@13568
   604
        SDL_bool dpad_up = SDL_FALSE;
slouken@13568
   605
        SDL_bool dpad_down = SDL_FALSE;
slouken@13568
   606
        SDL_bool dpad_left = SDL_FALSE;
slouken@13568
   607
        SDL_bool dpad_right = SDL_FALSE;
slouken@13568
   608
slouken@13568
   609
        switch (data[13]) {
slouken@13568
   610
        case 1:
slouken@13568
   611
            dpad_up = SDL_TRUE;
slouken@13568
   612
            break;
slouken@13568
   613
        case 2:
slouken@13568
   614
            dpad_up = SDL_TRUE;
slouken@13568
   615
            dpad_right = SDL_TRUE;
slouken@13568
   616
            break;
slouken@13568
   617
        case 3:
slouken@13568
   618
            dpad_right = SDL_TRUE;
slouken@13568
   619
            break;
slouken@13568
   620
        case 4:
slouken@13568
   621
            dpad_right = SDL_TRUE;
slouken@13568
   622
            dpad_down = SDL_TRUE;
slouken@13568
   623
            break;
slouken@13568
   624
        case 5:
slouken@13568
   625
            dpad_down = SDL_TRUE;
slouken@13568
   626
            break;
slouken@13568
   627
        case 6:
slouken@13568
   628
            dpad_left = SDL_TRUE;
slouken@13568
   629
            dpad_down = SDL_TRUE;
slouken@13568
   630
            break;
slouken@13568
   631
        case 7:
slouken@13568
   632
            dpad_left = SDL_TRUE;
slouken@13568
   633
            break;
slouken@13568
   634
        case 8:
slouken@13568
   635
            dpad_up = SDL_TRUE;
slouken@13568
   636
            dpad_left = SDL_TRUE;
slouken@13568
   637
            break;
slouken@13568
   638
        default:
slouken@13568
   639
            break;
slouken@13568
   640
        }
slouken@13568
   641
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
slouken@13568
   642
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
slouken@13568
   643
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
slouken@13568
   644
        SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
slouken@13568
   645
    }
slouken@13568
   646
slouken@13568
   647
    axis = (int)*(Uint16*)(&data[1]) - 0x8000;
slouken@13568
   648
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
slouken@13568
   649
    axis = (int)*(Uint16*)(&data[3]) - 0x8000;
slouken@13568
   650
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
slouken@13568
   651
    axis = (int)*(Uint16*)(&data[5]) - 0x8000;
slouken@13568
   652
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
slouken@13568
   653
    axis = (int)*(Uint16*)(&data[7]) - 0x8000;
slouken@13568
   654
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
slouken@13568
   655
slouken@13568
   656
    axis = ((int)*(Sint16*)(&data[9]) * 64) - 32768;
slouken@13568
   657
    if (axis == 32704) {
slouken@13568
   658
        axis = 32767;
slouken@13568
   659
    }
slouken@13568
   660
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
slouken@13568
   661
slouken@13568
   662
    axis = ((int)*(Sint16*)(&data[11]) * 64) - 32768;
slouken@13568
   663
    if (axis == 32704) {
slouken@13568
   664
        axis = 32767;
slouken@13568
   665
    }
slouken@13568
   666
    SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
slouken@13568
   667
slouken@13568
   668
    SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
slouken@13568
   669
}
slouken@13568
   670
slouken@13568
   671
static void
slouken@13568
   672
HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
slouken@13568
   673
{
slouken@13587
   674
    ctx->wireless_protocol = XBOX_ONE_WIRELESS_PROTOCOL_V1;
slouken@13568
   675
    SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
slouken@13568
   676
}
slouken@13568
   677
slouken@12111
   678
static SDL_bool
slouken@13354
   679
HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
slouken@12088
   680
{
slouken@13354
   681
    SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
slouken@13354
   682
    SDL_Joystick *joystick = NULL;
slouken@12088
   683
    Uint8 data[USB_PACKET_LENGTH];
slouken@12088
   684
    int size;
slouken@12088
   685
slouken@13354
   686
    if (device->num_joysticks > 0) {
slouken@13354
   687
        joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
slouken@13354
   688
    }
slouken@13354
   689
    if (!joystick) {
slouken@13354
   690
        return SDL_FALSE;
slouken@13354
   691
    }
slouken@13354
   692
slouken@13417
   693
    if (!ctx->initialized &&
slouken@13417
   694
        !ControllerSendsWaitingForInit(device->vendor_id, device->product_id)) {
slouken@13274
   695
        if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->start_time + CONTROLLER_INIT_DELAY_MS)) {
slouken@13481
   696
            if (!SendControllerInit(device, ctx)) {
slouken@13354
   697
                HIDAPI_JoystickDisconnected(device, joystick->instance_id);
slouken@13274
   698
                return SDL_FALSE;
slouken@13274
   699
            }
slouken@13274
   700
            ctx->initialized = SDL_TRUE;
slouken@13274
   701
        }
slouken@13274
   702
    }
slouken@13274
   703
slouken@13354
   704
    while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
slouken@13247
   705
#ifdef DEBUG_XBOX_PROTOCOL
slouken@13420
   706
        DumpPacket("Xbox One packet: size = %d", data, size);
slouken@13247
   707
#endif
slouken@13568
   708
        if (ctx->bluetooth) {
slouken@13568
   709
            switch (data[0]) {
slouken@13568
   710
            case 0x01:
slouken@13620
   711
                switch (size) {
slouken@13620
   712
                case 16:
slouken@13620
   713
                    HIDAPI_DriverXboxOneBluetooth_HandleStatePacketV1(joystick, device->dev, ctx, data, size);
slouken@13620
   714
                    break;
slouken@13620
   715
                case 17:
slouken@13620
   716
                    HIDAPI_DriverXboxOneBluetooth_HandleStatePacketV2(joystick, device->dev, ctx, data, size);
slouken@13620
   717
                    break;
slouken@13620
   718
                default:
slouken@13620
   719
                    break;
slouken@13620
   720
                }
slouken@13568
   721
                break;
slouken@13568
   722
            case 0x02:
slouken@13568
   723
                HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(joystick, device->dev, ctx, data, size);
slouken@13568
   724
                break;
slouken@13568
   725
            default:
slouken@13568
   726
#ifdef DEBUG_JOYSTICK
slouken@13568
   727
                SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
slouken@13417
   728
#endif
slouken@13568
   729
                break;
slouken@13402
   730
            }
slouken@13568
   731
        } else {
slouken@13568
   732
            switch (data[0]) {
slouken@13568
   733
            case 0x02:
slouken@13568
   734
                /* Controller is connected and waiting for initialization */
slouken@13568
   735
                if (!ctx->initialized) {
slouken@13568
   736
#ifdef DEBUG_XBOX_PROTOCOL
slouken@13568
   737
                    SDL_Log("Delay after init: %ums\n", SDL_GetTicks() - ctx->start_time);
slouken@13568
   738
#endif
slouken@13568
   739
                    if (!SendControllerInit(device, ctx)) {
slouken@13568
   740
                        HIDAPI_JoystickDisconnected(device, joystick->instance_id);
slouken@13568
   741
                        return SDL_FALSE;
slouken@13568
   742
                    }
slouken@13568
   743
                    ctx->initialized = SDL_TRUE;
slouken@13568
   744
                }
slouken@13568
   745
                break;
slouken@13568
   746
            case 0x03:
slouken@13568
   747
                /* Controller heartbeat */
slouken@13568
   748
                break;
slouken@13568
   749
            case 0x20:
slouken@13568
   750
                HIDAPI_DriverXboxOne_HandleStatePacket(joystick, device->dev, ctx, data, size);
slouken@13568
   751
                break;
slouken@13568
   752
            case 0x07:
slouken@13568
   753
                HIDAPI_DriverXboxOne_HandleModePacket(joystick, device->dev, ctx, data, size);
slouken@13568
   754
                break;
slouken@13568
   755
            default:
slouken@12088
   756
#ifdef DEBUG_JOYSTICK
slouken@13568
   757
                SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
slouken@12088
   758
#endif
slouken@13568
   759
                break;
slouken@13568
   760
            }
slouken@12088
   761
        }
slouken@12088
   762
    }
slouken@12088
   763
slouken@13354
   764
    if (size < 0) {
slouken@13354
   765
        /* Read error, device is disconnected */
slouken@13354
   766
        HIDAPI_JoystickDisconnected(device, joystick->instance_id);
slouken@13354
   767
    }
slouken@12162
   768
    return (size >= 0);
slouken@12088
   769
}
slouken@12088
   770
slouken@12896
   771
static void
slouken@13354
   772
HIDAPI_DriverXboxOne_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
slouken@12896
   773
{
slouken@13354
   774
    hid_close(device->dev);
slouken@13354
   775
    device->dev = NULL;
slouken@13354
   776
slouken@13354
   777
    SDL_free(device->context);
slouken@13354
   778
    device->context = NULL;
slouken@13354
   779
}
slouken@13354
   780
slouken@13354
   781
static void
slouken@13354
   782
HIDAPI_DriverXboxOne_FreeDevice(SDL_HIDAPI_Device *device)
slouken@13354
   783
{
slouken@12896
   784
}
slouken@12896
   785
slouken@12088
   786
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
slouken@12088
   787
{
slouken@12119
   788
    SDL_HINT_JOYSTICK_HIDAPI_XBOX,
slouken@12088
   789
    SDL_TRUE,
slouken@12088
   790
    HIDAPI_DriverXboxOne_IsSupportedDevice,
slouken@12088
   791
    HIDAPI_DriverXboxOne_GetDeviceName,
slouken@13354
   792
    HIDAPI_DriverXboxOne_InitDevice,
slouken@13369
   793
    HIDAPI_DriverXboxOne_GetDevicePlayerIndex,
slouken@13369
   794
    HIDAPI_DriverXboxOne_SetDevicePlayerIndex,
slouken@13354
   795
    HIDAPI_DriverXboxOne_UpdateDevice,
slouken@13354
   796
    HIDAPI_DriverXboxOne_OpenJoystick,
slouken@13354
   797
    HIDAPI_DriverXboxOne_RumbleJoystick,
slouken@13354
   798
    HIDAPI_DriverXboxOne_CloseJoystick,
slouken@13354
   799
    HIDAPI_DriverXboxOne_FreeDevice
slouken@12088
   800
};
slouken@12088
   801
slouken@12088
   802
#endif /* SDL_JOYSTICK_HIDAPI_XBOXONE */
slouken@12088
   803
slouken@12088
   804
#endif /* SDL_JOYSTICK_HIDAPI */
slouken@12088
   805
slouken@12088
   806
/* vi: set ts=4 sw=4 expandtab: */