From dec7875a6e23212021e4d9080330a42832dfe02a Mon Sep 17 00:00:00 2001
From: Edward Rudd <urkle@outoforder.cc>
Date: Tue, 15 Jun 2021 01:40:19 +0000
Subject: [PATCH] update SDL soruce to 2.0.14
---
source/src/joystick/hidapi/SDL_hidapi_xboxone.c | 737 +++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 561 insertions(+), 176 deletions(-)
diff --git a/source/src/joystick/hidapi/SDL_hidapi_xboxone.c b/source/src/joystick/hidapi/SDL_hidapi_xboxone.c
index 59dd358..5cb7dab 100644
--- a/source/src/joystick/hidapi/SDL_hidapi_xboxone.c
+++ b/source/src/joystick/hidapi/SDL_hidapi_xboxone.c
@@ -23,7 +23,6 @@
#ifdef SDL_JOYSTICK_HIDAPI
#include "SDL_hints.h"
-#include "SDL_log.h"
#include "SDL_events.h"
#include "SDL_timer.h"
#include "SDL_joystick.h"
@@ -35,41 +34,40 @@
#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
+/* Define this if you want verbose logging of the init sequence */
+/*#define DEBUG_JOYSTICK*/
+
/* Define this if you want to log all packets from the controller */
/*#define DEBUG_XBOX_PROTOCOL*/
-/* The amount of time to wait after hotplug to send controller init sequence */
-#define CONTROLLER_INIT_DELAY_MS 1500 /* 475 for Xbox One S, 1275 for the PDP Battlefield 1 */
+#define CONTROLLER_NEGOTIATION_TIMEOUT_MS 300
+#define CONTROLLER_PREPARE_INPUT_TIMEOUT_MS 50
+
/* Connect controller */
static const Uint8 xboxone_init0[] = {
0x04, 0x20, 0x00, 0x00
};
-/* Initial ack */
-static const Uint8 xboxone_init1[] = {
- 0x01, 0x20, 0x01, 0x09, 0x00, 0x04, 0x20, 0x3a,
- 0x00, 0x00, 0x00, 0x80, 0x00
-};
/* Start controller - extended? */
-static const Uint8 xboxone_init2[] = {
+static const Uint8 xboxone_init1[] = {
0x05, 0x20, 0x00, 0x0F, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x55, 0x53, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00
};
/* Start controller with input */
-static const Uint8 xboxone_init3[] = {
+static const Uint8 xboxone_init2[] = {
0x05, 0x20, 0x03, 0x01, 0x00
};
/* Enable LED */
-static const Uint8 xboxone_init4[] = {
+static const Uint8 xboxone_init3[] = {
0x0A, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
};
/* Start input reports? */
-static const Uint8 xboxone_init5[] = {
+static const Uint8 xboxone_init4[] = {
0x06, 0x20, 0x00, 0x02, 0x01, 0x00
};
/* Start rumble? */
-static const Uint8 xboxone_init6[] = {
+static const Uint8 xboxone_init5[] = {
0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xEB
};
@@ -92,56 +90,45 @@
static const SDL_DriverXboxOne_InitPacket xboxone_init_packets[] = {
- { 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init0, sizeof(xboxone_init0), { 0x04, 0xf0 } },
- { 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init1, sizeof(xboxone_init1), { 0x04, 0xb0 } },
+ { 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init0, sizeof(xboxone_init0), { 0x04, 0xb0 } },
+ { 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init1, sizeof(xboxone_init1), { 0x00, 0x00 } },
{ 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init2, sizeof(xboxone_init2), { 0x00, 0x00 } },
{ 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init3, sizeof(xboxone_init3), { 0x00, 0x00 } },
- { 0x0000, 0x0000, 0x0000, 0x0000, xboxone_init4, sizeof(xboxone_init4), { 0x00, 0x00 } },
/* These next packets are required for third party controllers (PowerA, PDP, HORI),
but aren't the correct protocol for Microsoft Xbox controllers.
*/
+ { 0x0000, 0x0000, 0x045e, 0x0000, xboxone_init4, sizeof(xboxone_init4), { 0x00, 0x00 } },
{ 0x0000, 0x0000, 0x045e, 0x0000, xboxone_init5, sizeof(xboxone_init5), { 0x00, 0x00 } },
- { 0x0000, 0x0000, 0x045e, 0x0000, xboxone_init6, sizeof(xboxone_init6), { 0x00, 0x00 } },
};
typedef enum {
- XBOX_ONE_WIRELESS_PROTOCOL_UNKNOWN,
- XBOX_ONE_WIRELESS_PROTOCOL_V1,
- XBOX_ONE_WIRELESS_PROTOCOL_V2,
-} SDL_XboxOneWirelessProtocol;
+ XBOX_ONE_INIT_STATE_START_NEGOTIATING = 0,
+ XBOX_ONE_INIT_STATE_NEGOTIATING = 1,
+ XBOX_ONE_INIT_STATE_PREPARE_INPUT = 2,
+ XBOX_ONE_INIT_STATE_COMPLETE = 3
+} SDL_XboxOneInitState;
typedef struct {
Uint16 vendor_id;
Uint16 product_id;
SDL_bool bluetooth;
- SDL_XboxOneWirelessProtocol wireless_protocol;
- SDL_bool initialized;
+ SDL_XboxOneInitState init_state;
+ int init_packet;
Uint32 start_time;
Uint8 sequence;
+ Uint32 send_time;
Uint8 last_state[USB_PACKET_LENGTH];
+ SDL_bool has_guide_packet;
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_DriverXboxOne_Context;
-
-#ifdef DEBUG_XBOX_PROTOCOL
-static void
-DumpPacket(const char *prefix, Uint8 *data, int size)
-{
- int i;
- char buffer[5*USB_PACKET_LENGTH];
-
- SDL_snprintf(buffer, sizeof(buffer), prefix, size);
- for (i = 0; i < size; ++i) {
- if ((i % 8) == 0) {
- SDL_snprintf(&buffer[SDL_strlen(buffer)], sizeof(buffer) - SDL_strlen(buffer), "\n%.2d: ", i);
- }
- SDL_snprintf(&buffer[SDL_strlen(buffer)], sizeof(buffer) - SDL_strlen(buffer), " 0x%.2x", data[i]);
- }
- SDL_strlcat(buffer, "\n", sizeof(buffer));
- SDL_Log("%s", buffer);
-}
-#endif /* DEBUG_XBOX_PROTOCOL */
static SDL_bool
IsBluetoothXboxOneController(Uint16 vendor_id, Uint16 product_id)
@@ -150,7 +137,8 @@
if (vendor_id == USB_VENDOR_MICROSOFT) {
if (product_id == USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH ||
product_id == USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH ||
- product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH) {
+ product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH ||
+ product_id == USB_PRODUCT_XBOX_ONE_SERIES_X_BLUETOOTH) {
return SDL_TRUE;
}
}
@@ -160,33 +148,81 @@
static SDL_bool
ControllerHasPaddles(Uint16 vendor_id, Uint16 product_id)
{
- if (vendor_id == USB_VENDOR_MICROSOFT) {
- if (product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 ||
- product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2) {
- return SDL_TRUE;
- }
- }
- return SDL_FALSE;
+ return SDL_IsJoystickXboxOneElite(vendor_id, product_id);
}
-/* Return true if this controller sends the 0x02 "waiting for init" packet */
static SDL_bool
-ControllerSendsWaitingForInit(Uint16 vendor_id, Uint16 product_id)
+ControllerHasTriggerRumble(Uint16 vendor_id, Uint16 product_id)
{
- if (vendor_id == USB_VENDOR_HYPERKIN) {
- /* The Hyperkin controllers always send 0x02 when waiting for init,
- and the Hyperkin Duke plays an Xbox startup animation, so we want
- to make sure we don't send the init sequence if it isn't needed.
- */
- return SDL_TRUE;
+ return SDL_IsJoystickXboxOneElite(vendor_id, product_id);
+}
+
+static SDL_bool
+ControllerHasShareButton(Uint16 vendor_id, Uint16 product_id)
+{
+ return SDL_IsJoystickXboxOneSeriesX(vendor_id, product_id);
+}
+
+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)
+{
+#ifdef __WIN32__
+ /* The Windows driver is taking care of acks */
+#else
+ if ((data[1] & 0x30) == 0x30) {
+ Uint8 ack_packet[] = { 0x01, 0x20, data[2], 0x09, 0x00, data[0], 0x20, data[3], 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ /* The initial ack needs 0x80 added to the response, for some reason */
+ 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
+ hid_write(device->dev, ack_packet, sizeof(ack_packet));
}
- if (vendor_id == USB_VENDOR_PDP) {
- /* The PDP Rock Candy (PID 0x0246) doesn't send 0x02 on Linux for some reason */
+#endif /* __WIN32__ */
+}
+
+#if 0
+static SDL_bool
+SendSerialRequest(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx)
+{
+ Uint8 serial_packet[] = { 0x1E, 0x30, 0x07, 0x01, 0x04 };
+
+ ctx->send_time = SDL_GetTicks();
+
+ /* Request the serial number
+ * Sending this should be done only after the negotiation is complete.
+ * It will cancel the announce packet if sent before that, and will be
+ * ignored if sent during the negotiation.
+ */
+ if (SDL_HIDAPI_LockRumble() < 0 ||
+ SDL_HIDAPI_SendRumbleAndUnlock(device, serial_packet, sizeof(serial_packet)) != sizeof(serial_packet)) {
+ SDL_SetError("Couldn't send serial packet");
return SDL_FALSE;
}
+ return SDL_TRUE;
+}
+#endif
- /* It doesn't hurt to reinit, especially if a driver has misconfigured the controller */
- /*return SDL_TRUE;*/
+static SDL_bool
+ControllerNeedsNegotiation(SDL_DriverXboxOne_Context *ctx)
+{
+ if (ctx->vendor_id == USB_VENDOR_PDP && ctx->product_id == 0x0246) {
+ /* The PDP Rock Candy (PID 0x0246) doesn't send the announce packet on Linux for some reason */
+ return SDL_TRUE;
+ }
return SDL_FALSE;
}
@@ -195,11 +231,10 @@
{
Uint16 vendor_id = ctx->vendor_id;
Uint16 product_id = ctx->product_id;
- int i;
Uint8 init_packet[USB_PACKET_LENGTH];
- for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
- const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i];
+ 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;
@@ -221,34 +256,25 @@
if (init_packet[0] != 0x01) {
init_packet[2] = ctx->sequence++;
}
- if (hid_write(device->dev, init_packet, packet->size) != packet->size) {
+#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]) {
- const Uint32 RESPONSE_TIMEOUT_MS = 50;
- Uint32 start = SDL_GetTicks();
- SDL_bool got_response = SDL_FALSE;
-
- while (!got_response && !SDL_TICKS_PASSED(SDL_GetTicks(), start + RESPONSE_TIMEOUT_MS)) {
- Uint8 data[USB_PACKET_LENGTH];
- int size;
-
- while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
-#ifdef DEBUG_XBOX_PROTOCOL
- DumpPacket("Xbox One INIT packet: size = %d", data, size);
-#endif
- if (size >= 2 && data[0] == packet->response[0] && data[1] == packet->response[1]) {
- got_response = SDL_TRUE;
- }
- }
- }
-#ifdef DEBUG_XBOX_PROTOCOL
- SDL_Log("Init sequence %d got response: %s\n", i, got_response ? "TRUE" : "FALSE");
-#endif
+ return SDL_TRUE;
}
}
+
+ /* All done with the negotiation, prepare for input! */
+ SetInitState(ctx, XBOX_ONE_INIT_STATE_PREPARE_INPUT);
+
return SDL_TRUE;
}
@@ -267,7 +293,7 @@
return SDL_FALSE;
}
#endif
- return (type == SDL_CONTROLLER_TYPE_XBOXONE);
+ return (type == SDL_CONTROLLER_TYPE_XBOXONE) ? SDL_TRUE : SDL_FALSE;
}
static const char *
@@ -293,6 +319,9 @@
{
}
+static SDL_bool HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
+static void HIDAPI_DriverXboxOne_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
+
static SDL_bool
HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
@@ -315,39 +344,63 @@
ctx->vendor_id = device->vendor_id;
ctx->product_id = device->product_id;
ctx->bluetooth = IsBluetoothXboxOneController(device->vendor_id, device->product_id);
- ctx->initialized = ctx->bluetooth ? SDL_TRUE : SDL_FALSE;
ctx->start_time = SDL_GetTicks();
ctx->sequence = 1;
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);
+
+ /* Assume that the controller is correctly initialized when we start */
+ 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
/* Initialize the joystick capabilities */
- joystick->nbuttons = ctx->has_paddles ? SDL_CONTROLLER_BUTTON_MAX : (SDL_CONTROLLER_BUTTON_MAX + 4);
+ joystick->nbuttons = 15;
+ if (ctx->has_share_button) {
+ joystick->nbuttons += 1;
+ }
+ if (ctx->has_paddles) {
+ joystick->nbuttons += 4;
+ }
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
- joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
+
+ if (!ctx->bluetooth) {
+ joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
+ }
return SDL_TRUE;
}
static int
-HIDAPI_DriverXboxOne_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
+HIDAPI_DriverXboxOne_UpdateRumble(SDL_HIDAPI_Device *device)
{
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
if (ctx->bluetooth) {
- Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00 };
+ Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB };
- rumble_packet[4] = (low_frequency_rumble >> 8);
- rumble_packet[5] = (high_frequency_rumble >> 8);
+ 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_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != 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, 0xFF };
+ Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB };
- /* Magnitude is 1..100 so scale the 16-bit input here */
- rumble_packet[8] = low_frequency_rumble / 655;
- rumble_packet[9] = high_frequency_rumble / 655;
+ 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_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
@@ -356,8 +409,55 @@
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;
+
+ /* Magnitude is 1..100 so scale the 16-bit input here */
+ ctx->low_frequency_rumble = low_frequency_rumble / 655;
+ ctx->high_frequency_rumble = high_frequency_rumble / 655;
+
+ 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();
+ }
+
+ /* Magnitude is 1..100 so scale the 16-bit input here */
+ ctx->left_trigger_rumble = left_rumble / 655;
+ ctx->right_trigger_rumble = right_rumble / 655;
+
+ return HIDAPI_DriverXboxOne_UpdateRumble(device);
+}
+
+static SDL_bool
+HIDAPI_DriverXboxOne_HasJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
+{
+ /* Doesn't have an RGB LED, so don't return true here */
+ return SDL_FALSE;
+}
+
+static int
+HIDAPI_DriverXboxOne_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
+{
+ 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, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
+HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
Sint16 axis;
@@ -375,21 +475,39 @@
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);
- 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);
+ if (ctx->vendor_id == USB_VENDOR_RAZER && ctx->product_id == USB_PRODUCT_RAZER_ATROX) {
+ /* The Razer Atrox has the right and left shoulder bits reversed */
+ 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) {
+ /* Version 1 of the firmware for Xbox One Series X */
+ if (ctx->last_state[18] != data[18]) {
+ SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data[18] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
+ }
+
+ /* Version 2 of the firmware for Xbox One Series X */
+ if (ctx->last_state[22] != data[22]) {
+ SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data[22] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
+ }
}
/* Xbox One S report is 18 bytes
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
Paddle bits:
- UL: 0x01 (A) UR: 0x02 (B)
- LL: 0x04 (X) LR: 0x08 (Y)
+ P3: 0x01 (A) P1: 0x02 (B)
+ P4: 0x04 (X) P2: 0x08 (Y)
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
Paddle bits:
- UL: 0x04 (A) UR: 0x01 (B)
- LL: 0x08 (X) LR: 0x02 (Y)
+ P3: 0x04 (A) P1: 0x01 (B)
+ P4: 0x08 (X) P2: 0x02 (Y)
*/
if (ctx->has_paddles && (size == 33 || size == 38)) {
int paddle_index;
@@ -402,10 +520,10 @@
if (size == 33) {
/* XBox One Elite Series 1 */
paddle_index = 32;
- button1_bit = 0x01;
- button2_bit = 0x02;
- button3_bit = 0x04;
- button4_bit = 0x08;
+ button1_bit = 0x02;
+ button2_bit = 0x08;
+ button3_bit = 0x01;
+ button4_bit = 0x04;
/* The mapped controller state is at offset 4, the raw state is at offset 18, compare them to see if the paddles are mapped */
paddles_mapped = (SDL_memcmp(&data[4], &data[18], 14) != 0);
@@ -413,10 +531,10 @@
} else /* if (size == 38) */ {
/* XBox One Elite Series 2 */
paddle_index = 18;
- button1_bit = 0x04;
- button2_bit = 0x01;
- button3_bit = 0x08;
- button4_bit = 0x02;
+ button1_bit = 0x01;
+ button2_bit = 0x02;
+ button3_bit = 0x04;
+ button4_bit = 0x08;
paddles_mapped = (data[19] != 0);
}
#ifdef DEBUG_XBOX_PROTOCOL
@@ -435,10 +553,11 @@
}
if (ctx->last_state[paddle_index] != data[paddle_index]) {
- SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MAX+0, (data[paddle_index] & button1_bit) ? SDL_PRESSED : SDL_RELEASED);
- SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MAX+1, (data[paddle_index] & button2_bit) ? SDL_PRESSED : SDL_RELEASED);
- SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MAX+2, (data[paddle_index] & button3_bit) ? SDL_PRESSED : SDL_RELEASED);
- SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MAX+3, (data[paddle_index] & button4_bit) ? SDL_PRESSED : SDL_RELEASED);
+ int nButton = SDL_CONTROLLER_BUTTON_MISC1 + ctx->has_share_button; /* Next available 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);
}
}
@@ -446,12 +565,20 @@
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)*(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 = *(Sint16*)(&data[10]);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
axis = *(Sint16*)(&data[12]);
@@ -465,23 +592,44 @@
}
static void
-HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
+HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
- if (data[1] == 0x30) {
- /* The Xbox One S controller needs acks for mode reports */
- const Uint8 seqnum = data[2];
- const Uint8 ack[] = { 0x01, 0x20, seqnum, 0x09, 0x00, 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
- hid_write(dev, ack, sizeof(ack));
- }
-
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
}
+/*
+ * Xbox One S with firmware 3.1.1221 uses a 16 byte packet and the GUIDE button in a separate packet
+ */
static void
-HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
+HIDAPI_DriverXboxOneBluetooth_HandleButtons16(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
- Sint16 axis;
+ 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);
+ }
+
+}
+
+/*
+ * Xbox One S with firmware 4.8.1923 uses a 17 byte packet with BACK button in byte 16 and the GUIDE button in a separate packet (on Windows), or in byte 15 (on Linux)
+ * Xbox One Elite Series 2 with firmware 4.7.1872 uses a 55 byte packet with BACK button in byte 16, paddles starting at byte 33, and the GUIDE button in a separate packet
+ * Xbox One Elite Series 2 with firmware 4.8.1908 uses a 33 byte packet with BACK button in byte 16, paddles starting at byte 17, and the GUIDE button in a separate packet
+ * Xbox One Series X with firmware 5.5.2641 uses a 17 byte packet with BACK and GUIDE buttons in byte 15, and SHARE button in byte 17
+ */
+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);
@@ -492,23 +640,91 @@
}
if (ctx->last_state[15] != data[15]) {
+ 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_GUIDE, (data[15] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
+ } else 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->wireless_protocol == XBOX_ONE_WIRELESS_PROTOCOL_UNKNOWN)
- {
- if (data[15] & 0x10) {
- ctx->wireless_protocol = XBOX_ONE_WIRELESS_PROTOCOL_V2;
- }
- }
- if (ctx->wireless_protocol == XBOX_ONE_WIRELESS_PROTOCOL_V2)
- {
- SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[15] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
- }
}
if (ctx->last_state[16] != data[16]) {
- SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
+ if (ctx->has_share_button) {
+ SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
+ } else {
+ SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
+ }
+ }
+
+ /*
+ Paddle bits:
+ P3: 0x04 (A) P1: 0x01 (B)
+ P4: 0x08 (X) P2: 0x02 (Y)
+ */
+ 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) {
+ /* Initial firmware for the Xbox Elite Series 2 controller */
+ paddle_index = 33;
+ button1_bit = 0x01;
+ button2_bit = 0x02;
+ button3_bit = 0x04;
+ button4_bit = 0x08;
+ paddles_mapped = (data[35] != 0);
+ } else /* if (size == 39) */ {
+ /* Updated firmware for the Xbox Elite Series 2 controller */
+ 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) {
+ /* Respect that the paddles are being used for other controls and don't pass them on to the app */
+ data[paddle_index] = 0;
+ }
+
+ if (ctx->last_state[paddle_index] != data[paddle_index]) {
+ int nButton = SDL_CONTROLLER_BUTTON_MISC1; /* Next available 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);
+ }
+ }
+}
+
+static void
+HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
+{
+ Sint16 axis;
+
+ if (size == 16) {
+ /* Original Xbox One S, with separate report for guide button */
+ HIDAPI_DriverXboxOneBluetooth_HandleButtons16(joystick, ctx, data, size);
+ } else {
+ HIDAPI_DriverXboxOneBluetooth_HandleButtons(joystick, ctx, data, size);
}
if (ctx->last_state[13] != data[13]) {
@@ -580,49 +796,134 @@
}
static void
-HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
+HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
{
- ctx->wireless_protocol = XBOX_ONE_WIRELESS_PROTOCOL_V1;
+ 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) {
+ /* Does this ever happen? */
+ 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: /* 2, 3 */
+ 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 /* SET_SERIAL_AFTER_OPEN */
+
static SDL_bool
-HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
+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:
+#ifdef __WIN32__
+ /* The Windows driver is taking care of negotiation */
+ 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)) {
+ /* We haven't heard anything, let's move on */
+#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_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
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]);
- }
- if (!joystick) {
- return SDL_FALSE;
- }
-
- if (!ctx->initialized &&
- !ControllerSendsWaitingForInit(device->vendor_id, device->product_id)) {
- if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->start_time + CONTROLLER_INIT_DELAY_MS)) {
- if (!SendControllerInit(device, ctx)) {
- HIDAPI_JoystickDisconnected(device, joystick->instance_id);
- return SDL_FALSE;
- }
- ctx->initialized = SDL_TRUE;
- }
- }
-
while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
#ifdef DEBUG_XBOX_PROTOCOL
- DumpPacket("Xbox One packet: size = %d", data, size);
+ HIDAPI_DumpPacket("Xbox One packet: size = %d", data, size);
#endif
if (ctx->bluetooth) {
switch (data[0]) {
case 0x01:
- HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(joystick, device->dev, ctx, data, size);
+ 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:
- HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(joystick, device->dev, ctx, data, size);
+ HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(joystick, ctx, data, size);
+ break;
+ case 0x04:
+ HIDAPI_DriverXboxOneBluetooth_HandleBatteryPacket(joystick, ctx, data, size);
break;
default:
#ifdef DEBUG_JOYSTICK
@@ -632,27 +933,77 @@
}
} else {
switch (data[0]) {
+ case 0x01:
+ /* ACK packet */
+ /* The data bytes are:
+ 0x01 0x20 NN 0x09, where NN is the packet sequence
+ then 0x00
+ then a byte of the sequence being acked
+ then 0x20
+ then 16-bit LE value, the size of the previous packet payload when it's a single packet
+ then 4 bytes of unknown data, often all zero
+ */
+ break;
case 0x02:
/* Controller is connected and waiting for initialization */
- if (!ctx->initialized) {
-#ifdef DEBUG_XBOX_PROTOCOL
- SDL_Log("Delay after init: %ums\n", SDL_GetTicks() - ctx->start_time);
+ /* The data bytes are:
+ 0x02 0x20 NN 0x1c, where NN is the packet sequence
+ then 6 bytes of wireless MAC address
+ then 2 bytes padding
+ then 16-bit VID
+ then 16-bit PID
+ then 16-bit firmware version quartet AA.BB.CC.DD
+ e.g. 0x05 0x00 0x05 0x00 0x51 0x0a 0x00 0x00
+ is firmware version 5.5.2641.0, and product version 0x0505 = 1285
+ then 8 bytes of unknown data
+ */
+#ifdef DEBUG_JOYSTICK
+ SDL_Log("Controller announce after %u ms\n", (SDL_GetTicks() - ctx->start_time));
#endif
- if (!SendControllerInit(device, ctx)) {
- HIDAPI_JoystickDisconnected(device, joystick->instance_id);
- return SDL_FALSE;
- }
- ctx->initialized = SDL_TRUE;
- }
+ SetInitState(ctx, XBOX_ONE_INIT_STATE_START_NEGOTIATING);
break;
case 0x03:
/* Controller heartbeat */
+ if (ctx->init_state < XBOX_ONE_INIT_STATE_COMPLETE) {
+ SetInitState(ctx, XBOX_ONE_INIT_STATE_COMPLETE);
+ }
break;
- case 0x20:
- HIDAPI_DriverXboxOne_HandleStatePacket(joystick, device->dev, ctx, data, size);
+ case 0x04:
+ /* Unknown chatty controller information, sent by both sides */
+ break;
+ case 0x06:
+ /* Unknown chatty controller information, sent by both sides */
break;
case 0x07:
- HIDAPI_DriverXboxOne_HandleModePacket(joystick, device->dev, ctx, data, size);
+ HIDAPI_DriverXboxOne_HandleModePacket(joystick, ctx, data, size);
+ break;
+ case 0x1E:
+ /* If the packet starts with this:
+ 0x1E 0x30 0x07 0x10 0x04 0x00
+ then the next 14 bytes are the controller serial number
+ e.g. 0x30 0x39 0x37 0x31 0x32 0x33 0x33 0x32 0x33 0x35 0x34 0x30 0x33 0x36
+ is serial number "3039373132333332333534303336"
+
+ The controller sends that in response to this request:
+ 0x1E 0x30 0x07 0x01 0x04
+ */
+#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);
+
+ /* Ignore the first input, it may be spurious */
+#ifdef DEBUG_JOYSTICK
+ SDL_Log("Controller ignoring spurious input\n");
+#endif
+ break;
+ }
+ HIDAPI_DriverXboxOne_HandleStatePacket(joystick, ctx, data, size);
break;
default:
#ifdef DEBUG_JOYSTICK
@@ -660,14 +1011,44 @@
#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);
if (size < 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
}
return (size >= 0);
+}
+
+static SDL_bool
+HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
+{
+ SDL_Joystick *joystick = NULL;
+
+ if (device->num_joysticks > 0) {
+ joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
+ }
+ if (!joystick) {
+ return SDL_FALSE;
+ }
+ return HIDAPI_DriverXboxOne_UpdateJoystick(device, joystick);
}
static void
@@ -697,8 +1078,12 @@
HIDAPI_DriverXboxOne_UpdateDevice,
HIDAPI_DriverXboxOne_OpenJoystick,
HIDAPI_DriverXboxOne_RumbleJoystick,
+ HIDAPI_DriverXboxOne_RumbleJoystickTriggers,
+ HIDAPI_DriverXboxOne_HasJoystickLED,
+ HIDAPI_DriverXboxOne_SetJoystickLED,
+ HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled,
HIDAPI_DriverXboxOne_CloseJoystick,
- HIDAPI_DriverXboxOne_FreeDevice
+ HIDAPI_DriverXboxOne_FreeDevice,
};
#endif /* SDL_JOYSTICK_HIDAPI_XBOXONE */
--
Gitblit v1.9.3