mirror of https://github.com/encounter/SDL.git
Added support for the Xbox One S controller in Bluetooth mode on Linux
This commit is contained in:
parent
9d4c3f12cd
commit
9ca5373024
|
@ -148,6 +148,7 @@ HIDAPI_DriverXboxOne_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor
|
||||||
SDL_DriverXboxOne_Context *ctx;
|
SDL_DriverXboxOne_Context *ctx;
|
||||||
int i;
|
int i;
|
||||||
Uint8 init_packet[USB_PACKET_LENGTH];
|
Uint8 init_packet[USB_PACKET_LENGTH];
|
||||||
|
SDL_bool is_bluetooth = SDL_FALSE;
|
||||||
|
|
||||||
ctx = (SDL_DriverXboxOne_Context *)SDL_calloc(1, sizeof(*ctx));
|
ctx = (SDL_DriverXboxOne_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
|
@ -156,16 +157,21 @@ HIDAPI_DriverXboxOne_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor
|
||||||
}
|
}
|
||||||
*context = ctx;
|
*context = ctx;
|
||||||
|
|
||||||
/* Send the controller init data */
|
if (vendor_id == 0x045e && product_id == 0x02fd) {
|
||||||
for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
|
is_bluetooth = SDL_TRUE;
|
||||||
const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i];
|
}
|
||||||
if (!packet->vendor_id || (vendor_id == packet->vendor_id && product_id == packet->product_id)) {
|
if (!is_bluetooth) {
|
||||||
SDL_memcpy(init_packet, packet->data, packet->size);
|
/* Send the controller init data */
|
||||||
init_packet[2] = ctx->sequence++;
|
for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
|
||||||
if (hid_write(dev, init_packet, packet->size) != packet->size) {
|
const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i];
|
||||||
SDL_SetError("Couldn't write Xbox One initialization packet");
|
if (!packet->vendor_id || (vendor_id == packet->vendor_id && product_id == packet->product_id)) {
|
||||||
SDL_free(ctx);
|
SDL_memcpy(init_packet, packet->data, packet->size);
|
||||||
return SDL_FALSE;
|
init_packet[2] = ctx->sequence++;
|
||||||
|
if (hid_write(dev, init_packet, packet->size) != packet->size) {
|
||||||
|
SDL_SetError("Couldn't write Xbox One initialization packet");
|
||||||
|
SDL_free(ctx);
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,15 +190,10 @@ HIDAPI_DriverXboxOne_Rumble(SDL_Joystick *joystick, hid_device *dev, void *conte
|
||||||
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
|
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
|
||||||
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, 0xFF };
|
||||||
|
|
||||||
/* The Rock Candy Xbox One Controller limits the range of
|
/* Magnitude is 1..100 so scale the 16-bit input here */
|
||||||
low frequency rumble strength in the range of [0 - 0x99]
|
|
||||||
high frequency rumble strength in the range of [0 - 0x82]
|
|
||||||
|
|
||||||
I think the valid range of rumble at the firmware level is [0 - 0x7F]
|
|
||||||
*/
|
|
||||||
rumble_packet[2] = ctx->sequence++;
|
rumble_packet[2] = ctx->sequence++;
|
||||||
rumble_packet[8] = (low_frequency_rumble >> 9);
|
rumble_packet[8] = low_frequency_rumble / 655;
|
||||||
rumble_packet[9] = (high_frequency_rumble >> 9);
|
rumble_packet[9] = high_frequency_rumble / 655;
|
||||||
|
|
||||||
if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
|
if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
|
||||||
return SDL_SetError("Couldn't send rumble packet");
|
return SDL_SetError("Couldn't send rumble packet");
|
||||||
|
@ -266,6 +267,100 @@ HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, hid_device *dev, S
|
||||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
HIDAPI_DriverXboxOne_HandleBluetoothStatePacket(SDL_Joystick *joystick, hid_device *dev, 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] & 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]) {
|
||||||
|
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->last_state[16] != data[16]) {
|
||||||
|
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)*(Sint16*)(&data[9]) * 64) - 32768;
|
||||||
|
if (axis == 32704) {
|
||||||
|
axis = 32767;
|
||||||
|
}
|
||||||
|
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
|
||||||
|
axis = ((int)*(Sint16*)(&data[11]) * 64) - 32768;
|
||||||
|
if (axis == 32704) {
|
||||||
|
axis = 32767;
|
||||||
|
}
|
||||||
|
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
|
||||||
|
axis = *(Uint16*)(&data[1]) - 32768;
|
||||||
|
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
|
||||||
|
axis = *(Uint16*)(&data[3]) - 32768;
|
||||||
|
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
|
||||||
|
axis = *(Uint16*)(&data[5]) - 32768;
|
||||||
|
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
|
||||||
|
axis = *(Uint16*)(&data[7]) - 32768;
|
||||||
|
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_HandleBluetoothModePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
|
||||||
|
{
|
||||||
|
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||||
|
}
|
||||||
|
|
||||||
static SDL_bool
|
static SDL_bool
|
||||||
HIDAPI_DriverXboxOne_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
|
HIDAPI_DriverXboxOne_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
|
||||||
{
|
{
|
||||||
|
@ -274,7 +369,23 @@ HIDAPI_DriverXboxOne_Update(SDL_Joystick *joystick, hid_device *dev, void *conte
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
|
while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
|
||||||
|
#ifdef DEBUG_XBOX_PROTOCOL
|
||||||
|
SDL_Log("Xbox One packet: size = %d\n"
|
||||||
|
" 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n"
|
||||||
|
" 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n"
|
||||||
|
" 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n",
|
||||||
|
size,
|
||||||
|
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
|
||||||
|
data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
|
||||||
|
data[16], data[17], data[18], data[19]);
|
||||||
|
#endif
|
||||||
switch (data[0]) {
|
switch (data[0]) {
|
||||||
|
case 0x01:
|
||||||
|
HIDAPI_DriverXboxOne_HandleBluetoothStatePacket(joystick, dev, ctx, data, size);
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
HIDAPI_DriverXboxOne_HandleBluetoothModePacket(joystick, dev, ctx, data, size);
|
||||||
|
break;
|
||||||
case 0x20:
|
case 0x20:
|
||||||
HIDAPI_DriverXboxOne_HandleStatePacket(joystick, dev, ctx, data, size);
|
HIDAPI_DriverXboxOne_HandleStatePacket(joystick, dev, ctx, data, size);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue