diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index 59030efff1093..3cdf8429288d7 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -1034,11 +1034,11 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const } #endif /* __LINUX__ */ #ifdef SDL_JOYSTICK_XBOX - if (!mapping) { - SDL_bool existing; - mapping = SDL_PrivateAddMappingForGUID(guid, -"default,Original Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", - &existing, SDL_CONTROLLER_MAPPING_PRIORITY_DEFAULT); + if (!mapping && SDL_IsJoystickXID(guid) + && (guid.data[10] != 0x01 || (guid.data[11] != 0x01 && guid.data[11] != 0x02))) { + // This device is not an XID Gamepad Style Controller and thus should not use the default mapping + // You can define an explicit mapping for this device inside SDL_gamecontrollerdb.h + return NULL; } #endif /* SDL_JOYSTICK_XBOX */ if (!mapping && name) { diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h index cd2b10ed89a78..4f16c9fd1a7e1 100644 --- a/src/joystick/SDL_gamecontrollerdb.h +++ b/src/joystick/SDL_gamecontrollerdb.h @@ -595,7 +595,15 @@ static const char *s_ControllerMappings [] = #if defined(SDL_JOYSTICK_EMSCRIPTEN) "default,Standard Gamepad,a:b0,b:b1,back:b8,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b16,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", #endif - "hidapi,*,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,", +#if defined(SDL_JOYSTICK_XBOX) + // Compiled from https://xboxdevwiki.net/Xbox_Input_Devices + "default,Original Xbox Controller (Generic),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000005e0400000202010100014200,Original Xbox Duke Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000005e0400008502010200014200,Original Xbox Controller-S (Japan),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000005e0400008702010200014200,Original Xbox Controller-S (v1),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000005e0400008902010200014200,Original Xbox Controller-S (v2),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", +#endif +"hidapi,*,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,", NULL }; diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 2fe01779bf8b2..2ae265b3e83b2 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -1132,14 +1132,15 @@ void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *prod Uint16 *guid16 = (Uint16 *)guid.data; /* If the GUID fits the form of BUS 0000 VENDOR 0000 PRODUCT 0000, return the data */ - if (/* guid16[0] is device bus type */ + if (SDL_IsJoystickXID(guid) || ( + /* guid16[0] is device bus type */ guid16[1] == 0x0000 && /* guid16[2] is vendor ID */ guid16[3] == 0x0000 && /* guid16[4] is product ID */ guid16[5] == 0x0000 /* guid16[6] is product version */ - ) { + )) { if (vendor) { *vendor = guid16[2]; } @@ -1217,6 +1218,13 @@ SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid) return (guid.data[14] == 'h') ? SDL_TRUE : SDL_FALSE; } +SDL_bool +SDL_IsJoystickXID(SDL_JoystickGUID guid) +{ + // For XID devices guid.data[14] contains XID_DESC.bDescriptorType which is always 0x42 + return (guid.data[14] == 0x42) ? SDL_TRUE : SDL_FALSE; +} + static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid) { static Uint32 wheel_joysticks[] = { @@ -1281,6 +1289,28 @@ static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid) Uint16 vendor; Uint16 product; Uint32 vidpid; + + https://xboxdevwiki.net/Xbox_Input_Devices#bType_.3D_1:_Xbox_Gamecontroller + if (SDL_IsJoystickXID(guid)) { + if (guid.data[10] != 0x01) { // XID_DESC.bType + // Non Game-Controller device + return SDL_JOYSTICK_TYPE_UNKNOWN; + } + + switch (guid.data[11]) { // XID_DESC.bSubType + case 0x01: // Duke + case 0x02: // S-Controller + return SDL_JOYSTICK_TYPE_GAMECONTROLLER; + case 0x10: // Steering Wheel + return SDL_JOYSTICK_TYPE_WHEEL; + case 0x20: // Arcade Stick + return SDL_JOYSTICK_TYPE_ARCADE_STICK; + case 0x50: // Light Gun + return SDL_JOYSTICK_TYPE_UNKNOWN; + default: + return SDL_JOYSTICK_TYPE_UNKNOWN; + } + } if (SDL_IsJoystickXInput(guid)) { /* XInput GUID, get the type based on the XInput device subtype */ diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index f02d30b667eec..3459ffe6fad24 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -75,6 +75,9 @@ extern SDL_bool SDL_IsJoystickXInput(SDL_JoystickGUID guid); /* Function to return whether a joystick guid comes from the HIDAPI driver */ extern SDL_bool SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid); +/* Function to return whether a joystick guid comes from the XBOX XID driver */ +extern SDL_bool SDL_IsJoystickXID(SDL_JoystickGUID guid); + /* Function to return whether a joystick should be ignored */ extern SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid); diff --git a/src/joystick/xbox/SDL_xboxjoystick.c b/src/joystick/xbox/SDL_xboxjoystick.c index 8afdb3dfe4d9e..8b10f08306207 100644 --- a/src/joystick/xbox/SDL_xboxjoystick.c +++ b/src/joystick/xbox/SDL_xboxjoystick.c @@ -25,12 +25,13 @@ #include "../../SDL_internal.h" -#if SDL_JOYSTICK_XBOX +#ifdef SDL_JOYSTICK_XBOX #include "SDL_joystick.h" #include "SDL_events.h" #include "../SDL_joystick_c.h" #include "../SDL_sysjoystick.h" +#include "SDL_xboxjoystick.h" #include #include @@ -39,68 +40,18 @@ #include #include -//#define SDL_JOYSTICK_XBOX_DEBUG -#ifdef SDL_JOYSTICK_XBOX_DEBUG -#include -#define JOY_DBGMSG debugPrint -#else -#define JOY_DBGMSG(...) -#endif - #define MAX_JOYSTICKS CONFIG_XID_MAX_DEV -#define MAX_PACKET_SIZE 32 -#define BUTTON_DEADZONE 0x20 - -//XINPUT defines and struct format from -//https://docs.microsoft.com/en-us/windows/win32/api/xinput/ns-xinput-xinput_gamepad -#define XINPUT_GAMEPAD_DPAD_UP 0x0001 -#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002 -#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004 -#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008 -#define XINPUT_GAMEPAD_START 0x0010 -#define XINPUT_GAMEPAD_BACK 0x0020 -#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040 -#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080 -#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 -#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 -#define XINPUT_GAMEPAD_A 0x1000 -#define XINPUT_GAMEPAD_B 0x2000 -#define XINPUT_GAMEPAD_X 0x4000 -#define XINPUT_GAMEPAD_Y 0x8000 -#define MAX_PACKET_SIZE 32 - -typedef struct _XINPUT_GAMEPAD -{ - Uint16 wButtons; - Uint8 bLeftTrigger; - Uint8 bRightTrigger; - Sint16 sThumbLX; - Sint16 sThumbLY; - Sint16 sThumbRX; - Sint16 sThumbRY; -} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD; - -//Struct linked to SDL_Joystick -typedef struct joystick_hwdata -{ - xid_dev_t *xid_dev; - Uint8 raw_data[MAX_PACKET_SIZE]; - Uint16 current_rumble[2]; - Uint32 rumble_expiry; -} joystick_hwdata, *pjoystick_hwdata; - -static Sint32 parse_input_data(xid_dev_t *xid_dev, PXINPUT_GAMEPAD controller, Uint8 *rdata); static Sint32 SDL_XBOX_JoystickGetDevicePlayerIndex(Sint32 device_index); //Create SDL events for connection/disconnection. These events can then be handled in the user application static void connection_callback(xid_dev_t *xid_dev, int status) { - JOY_DBGMSG("connection_callback: uid %i connected \n", xid_dev->uid); + SDL_Log("connection_callback: uid %i connected\n", xid_dev->uid); SDL_PrivateJoystickAdded(xid_dev->uid); } static void disconnect_callback(xid_dev_t *xid_dev, int status) { - JOY_DBGMSG("disconnect_callback uid %i disconnected\n", xid_dev->uid); + SDL_Log("disconnect_callback uid %i disconnected\n", xid_dev->uid); SDL_PrivateJoystickRemoved(xid_dev->uid); } @@ -112,22 +63,31 @@ static void int_read_callback(UTR_T *utr) { return; } - SDL_Joystick *joy = (SDL_Joystick *)xid_dev->user_data; - + Uint32 data_len = 0; + switch (xid_dev->xid_desc.bType) { + case XID_TYPE_GAMECONTROLLER: data_len = sizeof(xid_gamepad_in); break; + case XID_TYPE_STEELBATTALION: data_len = sizeof(xid_steelbattalion_in); break; + default: return; + } + //Cap data len to buffer size. - Uint32 data_len = utr->xfer_len; - if (data_len > MAX_PACKET_SIZE) - data_len = MAX_PACKET_SIZE; + if (data_len > utr->xfer_len) data_len = utr->xfer_len; + + if (!data_len) return; - if (joy->hwdata != NULL) - { - SDL_memcpy(joy->hwdata->raw_data, utr->buff, data_len); + SDL_Joystick *joy = (SDL_Joystick *)xid_dev->user_data; + if (joy->hwdata == NULL) return; + + SDL_memcpy(&joy->hwdata->in, utr->buff, data_len); + + //Re-queue the USB transfer + utr->xfer_len = 0; + utr->bIsTransferDone = 0; + usbh_int_xfer(utr); +} - //Re-queue the USB transfer - utr->xfer_len = 0; - utr->bIsTransferDone = 0; - usbh_int_xfer(utr); - } +xid_dev_t * xid_from_joystick(SDL_Joystick * joystick) { + return (joystick == NULL || joystick->hwdata == NULL) ? NULL : joystick->hwdata->xid_dev; } static xid_dev_t *xid_from_device_index(Sint32 device_index) { @@ -137,8 +97,9 @@ static xid_dev_t *xid_from_device_index(Sint32 device_index) { //Scan the xid_dev linked list and finds the nth xid_dev that is a gamepad. while (xid_dev != NULL && i <= device_index) { - //FIXME: Include xremote and steel battalion in the joystick API. - if (xid_dev->xid_desc.bType == XID_TYPE_GAMECONTROLLER) + //FIXME: Include xremote in the joystick API. + if (xid_dev->xid_desc.bType == XID_TYPE_GAMECONTROLLER + || xid_dev->xid_desc.bType == XID_TYPE_STEELBATTALION) { if (i == device_index) return xid_dev; @@ -206,14 +167,15 @@ static Sint32 SDL_XBOX_JoystickGetCount() { xid_dev_t *xid_dev = usbh_xid_get_device_list(); while (xid_dev != NULL) { - //FIXME: Include xremote and steel battalion in the joystick API. - if (xid_dev->xid_desc.bType == XID_TYPE_GAMECONTROLLER) + //FIXME: Include xremote in the joystick API. + if (xid_dev->xid_desc.bType == XID_TYPE_GAMECONTROLLER + || xid_dev->xid_desc.bType == XID_TYPE_STEELBATTALION) { pad_cnt++; } xid_dev = xid_dev->next; } - JOY_DBGMSG("SDL_XBOX_JoystickGetCount: Found %i pads\n", pad_cnt); + SDL_Log("SDL_XBOX_JoystickGetCount: Found %i pads\n", pad_cnt); return pad_cnt; } @@ -231,8 +193,7 @@ static const char* SDL_XBOX_JoystickGetDeviceName(Sint32 device_index) { Uint32 max_len = sizeof(name[device_index]); Sint32 player_index = SDL_XBOX_JoystickGetDevicePlayerIndex(device_index); - switch (xid_dev->xid_desc.bType) - { + switch (xid_dev->xid_desc.bType) { case XID_TYPE_GAMECONTROLLER: SDL_snprintf(name[device_index], max_len, "Original Xbox Controller #%u", player_index); break; @@ -260,7 +221,7 @@ static Sint32 SDL_XBOX_JoystickGetDevicePlayerIndex(Sint32 device_index) { if (player_index == 0) { // fallback to device_index if xid_get_device_port fails (returns 0) player_index = device_index; } - JOY_DBGMSG("SDL_XBOX_JoystickGetDevicePlayerIndex: %i\n", player_index); + SDL_Log("SDL_XBOX_JoystickGetDevicePlayerIndex: %i\n", player_index); return player_index; } @@ -268,33 +229,38 @@ static Sint32 SDL_XBOX_JoystickGetDevicePlayerIndex(Sint32 device_index) { static SDL_JoystickGUID SDL_XBOX_JoystickGetDeviceGUID(Sint32 device_index) { xid_dev_t *xid_dev = xid_from_device_index(device_index); - SDL_JoystickGUID ret; - SDL_zero(ret); + SDL_JoystickGUID guid; + SDL_zero(guid); if (xid_dev != NULL) { - //Format based on SDL_gamecontrollerdb.h - ret.data[0] = 0x03; - ret.data[4] = xid_dev->idVendor & 0xFF; - ret.data[5] = (xid_dev->idVendor >> 8) & 0xFF; - ret.data[8] = xid_dev->idProduct & 0xFF; - ret.data[9] = (xid_dev->idProduct >> 8) & 0xFF; + // Format based on SDL_hidapijoystick.c + Uint16 *guid16 = (Uint16 *)guid.data; + + guid16[0] = SDL_SwapLE16(SDL_HARDWARE_BUS_USB); + guid16[2] = SDL_SwapLE16(xid_dev->idVendor); + guid16[4] = SDL_SwapLE16(xid_dev->idProduct); + + // guid16[5] XID_DESC Info + guid.data[10] = xid_dev->xid_desc.bType; + guid.data[11] = xid_dev->xid_desc.bSubType; + + guid16[6] = SDL_SwapLE16(xid_dev->xid_desc.bcdXid); + + // guid16[7] Mark this GUID as an XID device for use elsewhere + guid.data[14] = xid_dev->xid_desc.bDescriptorType; } - return ret; + return guid; } static SDL_JoystickID SDL_XBOX_JoystickGetDeviceInstanceID(Sint32 device_index) { + SDL_JoystickID joyID = -1; + xid_dev_t *xid_dev = xid_from_device_index(device_index); - - SDL_JoystickID ret; - SDL_zero(ret); - - if (xid_dev != NULL) - { - SDL_memcpy(&ret, &xid_dev->uid, sizeof(xid_dev->uid)); - } - JOY_DBGMSG("SDL_XBOX_JoystickGetDeviceInstanceID: %i\n", xid_dev->uid); - return ret; + if (xid_dev != NULL) joyID = xid_dev->uid; + + SDL_Log("SDL_XBOX_JoystickGetDeviceInstanceID: %d\n", joyID); + return joyID; } static Sint32 SDL_XBOX_JoystickOpen(SDL_Joystick *joystick, Sint32 device_index) { @@ -302,50 +268,40 @@ static Sint32 SDL_XBOX_JoystickOpen(SDL_Joystick *joystick, Sint32 device_index) if (xid_dev == NULL) { - JOY_DBGMSG("SDL_XBOX_JoystickOpen: Could not find device index %i\n", device_index); + SDL_Log("SDL_XBOX_JoystickOpen: Could not find device index %i\n", device_index); return -1; } - - joystick->hwdata = (pjoystick_hwdata)SDL_malloc(sizeof(joystick_hwdata)); + + joystick->hwdata = (joystick_hwdata *)SDL_malloc(sizeof(joystick_hwdata)); assert(joystick->hwdata != NULL); SDL_zerop(joystick->hwdata); - joystick->hwdata->xid_dev = xid_dev; - joystick->hwdata->xid_dev->user_data = (void *)joystick; + joystick->player_index = SDL_XBOX_JoystickGetDevicePlayerIndex(device_index); joystick->guid = SDL_XBOX_JoystickGetDeviceGUID(device_index); - switch (xid_dev->xid_desc.bType) - { - case XID_TYPE_GAMECONTROLLER: - joystick->naxes = 6; /* LStickY, LStickX, LTrigg, RStickY, RStickX, RTrigg */ - joystick->nballs = 0; /* No balls here */ - joystick->nhats = 1; /* D-pad */ - joystick->nbuttons = 10; /* A, B, X, Y, RB, LB, Back, Start, LThumb, RThumb */ - break; + switch (xid_dev->xid_desc.bType) { + case XID_TYPE_GAMECONTROLLER: gamepad_open(joystick); break; + case XID_TYPE_STEELBATTALION: sbc_open(joystick); break; case XID_TYPE_XREMOTE: joystick->naxes = 0; joystick->nballs = 0; joystick->nhats = 0; joystick->nbuttons = 27; break; - case XID_TYPE_STEELBATTALION: - joystick->naxes = 10; //Tuner dial and gear level are treated like an axis - joystick->nballs = 0; - joystick->nhats = 0; - joystick->nbuttons = 39; //This includes the toggle switches - break; default: SDL_free(joystick->hwdata); joystick->hwdata = NULL; return -1; } + + xid_dev->user_data = (void *)joystick; - JOY_DBGMSG("JoystickOpened:\n"); - JOY_DBGMSG("joystick device_index: %i\n", device_index); - JOY_DBGMSG("joystick player_index: %i\n", joystick->player_index); - JOY_DBGMSG("joystick uid: %i\n", xid_dev->uid); - JOY_DBGMSG("joystick name: %s\n", SDL_XBOX_JoystickGetDeviceName(device_index)); + SDL_Log("SDL_XBOX_JoystickOpen:\n"); + SDL_Log("joystick device_index: %i\n", device_index); + SDL_Log("joystick player_index: %i\n", joystick->player_index); + SDL_Log("joystick uid: %i\n", xid_dev->uid); + SDL_Log("joystick name: %s\n", SDL_XBOX_JoystickGetDeviceName(device_index)); //Start reading interrupt pipe usbh_xid_read(xid_dev, 0, int_read_callback); @@ -357,125 +313,39 @@ static Sint32 SDL_XBOX_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) { - - //Check if rumble values are new values. - if (joystick->hwdata->current_rumble[0] == low_frequency_rumble && - joystick->hwdata->current_rumble[1] == high_frequency_rumble) - { - //Rumble values not changed, reset the expiry timer and leave. - joystick->hwdata->rumble_expiry = SDL_GetTicks() + duration_ms; - return 0; - } - - if (usbh_xid_rumble(joystick->hwdata->xid_dev, low_frequency_rumble, high_frequency_rumble) != USBH_OK) - { - return -1; - } - - joystick->hwdata->current_rumble[0] = low_frequency_rumble; - joystick->hwdata->current_rumble[1] = high_frequency_rumble; - joystick->hwdata->rumble_expiry = SDL_GetTicks() + duration_ms; - return 0; + + xid_dev_t * xid_dev = xid_from_joystick(joystick); + if (xid_dev == NULL) return -1; + + if (xid_dev->xid_desc.bType != XID_TYPE_GAMECONTROLLER) return -1; + + return gamepad_rumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms); } static void SDL_XBOX_JoystickUpdate(SDL_Joystick *joystick) { - Sint16 wButtons, axis, this_joy; - Sint32 hat = SDL_HAT_CENTERED; - XINPUT_GAMEPAD xpad; - - if (joystick == NULL || joystick->hwdata == NULL || joystick->hwdata->xid_dev == NULL) - { - return; - } - - //Check if the rumble timer has expired. - if (joystick->hwdata->rumble_expiry && SDL_GetTicks() > joystick->hwdata->rumble_expiry) - { - usbh_xid_rumble(joystick->hwdata->xid_dev, 0, 0); - joystick->hwdata->rumble_expiry = 0; - joystick->hwdata->current_rumble[0] = 0; - joystick->hwdata->current_rumble[1] = 0; - } - - Uint8 button_data[MAX_PACKET_SIZE]; - SDL_memcpy(button_data, joystick->hwdata->raw_data, MAX_PACKET_SIZE); - - //FIXME. Steel Battalion and XREMOTE should be parsed differently. - if (parse_input_data(joystick->hwdata->xid_dev, &xpad, button_data)) - { - wButtons = xpad.wButtons; - - //HAT - if (wButtons & XINPUT_GAMEPAD_DPAD_UP) hat |= SDL_HAT_UP; - if (wButtons & XINPUT_GAMEPAD_DPAD_DOWN) hat |= SDL_HAT_DOWN; - if (wButtons & XINPUT_GAMEPAD_DPAD_LEFT) hat |= SDL_HAT_LEFT; - if (wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) hat |= SDL_HAT_RIGHT; - if (hat != joystick->hats[0]) { - SDL_PrivateJoystickHat(joystick, 0, hat); - } - - //DIGITAL BUTTONS - static const Sint32 btn_map[10][2] = - { - {0, XINPUT_GAMEPAD_A}, - {1, XINPUT_GAMEPAD_B}, - {2, XINPUT_GAMEPAD_X}, - {3, XINPUT_GAMEPAD_Y}, - {4, XINPUT_GAMEPAD_LEFT_SHOULDER}, - {5, XINPUT_GAMEPAD_RIGHT_SHOULDER}, - {6, XINPUT_GAMEPAD_BACK}, - {7, XINPUT_GAMEPAD_START}, - {8, XINPUT_GAMEPAD_LEFT_THUMB}, - {9, XINPUT_GAMEPAD_RIGHT_THUMB} - }; - for (Sint32 i = 0; i < (sizeof(btn_map) / sizeof(btn_map[0])); i++) - { - if (joystick->buttons[btn_map[i][0]] != ((wButtons & btn_map[i][1]) > 0)) - SDL_PrivateJoystickButton(joystick, btn_map[i][0], (wButtons & btn_map[i][1]) ? SDL_PRESSED : SDL_RELEASED); - } - - //TRIGGERS - //LEFT TRIGGER (0-255 must be converted to signed short) - if (xpad.bLeftTrigger != joystick->axes[2].value) - SDL_PrivateJoystickAxis(joystick, 2, ((xpad.bLeftTrigger << 8) | xpad.bLeftTrigger) - (1 << 15)); - //RIGHT TRIGGER (0-255 must be converted to signed short) - if (xpad.bRightTrigger != joystick->axes[5].value) - SDL_PrivateJoystickAxis(joystick, 5, ((xpad.bRightTrigger << 8) | xpad.bRightTrigger) - (1 << 15)); - - //ANALOG STICKS - //LEFT X-AXIS - axis = xpad.sThumbLX; - if (axis != joystick->axes[0].value) - SDL_PrivateJoystickAxis(joystick, 0, axis); - //LEFT Y-AXIS - axis = xpad.sThumbLY; - if (axis != joystick->axes[1].value) - SDL_PrivateJoystickAxis(joystick, 1, ~axis); - //RIGHT X-AXIS - axis = xpad.sThumbRX; - if (axis != joystick->axes[3].value) - SDL_PrivateJoystickAxis(joystick, 3, axis); - //RIGHT Y-AXIS - axis = xpad.sThumbRY; - if (axis != joystick->axes[4].value) - SDL_PrivateJoystickAxis(joystick, 4, ~axis); + xid_dev_t * xid_dev = xid_from_joystick(joystick); + if (xid_dev == NULL) return; + + switch (xid_dev->xid_desc.bType) { + case XID_TYPE_GAMECONTROLLER: gamepad_update(joystick); break; + case XID_TYPE_STEELBATTALION: sbc_update(joystick); break; } - return; } static void SDL_XBOX_JoystickClose(SDL_Joystick *joystick) { - JOY_DBGMSG("SDL_XBOX_JoystickClose:\n"); - if (joystick->hwdata == NULL) - return; - - usbh_xid_rumble(joystick->hwdata->xid_dev, 0, 0); - - xid_dev_t *xid_dev = joystick->hwdata->xid_dev; - xid_dev->user_data = NULL; + SDL_Log("SDL_XBOX_JoystickClose:\n"); + + xid_dev_t * xid_dev = xid_from_joystick(joystick); if (xid_dev != NULL) { - JOY_DBGMSG("Closing joystick:\n", joystick->hwdata->xid_dev->uid); - JOY_DBGMSG("joystick player_index: %i\n", joystick->player_index); + switch (xid_dev->xid_desc.bType) { + case XID_TYPE_GAMECONTROLLER: gamepad_close(joystick); break; + case XID_TYPE_STEELBATTALION: sbc_close(joystick); break; + } + xid_dev->user_data = NULL; + + SDL_Log("Closing joystick: %u\n", joystick->hwdata->xid_dev->uid); + SDL_Log("joystick player_index: %i\n", joystick->player_index); } SDL_free(joystick->hwdata); joystick->hwdata = NULL; @@ -483,7 +353,7 @@ static void SDL_XBOX_JoystickClose(SDL_Joystick *joystick) { } static void SDL_XBOX_JoystickQuit(void) { - JOY_DBGMSG("SDL_XBOX_JoystickQuit\n"); + SDL_Log("SDL_XBOX_JoystickQuit\n"); usbh_install_xid_conn_callback(NULL, NULL); //We dont call usbh_core_deinit() here incase the user is using //the USB stack in other parts of their application other than game controllers. @@ -504,44 +374,6 @@ SDL_JoystickDriver SDL_XBOX_JoystickDriver = { SDL_XBOX_JoystickQuit }; -static Sint32 parse_input_data(xid_dev_t *xid_dev, PXINPUT_GAMEPAD controller, Uint8 *rdata) { - if (xid_dev == NULL) - { - return 0; - } - - Uint16 wButtons = *((Uint16*)&rdata[2]); - controller->wButtons = 0; - - //Map digital buttons - if (wButtons & (1 << 0)) controller->wButtons |= XINPUT_GAMEPAD_DPAD_UP; - if (wButtons & (1 << 1)) controller->wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; - if (wButtons & (1 << 2)) controller->wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; - if (wButtons & (1 << 3)) controller->wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; - if (wButtons & (1 << 4)) controller->wButtons |= XINPUT_GAMEPAD_START; - if (wButtons & (1 << 5)) controller->wButtons |= XINPUT_GAMEPAD_BACK; - if (wButtons & (1 << 6)) controller->wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; - if (wButtons & (1 << 7)) controller->wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; - - //Analog buttons are converted to digital - if (rdata[4] > BUTTON_DEADZONE) controller->wButtons |= XINPUT_GAMEPAD_A; - if (rdata[5] > BUTTON_DEADZONE) controller->wButtons |= XINPUT_GAMEPAD_B; - if (rdata[6] > BUTTON_DEADZONE) controller->wButtons |= XINPUT_GAMEPAD_X; - if (rdata[7] > BUTTON_DEADZONE) controller->wButtons |= XINPUT_GAMEPAD_Y; - if (rdata[8] > BUTTON_DEADZONE) controller->wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; //BLACK - if (rdata[9] > BUTTON_DEADZONE) controller->wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; //WHITE - - //Map the left and right triggers - controller->bLeftTrigger = rdata[10]; - controller->bRightTrigger = rdata[11]; - - //Map analog sticks - controller->sThumbLX = *((Sint16 *)&rdata[12]); - controller->sThumbLY = *((Sint16 *)&rdata[14]); - controller->sThumbRX = *((Sint16 *)&rdata[16]); - controller->sThumbRY = *((Sint16 *)&rdata[18]); - return 1; -} #endif /* SDL_JOYSTICK_XBOX */ diff --git a/src/joystick/xbox/SDL_xboxjoystick.h b/src/joystick/xbox/SDL_xboxjoystick.h new file mode 100644 index 0000000000000..6b30018b544ad --- /dev/null +++ b/src/joystick/xbox/SDL_xboxjoystick.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +typedef struct gamepad_data { + Uint16 low_frequency_rumble; + Uint16 high_frequency_rumble; + Uint32 rumble_expiry; +} gamepad_data; + +typedef struct sbc_data { + Uint8 lights[STEELBATTALION_LIGHT_BYTES]; +} sbc_data; + +//Struct linked to SDL_Joystick +typedef struct joystick_hwdata +{ + xid_dev_t *xid_dev; + union { + xid_gamepad_in gamepad; + xid_steelbattalion_in sbc; + } in; + union { + gamepad_data gamepad; + sbc_data sbc; + } data; +} joystick_hwdata; + +xid_dev_t * xid_from_joystick(SDL_Joystick * joystick); + +void gamepad_open(SDL_Joystick * joystick); +void gamepad_update(SDL_Joystick *joystick); +Sint32 gamepad_rumble(SDL_Joystick *joystick, Uint16 lf_rumble, Uint16 hf_rumble, Uint32 duration_ms); +void gamepad_close(SDL_Joystick * joystick); + +void sbc_open(SDL_Joystick * joystick); +void sbc_update(SDL_Joystick *joystick); +void sbc_close(SDL_Joystick * joystick); diff --git a/src/joystick/xbox/gamepad.c b/src/joystick/xbox/gamepad.c new file mode 100644 index 0000000000000..052c43cd0094b --- /dev/null +++ b/src/joystick/xbox/gamepad.c @@ -0,0 +1,116 @@ +#include +#include "../SDL_sysjoystick.h" +#include "SDL_xboxjoystick.h" + +#include + +#define BUTTON_DEADZONE 0x20 + +static inline gamepad_data * get_gamepad_data(SDL_Joystick * joystick) { + return (joystick == NULL || joystick->hwdata == NULL) ? NULL : &joystick->hwdata->data.gamepad; +} + +void gamepad_open(SDL_Joystick * joystick) { + if (joystick == NULL) return; + + joystick->naxes = 6; /* LStickY, LStickX, LTrigg, RStickY, RStickX, RTrigg */ + joystick->nballs = 0; /* No balls here */ + joystick->nhats = 1; /* D-pad */ + joystick->nbuttons = 10; /* A, B, X, Y, RB, LB, Back, Start, LThumb, RThumb */ +} + +void gamepad_update(SDL_Joystick *joystick) { + gamepad_data * gamepad = get_gamepad_data(joystick); + if (gamepad == NULL) return; + + // Check if the rumble timer has expired. + if (gamepad->rumble_expiry && SDL_GetTicks() > gamepad->rumble_expiry) { + usbh_xid_rumble(joystick->hwdata->xid_dev, 0, 0); + gamepad->rumble_expiry = 0; + gamepad->low_frequency_rumble = 0; + gamepad->high_frequency_rumble = 0; + } + + xid_gamepad_in * inpad = &joystick->hwdata->in.gamepad; + + // Fill out the rest of the buttons from the analog inputs + if (inpad->a > BUTTON_DEADZONE) inpad->dButtons |= XINPUT_GAMEPAD_A; + if (inpad->b > BUTTON_DEADZONE) inpad->dButtons |= XINPUT_GAMEPAD_B; + if (inpad->x > BUTTON_DEADZONE) inpad->dButtons |= XINPUT_GAMEPAD_X; + if (inpad->y > BUTTON_DEADZONE) inpad->dButtons |= XINPUT_GAMEPAD_Y; + if (inpad->black > BUTTON_DEADZONE) inpad->dButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; + if (inpad->white > BUTTON_DEADZONE) inpad->dButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; + + //HAT + Sint32 hat = SDL_HAT_CENTERED; + if (inpad->dButtons & XINPUT_GAMEPAD_DPAD_UP) hat |= SDL_HAT_UP; + if (inpad->dButtons & XINPUT_GAMEPAD_DPAD_DOWN) hat |= SDL_HAT_DOWN; + if (inpad->dButtons & XINPUT_GAMEPAD_DPAD_LEFT) hat |= SDL_HAT_LEFT; + if (inpad->dButtons & XINPUT_GAMEPAD_DPAD_RIGHT) hat |= SDL_HAT_RIGHT; + SDL_PrivateJoystickHat(joystick, 0, hat); + + //DIGITAL BUTTONS + static const uint16_t btn_map[10] = + { + XINPUT_GAMEPAD_A, + XINPUT_GAMEPAD_B, + XINPUT_GAMEPAD_X, + XINPUT_GAMEPAD_Y, + XINPUT_GAMEPAD_LEFT_SHOULDER, + XINPUT_GAMEPAD_RIGHT_SHOULDER, + XINPUT_GAMEPAD_BACK, + XINPUT_GAMEPAD_START, + XINPUT_GAMEPAD_LEFT_THUMB, + XINPUT_GAMEPAD_RIGHT_THUMB + }; + + for (int i = 0; i < (sizeof(btn_map) / sizeof(btn_map[0])); i++) { + SDL_PrivateJoystickButton(joystick, i, (inpad->dButtons & btn_map[i]) ? SDL_PRESSED : SDL_RELEASED); + } + + //TRIGGERS + //LEFT TRIGGER (0-255 must be converted to signed short) + SDL_PrivateJoystickAxis(joystick, 2, ((inpad->leftTrigger << 8) | inpad->leftTrigger) - 0x8000); + //RIGHT TRIGGER (0-255 must be converted to signed short) + SDL_PrivateJoystickAxis(joystick, 5, ((inpad->rightTrigger << 8) | inpad->rightTrigger) - 0x8000); + + //ANALOG STICKS + //LEFT X-AXIS + SDL_PrivateJoystickAxis(joystick, 0, inpad->leftStickX); + //LEFT Y-AXIS + SDL_PrivateJoystickAxis(joystick, 1, inpad->leftStickY); + //RIGHT X-AXIS + SDL_PrivateJoystickAxis(joystick, 3, inpad->rightStickX); + //RIGHT Y-AXIS + SDL_PrivateJoystickAxis(joystick, 4, inpad->rightStickY); +} + +Sint32 gamepad_rumble(SDL_Joystick * joystick, Uint16 lf_rumble, Uint16 hf_rumble, Uint32 duration_ms) { + gamepad_data * gamepad = get_gamepad_data(joystick); + if (gamepad == NULL) return -1; + + //Check if rumble values are new values. + if (gamepad->low_frequency_rumble == lf_rumble + && gamepad->high_frequency_rumble == hf_rumble) + { + //Rumble values not changed, reset the expiry timer and leave. + gamepad->rumble_expiry = SDL_GetTicks() + duration_ms; + return 0; + } + + xid_dev_t * xid_dev = xid_from_joystick(joystick); + if (usbh_xid_rumble(xid_dev, lf_rumble, hf_rumble) != USBH_OK) + { + return -1; + } + + gamepad->low_frequency_rumble = lf_rumble; + gamepad->high_frequency_rumble = hf_rumble; + gamepad->rumble_expiry = SDL_GetTicks() + duration_ms; + + return 0; +} + +void gamepad_close(SDL_Joystick * joystick) { + usbh_xid_rumble(joystick->hwdata->xid_dev, 0, 0); +} diff --git a/src/joystick/xbox/sbc.c b/src/joystick/xbox/sbc.c new file mode 100644 index 0000000000000..35bc186cb5c9c --- /dev/null +++ b/src/joystick/xbox/sbc.c @@ -0,0 +1,126 @@ +#include +#include "../SDL_sysjoystick.h" +#include "SDL_xboxjoystick.h" + +#include + +enum SBC_BUTTON { + BUTTON_FIRE_MAIN, + BUTTON_FIRE_SUB, + BUTTON_LOCK_ON, + BUTTON_EJECT, + BUTTON_HATCH, + BUTTON_IGNITION, + BUTTON_START, + BUTTON_MULTI_TOGGLE, + BUTTON_MULTI_ZOOM, + BUTTON_MULTI_MODE, + BUTTON_SUB_MODE, + BUTTON_ZOOM_IN, + BUTTON_ZOOM_OUT, + BUTTON_FSS, + BUTTON_MANIPULATOR, + BUTTON_LINE_COLOR_CHANGE, + BUTTON_WASHING, + BUTTON_EXTINGUISHER, + BUTTON_CHAFF, + BUTTON_TANK_DETACH, + BUTTON_OVERRIDE, + BUTTON_NIGHT_SCOPE, + BUTTON_F1, + BUTTON_F2, + BUTTON_F3, + BUTTON_CYCLE_MAIN, + BUTTON_CYCLE_SUB, + BUTTON_MAG_CHANGE, + BUTTON_COMM_1, + BUTTON_COMM_2, + BUTTON_COMM_3, + BUTTON_COMM_4, + BUTTON_COMM_5, + BUTTON_SIGHT_CHANGE, + // Toggle Switches + SWITCH_FILTER, + SWITCH_OXYGEN, + SWITCH_FUEL, + SWITCH_BUFFER, + SWITCH_LOCATION, + + SBC_BUTTON_COUNT +}; + +enum SBC_AXIS { + AXIS_AIM_X, + AXIS_AIM_Y, + + AXIS_TURN, + + AXIS_SIGHT_X, + AXIS_SIGHT_Y, + + AXIS_SLIDE, + AXIS_BRAKE, + AXIS_ACCEL, + + AXIS_TUNER, + AXIS_SHIFTER, + + SBC_AXIS_COUNT +}; + +static inline sbc_data * get_sbc_data(SDL_Joystick * joystick) { + return (joystick == NULL || joystick->hwdata == NULL) ? NULL : &joystick->hwdata->data.sbc; +} + +void sbc_open(SDL_Joystick * joystick) { + if (joystick == NULL) return; + + joystick->naxes = SBC_AXIS_COUNT; + joystick->nballs = 0; + joystick->nhats = 0; + joystick->nbuttons = SBC_BUTTON_COUNT; //This includes the toggle switches +} + +static Uint8 get_sbc_button_pressed(xid_steelbattalion_in * insbc, enum SBC_BUTTON btn) { + unsigned int button_offset = btn / 16; + Uint16 button_mask = 1 << (btn % 16); + + return (insbc->buttons[button_offset] & button_mask) ? SDL_PRESSED : SDL_RELEASED; +} + +void sbc_update(SDL_Joystick *joystick) { + sbc_data * sbc = get_sbc_data(joystick); + if (sbc == NULL) return; + + xid_steelbattalion_in * insbc = &joystick->hwdata->in.sbc; + + for (enum SBC_BUTTON btn = 0; btn < SBC_BUTTON_COUNT; btn++) { + SDL_PrivateJoystickButton(joystick, btn, get_sbc_button_pressed(insbc, btn)); + } + + // Aiming Lever (convert from unsigned to signed) + SDL_PrivateJoystickAxis(joystick, AXIS_AIM_X, insbc->aimingLeverX); + SDL_PrivateJoystickAxis(joystick, AXIS_AIM_Y, insbc->aimingLeverY); + + // Turning Lever + SDL_PrivateJoystickAxis(joystick, AXIS_TURN, insbc->turningLever); + + // Sight Change + SDL_PrivateJoystickAxis(joystick, AXIS_SIGHT_X, insbc->sightChangeX); + SDL_PrivateJoystickAxis(joystick, AXIS_SIGHT_Y, insbc->sightChangeY); + + // Pedals (convert from unsigned to signed) + SDL_PrivateJoystickAxis(joystick, AXIS_SLIDE, insbc->slidePedal); + SDL_PrivateJoystickAxis(joystick, AXIS_ACCEL, insbc->accelPedal); + SDL_PrivateJoystickAxis(joystick, AXIS_BRAKE, insbc->brakePedal); + + // Tuner MIN=0, MAX=15 + SDL_PrivateJoystickAxis(joystick, AXIS_TUNER, insbc->tuner); + + // Shifter MIN=-2, MAX=5 + SDL_PrivateJoystickAxis(joystick, AXIS_SHIFTER, insbc->shifter); +} + +void sbc_close(SDL_Joystick * joystick) { + +}