#include "../../SDL_internal.h"
#ifdef SDL_JOYSTICK_HIDAPI
#include "SDL_events.h"
#include "SDL_timer.h"
#include "SDL_joystick.h"
#include "SDL_gamecontroller.h"
#include "../../SDL_hints_c.h"
#include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h"
#include "SDL_hidapi_rumble.h"
#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
#define CONTROLLER_NEGOTIATION_TIMEOUT_MS 300
#define CONTROLLER_PREPARE_INPUT_TIMEOUT_MS 50
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD -25058
static const Uint8 xboxone_init0[] = {
0x05, 0x20, 0x03, 0x01, 0x00
};
static const Uint8 xboxone_init1[] = {
0x0A, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
};
static const Uint8 xboxone_powera_rumble_init[] = {
0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
0x1D, 0x1D, 0xFF, 0x00, 0x00
};
static const Uint8 xboxone_init2[] = {
0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xEB
};
static const Uint8 security_passed_packet[] = {
0x06, 0x20, 0x00, 0x02, 0x01, 0x00
};
typedef struct {
Uint16 vendor_id;
Uint16 product_id;
Uint16 exclude_vendor_id;
Uint16 exclude_product_id;
const Uint8 *data;
int size;
const Uint8 response[2];
} SDL_DriverXboxOne_InitPacket;
static const SDL_DriverXboxOne_InitPacket xboxone_init_packets[] = {
{ 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init0, sizeof(xboxone_init0), { 0x00, 0x00 } },
{ 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init1, sizeof(xboxone_init1), { 0x00, 0x00 } },
{ 0x0e6f, 0x0000, 0x0000, 0x0000, security_passed_packet, sizeof(security_passed_packet), { 0x00, 0x00 } },
{ 0x24c6, 0x541a, 0x0000, 0x0000, xboxone_powera_rumble_init, sizeof(xboxone_powera_rumble_init), { 0x00, 0x00 } },
{ 0x24c6, 0x542a, 0x0000, 0x0000, xboxone_powera_rumble_init, sizeof(xboxone_powera_rumble_init), { 0x00, 0x00 } },
{ 0x24c6, 0x543a, 0x0000, 0x0000, xboxone_powera_rumble_init, sizeof(xboxone_powera_rumble_init), { 0x00, 0x00 } },
{ 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init2, sizeof(xboxone_init2), { 0x00, 0x00 } },
};
typedef enum {
XBOX_ONE_INIT_STATE_START_NEGOTIATING,
XBOX_ONE_INIT_STATE_NEGOTIATING,
XBOX_ONE_INIT_STATE_PREPARE_INPUT,
XBOX_ONE_INIT_STATE_COMPLETE,
} SDL_XboxOneInitState;
typedef enum {
XBOX_ONE_RUMBLE_STATE_IDLE,
XBOX_ONE_RUMBLE_STATE_QUEUED,
XBOX_ONE_RUMBLE_STATE_BUSY
} SDL_XboxOneRumbleState;
typedef struct {
SDL_HIDAPI_Device *device;
Uint16 vendor_id;
Uint16 product_id;
SDL_bool bluetooth;
SDL_XboxOneInitState init_state;
int init_packet;
Uint32 start_time;
Uint8 sequence;
Uint32 send_time;
SDL_bool has_guide_packet;
SDL_bool has_color_led;
SDL_bool has_paddles;
SDL_bool has_trigger_rumble;
SDL_bool has_share_button;
Uint8 low_frequency_rumble;
Uint8 high_frequency_rumble;
Uint8 left_trigger_rumble;
Uint8 right_trigger_rumble;
SDL_XboxOneRumbleState rumble_state;
Uint32 rumble_time;
SDL_bool rumble_pending;
Uint8 last_state[USB_PACKET_LENGTH];
} SDL_DriverXboxOne_Context;
static SDL_bool
ControllerHasColorLED(Uint16 vendor_id, Uint16 product_id)
{
return (vendor_id == USB_VENDOR_MICROSOFT && product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2);
}
static SDL_bool
ControllerHasPaddles(Uint16 vendor_id, Uint16 product_id)
{
return SDL_IsJoystickXboxOneElite(vendor_id, product_id);
}
static SDL_bool
ControllerHasTriggerRumble(Uint16 vendor_id, Uint16 product_id)
{
if (vendor_id == USB_VENDOR_MICROSOFT) {
return SDL_TRUE;
}
return SDL_FALSE;
}
static SDL_bool
ControllerHasShareButton(Uint16 vendor_id, Uint16 product_id)
{
return SDL_IsJoystickXboxSeriesX(vendor_id, product_id);
}
static int GetHomeLEDBrightness(const char *hint)
{
const int MAX_VALUE = 50;
int value = 20;
if (hint && *hint) {
if (SDL_strchr(hint, '.') != NULL) {
value = (int)(MAX_VALUE * SDL_atof(hint));
} else if (!SDL_GetStringBoolean(hint, SDL_TRUE)) {
value = 0;
}
}
return value;
}
static void SetHomeLED(SDL_DriverXboxOne_Context *ctx, int value)
{
Uint8 led_packet[] = { 0x0A, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00 };
if (value > 0) {
led_packet[5] = 0x01;
led_packet[6] = (Uint8)value;
}
SDL_HIDAPI_SendRumble(ctx->device, led_packet, sizeof(led_packet));
}
static void SDLCALL SDL_HomeLEDHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)userdata;
if (hint && *hint) {
SetHomeLED(ctx, GetHomeLEDBrightness(hint));
}
}
static void
SetInitState(SDL_DriverXboxOne_Context *ctx, SDL_XboxOneInitState state)
{
#ifdef DEBUG_JOYSTICK
SDL_Log("Setting init state %d\n", state);
#endif
ctx->init_state = state;
}
static void
SendAckIfNeeded(SDL_HIDAPI_Device *device, Uint8 *data, int size)
{
#if defined(__WIN32__) || defined(__WINGDK__)
#else
if ((data[1] & 0x30) == 0x30) {
Uint8 ack_packet[] = { 0x01, 0x20, 0x00, 0x09, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
ack_packet[2] = data[2];
ack_packet[5] = data[0];
ack_packet[7] = data[3];
if (data[0] == 0x04 && data[1] == 0xF0) {
ack_packet[11] = 0x80;
}
#ifdef DEBUG_XBOX_PROTOCOL
HIDAPI_DumpPacket("Xbox One sending ACK packet: size = %d", ack_packet, sizeof(ack_packet));
#endif
if (SDL_HIDAPI_LockRumble() < 0 ||
SDL_HIDAPI_SendRumbleAndUnlock(device, ack_packet, sizeof(ack_packet)) != sizeof(ack_packet)) {
SDL_SetError("Couldn't send ack packet");
}
}
#endif
}
#if 0#endif
static SDL_bool
ControllerNeedsNegotiation(SDL_DriverXboxOne_Context *ctx)
{
if (ctx->vendor_id == USB_VENDOR_PDP && ctx->product_id == 0x0246) {
return SDL_TRUE;
}
return SDL_FALSE;
}
static SDL_bool
SendControllerInit(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
{
Uint16 vendor_id = ctx->vendor_id;
Uint16 product_id = ctx->product_id;
Uint8 init_packet[USB_PACKET_LENGTH];
for ( ; ctx->init_packet < SDL_arraysize(xboxone_init_packets); ++ctx->init_packet) {
const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[ctx->init_packet];
if (packet->vendor_id && (vendor_id != packet->vendor_id)) {
continue;
}
if (packet->product_id && (product_id != packet->product_id)) {
continue;
}
if (packet->exclude_vendor_id && (vendor_id == packet->exclude_vendor_id)) {
continue;
}
if (packet->exclude_product_id && (product_id == packet->exclude_product_id)) {
continue;
}
SDL_memcpy(init_packet, packet->data, packet->size);
if (init_packet[0] != 0x01) {
init_packet[2] = ctx->sequence++;
}
if (init_packet[0] == 0x0A) {
int brightness = GetHomeLEDBrightness(SDL_GetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED));
init_packet[5] = (brightness > 0) ? 0x01 : 0x00;
init_packet[6] = (Uint8)brightness;
}
#ifdef DEBUG_XBOX_PROTOCOL
HIDAPI_DumpPacket("Xbox One sending INIT packet: size = %d", init_packet, packet->size);
#endif
ctx->send_time = SDL_GetTicks();
if (SDL_HIDAPI_LockRumble() < 0 ||
SDL_HIDAPI_SendRumbleAndUnlock(device, init_packet, packet->size) != packet->size) {
SDL_SetError("Couldn't write Xbox One initialization packet");
return SDL_FALSE;
}
if (packet->response[0]) {
return SDL_TRUE;
}
if (packet->data == xboxone_powera_rumble_init) {
SDL_Delay(10);
}
}
SetInitState(ctx, XBOX_ONE_INIT_STATE_PREPARE_INPUT);
return SDL_TRUE;
}
static void
HIDAPI_DriverXboxOne_RegisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE, callback, userdata);
}
static void
HIDAPI_DriverXboxOne_UnregisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX, callback, userdata);
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE, callback, userdata);
}
static SDL_bool
HIDAPI_DriverXboxOne_IsEnabled(void)
{
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE,
SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX,
SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
SDL_HIDAPI_DEFAULT)));
}
static SDL_bool
HIDAPI_DriverXboxOne_IsSupportedDevice(SDL_HIDAPI_Device *device, 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)
{
#ifdef __MACOSX__
if (!SDL_IsJoystickBluetoothXboxOne(vendor_id, product_id)) {
return SDL_FALSE;
}
#endif
return (type == SDL_CONTROLLER_TYPE_XBOXONE) ? SDL_TRUE : SDL_FALSE;
}
static SDL_bool
HIDAPI_DriverXboxOne_InitDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverXboxOne_Context *ctx;
ctx = (SDL_DriverXboxOne_Context *)SDL_calloc(1, sizeof(*ctx));
if (!ctx) {
SDL_OutOfMemory();
return SDL_FALSE;
}
ctx->device = device;
device->context = ctx;
ctx->vendor_id = device->vendor_id;
ctx->product_id = device->product_id;
ctx->bluetooth = SDL_IsJoystickBluetoothXboxOne(device->vendor_id, device->product_id);
ctx->start_time = SDL_GetTicks();
ctx->sequence = 1;
ctx->has_color_led = ControllerHasColorLED(ctx->vendor_id, ctx->product_id);
ctx->has_paddles = ControllerHasPaddles(ctx->vendor_id, ctx->product_id);
ctx->has_trigger_rumble = ControllerHasTriggerRumble(ctx->vendor_id, ctx->product_id);
ctx->has_share_button = ControllerHasShareButton(ctx->vendor_id, ctx->product_id);
if (ControllerNeedsNegotiation(ctx)) {
ctx->init_state = XBOX_ONE_INIT_STATE_START_NEGOTIATING;
} else {
ctx->init_state = XBOX_ONE_INIT_STATE_COMPLETE;
}
#ifdef DEBUG_JOYSTICK
SDL_Log("Controller version: %d (0x%.4x)\n", device->version, device->version);
#endif
device->type = SDL_CONTROLLER_TYPE_XBOXONE;
return HIDAPI_JoystickConnected(device, NULL);
}
static int
HIDAPI_DriverXboxOne_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
{
return -1;
}
static void
HIDAPI_DriverXboxOne_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
{
}
static SDL_bool
HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
ctx->low_frequency_rumble = 0;
ctx->high_frequency_rumble = 0;
ctx->left_trigger_rumble = 0;
ctx->right_trigger_rumble = 0;
ctx->rumble_state = XBOX_ONE_RUMBLE_STATE_IDLE;
ctx->rumble_time = 0;
ctx->rumble_pending = SDL_FALSE;
SDL_zeroa(ctx->last_state);
joystick->nbuttons = 15;
if (ctx->has_share_button) {
joystick->nbuttons += 1;
}
if (ctx->has_paddles) {
joystick->nbuttons += 4;
}
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
if (!ctx->bluetooth) {
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
}
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED,
SDL_HomeLEDHintChanged, ctx);
return SDL_TRUE;
}
static void
HIDAPI_DriverXboxOne_RumbleSent(void *userdata)
{
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)userdata;
ctx->rumble_time = SDL_GetTicks();
}
static int
HIDAPI_DriverXboxOne_UpdateRumble(SDL_HIDAPI_Device *device)
{
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
if (ctx->rumble_state == XBOX_ONE_RUMBLE_STATE_QUEUED) {
if (ctx->rumble_time) {
ctx->rumble_state = XBOX_ONE_RUMBLE_STATE_BUSY;
}
}
if (ctx->rumble_state == XBOX_ONE_RUMBLE_STATE_BUSY) {
const Uint32 RUMBLE_BUSY_TIME_MS = ctx->bluetooth ? 50 : 10;
if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->rumble_time + RUMBLE_BUSY_TIME_MS)) {
ctx->rumble_time = 0;
ctx->rumble_state = XBOX_ONE_RUMBLE_STATE_IDLE;
}
}
if (!ctx->rumble_pending) {
return 0;
}
if (ctx->rumble_state != XBOX_ONE_RUMBLE_STATE_IDLE) {
return 0;
}
ctx->rumble_pending = SDL_FALSE;
if (SDL_HIDAPI_LockRumble() < 0) {
return -1;
}
if (ctx->bluetooth) {
Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB };
rumble_packet[2] = ctx->left_trigger_rumble;
rumble_packet[3] = ctx->right_trigger_rumble;
rumble_packet[4] = ctx->low_frequency_rumble;
rumble_packet[5] = ctx->high_frequency_rumble;
if (SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(device, rumble_packet, sizeof(rumble_packet), HIDAPI_DriverXboxOne_RumbleSent, ctx) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
} else {
Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB };
rumble_packet[6] = ctx->left_trigger_rumble;
rumble_packet[7] = ctx->right_trigger_rumble;
rumble_packet[8] = ctx->low_frequency_rumble;
rumble_packet[9] = ctx->high_frequency_rumble;
if (SDL_HIDAPI_SendRumbleWithCallbackAndUnlock(device, rumble_packet, sizeof(rumble_packet), HIDAPI_DriverXboxOne_RumbleSent, ctx) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
}
ctx->rumble_state = XBOX_ONE_RUMBLE_STATE_QUEUED;
return 0;
}
static int
HIDAPI_DriverXboxOne_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
ctx->low_frequency_rumble = low_frequency_rumble / 655;
ctx->high_frequency_rumble = high_frequency_rumble / 655;
ctx->rumble_pending = SDL_TRUE;
return HIDAPI_DriverXboxOne_UpdateRumble(device);
}
static int
HIDAPI_DriverXboxOne_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
if (!ctx->has_trigger_rumble) {
return SDL_Unsupported();
}
ctx->left_trigger_rumble = left_rumble / 655;
ctx->right_trigger_rumble = right_rumble / 655;
ctx->rumble_pending = SDL_TRUE;
return HIDAPI_DriverXboxOne_UpdateRumble(device);
}
static Uint32
HIDAPI_DriverXboxOne_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
Uint32 result = 0;
result |= SDL_JOYCAP_RUMBLE;
if (ctx->has_trigger_rumble) {
result |= SDL_JOYCAP_RUMBLE_TRIGGERS;
}
if (ctx->has_color_led) {
result |= SDL_JOYCAP_LED;
}
return result;
}
static int
HIDAPI_DriverXboxOne_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
if (ctx->has_color_led) {
Uint8 led_packet[] = { 0x0E, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };
led_packet[5] = 0x00;
led_packet[6] = red;
led_packet[7] = green;
led_packet[8] = blue;
if (SDL_HIDAPI_SendRumble(device, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
return SDL_SetError("Couldn't send LED packet");
}
return 0;
} else {
return SDL_Unsupported();
}
}
static int
HIDAPI_DriverXboxOne_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static int
HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
}
static void
HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
Sint16 axis;
if (ctx->last_state[4] != data[4]) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[4] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[4] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[4] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[4] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[4] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[4] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[5] != data[5]) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[5] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[5] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[5] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[5] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
if (ctx->vendor_id == USB_VENDOR_RAZER && ctx->product_id == USB_PRODUCT_RAZER_ATROX) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
} else {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
}
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[5] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[5] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->has_share_button) {
if (size < 48) {
if (ctx->last_state[18] != data[18]) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data[18] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
}
} else if (size == 48) {
if (ctx->last_state[22] != data[22]) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data[22] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
}
} else if (size == 50) {
if (ctx->last_state[32] != data[32]) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data[32] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
}
}
}
if (ctx->has_paddles && (size == 33 || size == 38 || size == 50)) {
int paddle_index;
int button1_bit;
int button2_bit;
int button3_bit;
int button4_bit;
SDL_bool paddles_mapped;
if (size == 33) {
paddle_index = 32;
button1_bit = 0x02;
button2_bit = 0x08;
button3_bit = 0x01;
button4_bit = 0x04;
paddles_mapped = (SDL_memcmp(&data[4], &data[18], 2) != 0);
} else if (size == 38) {
paddle_index = 18;
button1_bit = 0x01;
button2_bit = 0x02;
button3_bit = 0x04;
button4_bit = 0x08;
paddles_mapped = (data[19] != 0);
} else {
paddle_index = 22;
button1_bit = 0x01;
button2_bit = 0x02;
button3_bit = 0x04;
button4_bit = 0x08;
paddles_mapped = (data[23] != 0);
}
#ifdef DEBUG_XBOX_PROTOCOL
SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s\n",
(data[paddle_index] & button1_bit) ? 1 : 0,
(data[paddle_index] & button2_bit) ? 1 : 0,
(data[paddle_index] & button3_bit) ? 1 : 0,
(data[paddle_index] & button4_bit) ? 1 : 0,
paddles_mapped ? "TRUE" : "FALSE"
);
#endif
if (paddles_mapped) {
data[paddle_index] = 0;
}
if (ctx->last_state[paddle_index] != data[paddle_index]) {
int nButton = SDL_CONTROLLER_BUTTON_MISC1 + ctx->has_share_button;
SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button1_bit) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button2_bit) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button3_bit) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button4_bit) ? SDL_PRESSED : SDL_RELEASED);
}
}
axis = ((int)SDL_SwapLE16(*(Sint16*)(&data[6])) * 64) - 32768;
if (axis == 32704) {
axis = 32767;
}
if (axis == -32768 && size == 30 && (data[22] & 0x80) != 0) {
axis = 32767;
}
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
axis = ((int)SDL_SwapLE16(*(Sint16*)(&data[8])) * 64) - 32768;
if (axis == -32768 && size == 30 && (data[22] & 0x40) != 0) {
axis = 32767;
}
if (axis == 32704) {
axis = 32767;
}
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
axis = SDL_SwapLE16(*(Sint16*)(&data[10]));
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
axis = SDL_SwapLE16(*(Sint16*)(&data[12]));
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
axis = SDL_SwapLE16(*(Sint16*)(&data[14]));
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
axis = SDL_SwapLE16(*(Sint16*)(&data[16]));
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
static void
HIDAPI_DriverXboxOne_HandleStatusPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
if (ctx->init_state < XBOX_ONE_INIT_STATE_COMPLETE) {
SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
}
}
static void
HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
}
static void
HIDAPI_DriverXboxOneBluetooth_HandleButtons16(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
if (ctx->last_state[14] != data[14]) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[14] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[14] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[14] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[14] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[14] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[14] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[14] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[14] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[15] != data[15]) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[15] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[15] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
}
}
static void
HIDAPI_DriverXboxOneBluetooth_HandleButtons(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
if (ctx->last_state[14] != data[14]) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[14] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[14] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[14] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[14] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[14] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[14] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->last_state[15] != data[15]) {
if (!ctx->has_guide_packet) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[15] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
}
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[15] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[15] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[15] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->has_share_button) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[15] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
} else {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, ((data[15] & 0x04) || (data[16] & 0x01)) ? SDL_PRESSED : SDL_RELEASED);
}
if (ctx->has_paddles && (size == 39 || size == 55)) {
int paddle_index;
int button1_bit;
int button2_bit;
int button3_bit;
int button4_bit;
SDL_bool paddles_mapped;
if (size == 55) {
paddle_index = 33;
button1_bit = 0x01;
button2_bit = 0x02;
button3_bit = 0x04;
button4_bit = 0x08;
paddles_mapped = (data[35] != 0);
} else {
paddle_index = 17;
button1_bit = 0x01;
button2_bit = 0x02;
button3_bit = 0x04;
button4_bit = 0x08;
paddles_mapped = (data[19] != 0);
}
#ifdef DEBUG_XBOX_PROTOCOL
SDL_Log(">>> Paddles: %d,%d,%d,%d mapped = %s\n",
(data[paddle_index] & button1_bit) ? 1 : 0,
(data[paddle_index] & button2_bit) ? 1 : 0,
(data[paddle_index] & button3_bit) ? 1 : 0,
(data[paddle_index] & button4_bit) ? 1 : 0,
paddles_mapped ? "TRUE" : "FALSE"
);
#endif
if (paddles_mapped) {
data[paddle_index] = 0;
}
if (ctx->last_state[paddle_index] != data[paddle_index]) {
int nButton = SDL_CONTROLLER_BUTTON_MISC1;
SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button1_bit) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button2_bit) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button3_bit) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, nButton++, (data[paddle_index] & button4_bit) ? SDL_PRESSED : SDL_RELEASED);
}
}
}
static void
HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
Sint16 axis;
if (size == 16) {
HIDAPI_DriverXboxOneBluetooth_HandleButtons16(joystick, ctx, data, size);
} else if (size > 16) {
HIDAPI_DriverXboxOneBluetooth_HandleButtons(joystick, ctx, data, size);
} else {
#ifdef DEBUG_XBOX_PROTOCOL
SDL_Log("Unknown Bluetooth state packet format\n");
#endif
return;
}
if (ctx->last_state[13] != data[13]) {
SDL_bool dpad_up = SDL_FALSE;
SDL_bool dpad_down = SDL_FALSE;
SDL_bool dpad_left = SDL_FALSE;
SDL_bool dpad_right = SDL_FALSE;
switch (data[13]) {
case 1:
dpad_up = SDL_TRUE;
break;
case 2:
dpad_up = SDL_TRUE;
dpad_right = SDL_TRUE;
break;
case 3:
dpad_right = SDL_TRUE;
break;
case 4:
dpad_right = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 5:
dpad_down = SDL_TRUE;
break;
case 6:
dpad_left = SDL_TRUE;
dpad_down = SDL_TRUE;
break;
case 7:
dpad_left = SDL_TRUE;
break;
case 8:
dpad_up = SDL_TRUE;
dpad_left = SDL_TRUE;
break;
default:
break;
}
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
}
axis = ((int)SDL_SwapLE16(*(Sint16*)(&data[9])) * 64) - 32768;
if (axis == 32704) {
axis = 32767;
}
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
axis = ((int)SDL_SwapLE16(*(Sint16*)(&data[11])) * 64) - 32768;
if (axis == 32704) {
axis = 32767;
}
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
axis = (int)SDL_SwapLE16(*(Uint16*)(&data[1])) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
axis = (int)SDL_SwapLE16(*(Uint16*)(&data[3])) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
axis = (int)SDL_SwapLE16(*(Uint16*)(&data[5])) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
axis = (int)SDL_SwapLE16(*(Uint16*)(&data[7])) - 0x8000;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
static void
HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
ctx->has_guide_packet = SDL_TRUE;
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
}
static void
HIDAPI_DriverXboxOneBluetooth_HandleBatteryPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
Uint8 flags = data[1];
SDL_bool on_usb = (((flags & 0x0C) >> 2) == 0);
if (on_usb) {
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_WIRED);
} else {
switch ((flags & 0x03)) {
case 0:
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_LOW);
break;
case 1:
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_MEDIUM);
break;
default:
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_FULL);
break;
}
}
}
#ifdef SET_SERIAL_AFTER_OPEN
static void
HIDAPI_DriverXboxOne_HandleSerialIDPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
char serial[ 29 ];
int i;
for (i = 0; i < 14; ++i) {
SDL_uitoa( data[6 + i], &serial[i * 2], 16 );
}
serial[i * 2] = '\0';
if (!joystick->serial || SDL_strcmp(joystick->serial, serial) != 0) {
#ifdef DEBUG_JOYSTICK
SDL_Log("Setting serial number to %s\n", serial);
#endif
joystick->serial = SDL_strdup(serial);
}
}
#endif
static SDL_bool
HIDAPI_DriverXboxOne_UpdateInitState(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
{
SDL_XboxOneInitState prev_state;
do
{
prev_state = ctx->init_state;
switch (ctx->init_state) {
case XBOX_ONE_INIT_STATE_START_NEGOTIATING:
#if defined(__WIN32__) || defined(__WINGDK__)
SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
#else
SetInitState(ctx, XBOX_ONE_INIT_STATE_NEGOTIATING);
ctx->init_packet = 0;
if (!SendControllerInit(device, ctx)) {
return SDL_FALSE;
}
#endif
break;
case XBOX_ONE_INIT_STATE_NEGOTIATING:
if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->send_time + CONTROLLER_NEGOTIATION_TIMEOUT_MS)) {
#ifdef DEBUG_JOYSTICK
SDL_Log("Init sequence %d timed out after %u ms\n", ctx->init_packet, (SDL_GetTicks() - ctx->send_time));
#endif
++ctx->init_packet;
if (!SendControllerInit(device, ctx)) {
return SDL_FALSE;
}
}
break;
case XBOX_ONE_INIT_STATE_PREPARE_INPUT:
if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->send_time + CONTROLLER_PREPARE_INPUT_TIMEOUT_MS)) {
#ifdef DEBUG_JOYSTICK
SDL_Log("Prepare input complete after %u ms\n", (SDL_GetTicks() - ctx->send_time));
#endif
SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
}
break;
case XBOX_ONE_INIT_STATE_COMPLETE:
break;
}
} while (ctx->init_state != prev_state);
return SDL_TRUE;
}
static SDL_bool
HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
{
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
SDL_Joystick *joystick = NULL;
Uint8 data[USB_PACKET_LENGTH];
int size;
if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
} else {
return SDL_FALSE;
}
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
#ifdef DEBUG_XBOX_PROTOCOL
HIDAPI_DumpPacket("Xbox One packet: size = %d", data, size);
#endif
if (ctx->bluetooth) {
switch (data[0]) {
case 0x01:
if (!joystick) {
break;
}
if (size >= 16) {
HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(joystick, ctx, data, size);
} else {
#ifdef DEBUG_JOYSTICK
SDL_Log("Unknown Xbox One Bluetooth packet size: %d\n", size);
#endif
}
break;
case 0x02:
if (!joystick) {
break;
}
HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(joystick, ctx, data, size);
break;
case 0x04:
if (!joystick) {
break;
}
HIDAPI_DriverXboxOneBluetooth_HandleBatteryPacket(joystick, ctx, data, size);
break;
default:
#ifdef DEBUG_JOYSTICK
SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
#endif
break;
}
} else {
switch (data[0]) {
case 0x01:
break;
case 0x02:
if (data[1] == 0x20) {
#ifdef DEBUG_JOYSTICK
SDL_Log("Controller announce after %u ms\n", (SDL_GetTicks() - ctx->start_time));
#endif
SetInitState(ctx, XBOX_ONE_INIT_STATE_START_NEGOTIATING);
} else {
}
break;
case 0x03:
if (!joystick) {
}
HIDAPI_DriverXboxOne_HandleStatusPacket(joystick, ctx, data, size);
break;
case 0x04:
break;
case 0x06:
break;
case 0x07:
if (!joystick) {
break;
}
HIDAPI_DriverXboxOne_HandleModePacket(joystick, ctx, data, size);
break;
case 0x1E:
if (!joystick) {
break;
}
#ifdef SET_SERIAL_AFTER_OPEN
if (size == 20 && data[3] == 0x10) {
HIDAPI_DriverXboxOne_HandleSerialIDPacket(joystick, ctx, data, size);
}
#endif
break;
case 0x20:
if (ctx->init_state < XBOX_ONE_INIT_STATE_COMPLETE) {
SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
#ifdef DEBUG_JOYSTICK
SDL_Log("Controller ignoring spurious input\n");
#endif
break;
}
if (!joystick) {
break;
}
HIDAPI_DriverXboxOne_HandleStatePacket(joystick, ctx, data, size);
break;
default:
#ifdef DEBUG_JOYSTICK
SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
#endif
break;
}
SendAckIfNeeded(device, data, size);
if (ctx->init_state == XBOX_ONE_INIT_STATE_NEGOTIATING) {
const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[ctx->init_packet];
if (size >= 4 && data[0] == packet->response[0] && data[1] == packet->response[1]) {
#ifdef DEBUG_JOYSTICK
SDL_Log("Init sequence %d got response after %u ms\n", ctx->init_packet, (SDL_GetTicks() - ctx->send_time));
#endif
++ctx->init_packet;
SendControllerInit(device, ctx);
}
}
}
}
HIDAPI_DriverXboxOne_UpdateInitState(device, ctx);
HIDAPI_DriverXboxOne_UpdateRumble(device);
if (size < 0) {
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
return (size >= 0);
}
static void
HIDAPI_DriverXboxOne_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED,
SDL_HomeLEDHintChanged, ctx);
}
static void
HIDAPI_DriverXboxOne_FreeDevice(SDL_HIDAPI_Device *device)
{
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
{
SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE,
SDL_TRUE,
HIDAPI_DriverXboxOne_RegisterHints,
HIDAPI_DriverXboxOne_UnregisterHints,
HIDAPI_DriverXboxOne_IsEnabled,
HIDAPI_DriverXboxOne_IsSupportedDevice,
HIDAPI_DriverXboxOne_InitDevice,
HIDAPI_DriverXboxOne_GetDevicePlayerIndex,
HIDAPI_DriverXboxOne_SetDevicePlayerIndex,
HIDAPI_DriverXboxOne_UpdateDevice,
HIDAPI_DriverXboxOne_OpenJoystick,
HIDAPI_DriverXboxOne_RumbleJoystick,
HIDAPI_DriverXboxOne_RumbleJoystickTriggers,
HIDAPI_DriverXboxOne_GetJoystickCapabilities,
HIDAPI_DriverXboxOne_SetJoystickLED,
HIDAPI_DriverXboxOne_SendJoystickEffect,
HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled,
HIDAPI_DriverXboxOne_CloseJoystick,
HIDAPI_DriverXboxOne_FreeDevice,
};
#endif
#endif