From e12457d8bff5f6c0d31a6c38cdbe7ea8a6ff8231 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 10 Nov 2020 12:26:30 -0800 Subject: [PATCH] Added support for the Xbox Series X controller to the HIDAPI driver --- src/hidapi/libusb/hid.c | 4 ++-- src/joystick/SDL_gamecontroller.c | 5 +++- src/joystick/SDL_joystick.c | 12 ++++++++++ src/joystick/SDL_joystick_c.h | 3 +++ src/joystick/controller_type.h | 2 ++ src/joystick/hidapi/SDL_hidapi_xboxone.c | 29 ++++++++++++++++++++---- src/joystick/usb_ids.h | 2 ++ 7 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/hidapi/libusb/hid.c b/src/hidapi/libusb/hid.c index 956dd9772..4e93559be 100644 --- a/src/hidapi/libusb/hid.c +++ b/src/hidapi/libusb/hid.c @@ -982,9 +982,9 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive) libusb_get_config_descriptor(usb_dev, 0, &conf_desc); if (!conf_desc) continue; - for (j = 0; j < conf_desc->bNumInterfaces; j++) { + for (j = 0; j < conf_desc->bNumInterfaces && !good_open; j++) { const struct libusb_interface *intf = &conf_desc->interface[j]; - for (k = 0; k < intf->num_altsetting; k++) { + for (k = 0; k < intf->num_altsetting && !good_open; k++) { const struct libusb_interface_descriptor *intf_desc; intf_desc = &intf->altsetting[k]; if (should_enumerate_interface(desc.idVendor, intf_desc)) { diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index b37f4c191..e7db9c199 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -568,7 +568,10 @@ static ControllerMapping_t *SDL_CreateMappingForHIDAPIController(SDL_JoystickGUI /* All other controllers have the standard set of 19 buttons and 6 axes */ SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", sizeof(mapping_string)); - if (SDL_IsJoystickXboxOneElite(vendor, product)) { + if (SDL_IsJoystickXboxOneSeriesX(vendor, product)) { + /* XBox One Series X Controllers have a share button under the guide button */ + SDL_strlcat(mapping_string, "misc1:b15,", sizeof(mapping_string)); + } else if (SDL_IsJoystickXboxOneElite(vendor, product)) { /* XBox One Elite Controllers have 4 back paddle buttons */ SDL_strlcat(mapping_string, "paddle1:b15,paddle2:b17,paddle3:b16,paddle4:b18,", sizeof(mapping_string)); } else if (SDL_IsJoystickSteamController(vendor, product)) { diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index c161aa37e..63ecf9340 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -1793,6 +1793,18 @@ SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id) return SDL_FALSE; } +SDL_bool +SDL_IsJoystickXboxOneSeriesX(Uint16 vendor_id, Uint16 product_id) +{ + if (vendor_id == USB_VENDOR_MICROSOFT) { + if (product_id == USB_PRODUCT_XBOX_ONE_SERIES_X || + product_id == USB_PRODUCT_XBOX_ONE_SERIES_X_BLUETOOTH) { + return SDL_TRUE; + } + } + return SDL_FALSE; +} + SDL_bool SDL_IsJoystickPS4(Uint16 vendor_id, Uint16 product_id) { diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index 4f31c3a1c..ce96d5040 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -64,6 +64,9 @@ extern SDL_GameControllerType SDL_GetJoystickGameControllerType(const char *name /* Function to return whether a joystick is an Xbox One Elite controller */ extern SDL_bool SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id); +/* Function to return whether a joystick is an Xbox One Series X controller */ +extern SDL_bool SDL_IsJoystickXboxOneSeriesX(Uint16 vendor_id, Uint16 product_id); + /* Function to return whether a joystick is a PS4 controller */ extern SDL_bool SDL_IsJoystickPS4(Uint16 vendor_id, Uint16 product_id); diff --git a/src/joystick/controller_type.h b/src/joystick/controller_type.h index 12e0fd706..e1ab997d8 100644 --- a/src/joystick/controller_type.h +++ b/src/joystick/controller_type.h @@ -323,6 +323,8 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x045e, 0x02ff ), k_eControllerType_XBoxOneController, NULL }, // Microsoft X-Box One controller with the RAWINPUT driver on Windows { MAKE_CONTROLLER_ID( 0x045e, 0x0b00 ), k_eControllerType_XBoxOneController, "Xbox One Elite 2 Controller" }, // Microsoft X-Box One Elite Series 2 pad { MAKE_CONTROLLER_ID( 0x045e, 0x0b05 ), k_eControllerType_XBoxOneController, "Xbox One Elite 2 Controller" }, // Microsoft X-Box One Elite Series 2 pad (Bluetooth) + { MAKE_CONTROLLER_ID( 0x045e, 0x0b12 ), k_eControllerType_XBoxOneController, "Xbox One Series X Controller" }, // Microsoft X-Box One Elite Series X pad + { MAKE_CONTROLLER_ID( 0x045e, 0x0b13 ), k_eControllerType_XBoxOneController, "Xbox One Series X Controller" }, // Microsoft X-Box One Elite Series X pad (Bluetooth) { MAKE_CONTROLLER_ID( 0x0738, 0x4a01 ), k_eControllerType_XBoxOneController, NULL }, // Mad Catz FightStick TE 2 { MAKE_CONTROLLER_ID( 0x0e6f, 0x0139 ), k_eControllerType_XBoxOneController, "PDP Xbox One Afterglow" }, // PDP Afterglow Wired Controller for Xbox One { MAKE_CONTROLLER_ID( 0x0e6f, 0x013B ), k_eControllerType_XBoxOneController, "PDP Xbox One Face-Off Controller" }, // PDP Face-Off Gamepad for Xbox One diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c index 109317f4f..ff217ded6 100644 --- a/src/joystick/hidapi/SDL_hidapi_xboxone.c +++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c @@ -125,6 +125,7 @@ typedef struct { Uint8 sequence; Uint8 last_state[USB_PACKET_LENGTH]; SDL_bool has_paddles; + SDL_bool has_share_button; } SDL_DriverXboxOne_Context; @@ -148,6 +149,12 @@ ControllerHasPaddles(Uint16 vendor_id, Uint16 product_id) return SDL_IsJoystickXboxOneElite(vendor_id, product_id); } +static SDL_bool +ControllerHasShareButton(Uint16 vendor_id, Uint16 product_id) +{ + return SDL_IsJoystickXboxOneSeriesX(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) @@ -299,9 +306,16 @@ HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst ctx->input_ready = SDL_TRUE; ctx->sequence = 1; ctx->has_paddles = ControllerHasPaddles(ctx->vendor_id, ctx->product_id); + ctx->has_share_button = ControllerHasShareButton(ctx->vendor_id, ctx->product_id); /* Initialize the joystick capabilities */ - joystick->nbuttons = ctx->has_paddles ? 19 : 15; + 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; @@ -380,6 +394,10 @@ HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[5] & 0x80) ? SDL_PRESSED : SDL_RELEASED); } + if (ctx->has_share_button && ctx->last_state[18] != data[18]) { + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1, (data[18] & 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: @@ -434,10 +452,11 @@ HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, } if (ctx->last_state[paddle_index] != data[paddle_index]) { - SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1 + 0, (data[paddle_index] & button1_bit) ? SDL_PRESSED : SDL_RELEASED); - SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1 + 1, (data[paddle_index] & button2_bit) ? SDL_PRESSED : SDL_RELEASED); - SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1 + 2, (data[paddle_index] & button3_bit) ? SDL_PRESSED : SDL_RELEASED); - SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1 + 3, (data[paddle_index] & button4_bit) ? SDL_PRESSED : SDL_RELEASED); + 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); } } diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h index d1981b407..00de4bd68 100644 --- a/src/joystick/usb_ids.h +++ b/src/joystick/usb_ids.h @@ -50,6 +50,8 @@ #define USB_PRODUCT_XBOX_ONE_S 0x02ea #define USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH 0x02e0 #define USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH 0x02fd +#define USB_PRODUCT_XBOX_ONE_SERIES_X 0x0b12 +#define USB_PRODUCT_XBOX_ONE_SERIES_X_BLUETOOTH 0x0b13 #endif /* usb_ids_h_ */