From 8f13d0831b2cdad18164d968d5d6cf67b58d9ea3 Mon Sep 17 00:00:00 2001 From: Samuel Deutsch Date: Fri, 27 Jun 2025 01:58:35 -0700 Subject: [PATCH 1/6] Added support for the Steel Battalion Controller --- src/joystick/xbox/SDL_xboxjoystick.c | 244 +++++---------------------- src/joystick/xbox/SDL_xboxjoystick.h | 38 +++++ src/joystick/xbox/gamepad.c | 191 +++++++++++++++++++++ src/joystick/xbox/sbc.c | 143 ++++++++++++++++ 4 files changed, 411 insertions(+), 205 deletions(-) create mode 100644 src/joystick/xbox/SDL_xboxjoystick.h create mode 100644 src/joystick/xbox/gamepad.c create mode 100644 src/joystick/xbox/sbc.c diff --git a/src/joystick/xbox/SDL_xboxjoystick.c b/src/joystick/xbox/SDL_xboxjoystick.c index 8afdb3dfe4d9e..7353dda5ce4fa 100644 --- a/src/joystick/xbox/SDL_xboxjoystick.c +++ b/src/joystick/xbox/SDL_xboxjoystick.c @@ -31,6 +31,7 @@ #include "SDL_events.h" #include "../SDL_joystick_c.h" #include "../SDL_sysjoystick.h" +#include "SDL_xboxjoystick.h" #include #include @@ -48,48 +49,6 @@ #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); @@ -130,6 +89,10 @@ static void int_read_callback(UTR_T *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) { xid_dev_t *xid_dev = usbh_xid_get_device_list(); @@ -206,8 +169,9 @@ 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++; } @@ -305,41 +269,31 @@ static Sint32 SDL_XBOX_JoystickOpen(SDL_Joystick *joystick, Sint32 device_index) JOY_DBGMSG("SDL_XBOX_JoystickOpen: Could not find device index %i\n", device_index); return -1; } - + joystick->hwdata = (pjoystick_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); @@ -357,123 +311,41 @@ 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; + + xid_dev_t * xid_dev = xid_from_joystick(joystick); + if (xid_dev == NULL) return -1; + + switch (xid_dev->xid_desc.bType) { + case XID_TYPE_GAMECONTROLLER: return gamepad_rumble(joystick, + low_frequency_rumble, + high_frequency_rumble, + duration_ms); + default: 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; } 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; + + xid_dev_t * xid_dev = xid_from_joystick(joystick); if (xid_dev != NULL) { + 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; + JOY_DBGMSG("Closing joystick:\n", joystick->hwdata->xid_dev->uid); JOY_DBGMSG("joystick player_index: %i\n", joystick->player_index); } @@ -504,44 +376,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..69d1a13ccf213 --- /dev/null +++ b/src/joystick/xbox/SDL_xboxjoystick.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +#define MAX_PACKET_SIZE 32 +#define SBC_LIGHT_COUNT 48 + +typedef struct gamepad_data { + Uint16 low_frequency_rumble; + Uint16 high_frequency_rumble; + Uint32 rumble_expiry; +} gamepad_data, *pgamepad_data; + +typedef struct sbc_data { + Uint8 lights[SBC_LIGHT_COUNT / 2]; +} sbc_data, *psbc_data; + +//Struct linked to SDL_Joystick +typedef struct joystick_hwdata +{ + xid_dev_t *xid_dev; + Uint8 raw_data[MAX_PACKET_SIZE]; + union { + gamepad_data gamepad; + sbc_data sbc; + } data; +} joystick_hwdata, *pjoystick_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..f14239b59cb87 --- /dev/null +++ b/src/joystick/xbox/gamepad.c @@ -0,0 +1,191 @@ +#include +#include "../SDL_sysjoystick.h" +#include "SDL_xboxjoystick.h" + +#include + +#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; + +static inline pgamepad_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) { + pgamepad_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; + } + + Uint8 rdata[MAX_PACKET_SIZE]; + SDL_memcpy(rdata, joystick->hwdata->raw_data, MAX_PACKET_SIZE); + + XINPUT_GAMEPAD xpad; + + { + Uint16 wButtons = *((Uint16*)&rdata[2]); + xpad.wButtons = 0; + + // Map digital buttons + if (wButtons & (1 << 0)) xpad.wButtons |= XINPUT_GAMEPAD_DPAD_UP; + if (wButtons & (1 << 1)) xpad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; + if (wButtons & (1 << 2)) xpad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; + if (wButtons & (1 << 3)) xpad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; + if (wButtons & (1 << 4)) xpad.wButtons |= XINPUT_GAMEPAD_START; + if (wButtons & (1 << 5)) xpad.wButtons |= XINPUT_GAMEPAD_BACK; + if (wButtons & (1 << 6)) xpad.wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; + if (wButtons & (1 << 7)) xpad.wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; + + //Analog buttons are converted to digital + if (rdata[4] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_A; + if (rdata[5] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_B; + if (rdata[6] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_X; + if (rdata[7] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_Y; + if (rdata[8] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; //BLACK + if (rdata[9] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; //WHITE + } + + //Map the left and right triggers + xpad.bLeftTrigger = rdata[10]; + xpad.bRightTrigger = rdata[11]; + + //Map analog sticks + xpad.sThumbLX = *((Sint16 *)&rdata[12]); + xpad.sThumbLY = *((Sint16 *)&rdata[14]); + xpad.sThumbRX = *((Sint16 *)&rdata[16]); + xpad.sThumbRY = *((Sint16 *)&rdata[18]); + + //HAT + { + Sint32 hat = SDL_HAT_CENTERED; + if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_UP) hat |= SDL_HAT_UP; + if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) hat |= SDL_HAT_DOWN; + if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) hat |= SDL_HAT_LEFT; + if (xpad.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]] != ((xpad.wButtons & btn_map[i][1]) > 0)) + SDL_PrivateJoystickButton(joystick, btn_map[i][0], (xpad.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 + { + Sint16 axis; + //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); + } +} + +Sint32 gamepad_rumble(SDL_Joystick * joystick, Uint16 lf_rumble, Uint16 hf_rumble, Uint32 duration_ms) { + pgamepad_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..acab5583e390d --- /dev/null +++ b/src/joystick/xbox/sbc.c @@ -0,0 +1,143 @@ +#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 +}; + +// Steel Battalion Controller +typedef struct _XINPUT_SBC +{ + Uint16 buttons[3]; + Uint16 aimingLeverX; // 0 = Left, 0xFFFF = Right + Uint16 aimingLeverY; // 0 = Top, 0xFFFF = Bottom + Sint16 turningLever; + Sint16 sightChangeX; + Sint16 sightChangeY; + Uint16 slidePedal; + Uint16 brakePedal; + Uint16 accelPedal; + Uint8 tuner; // 0-15 is from 9oclock, around clockwise + Sint8 shifter; // -2 = R, -1 = N, 0 = Error, 1 = 1st, 2 = 2nd, 3 = 3rnd, 4 = 4th, 5 = 5th +} XINPUT_SBC, *PXINPUT_SBC; + +static inline psbc_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 SDL_bool get_sbc_button_pressed(PXINPUT_SBC xsbc, enum SBC_BUTTON btn) { + unsigned int button_offset = btn / 16; + Uint16 button_mask = 1 << (btn % 16); + + return (xsbc->buttons[button_offset] & button_mask) ? SDL_TRUE : SDL_FALSE; +} + +void sbc_update(SDL_Joystick *joystick) { + psbc_data sbc = get_sbc_data(joystick); + if (sbc == NULL) return; + + XINPUT_SBC xsbc; + SDL_memcpy(&xsbc, joystick->hwdata->raw_data, sizeof(XINPUT_SBC)); + + for (enum SBC_BUTTON btn = 0; btn < SBC_BUTTON_COUNT; btn++) { + SDL_PrivateJoystickButton(joystick, btn, get_sbc_button_pressed(&xsbc, btn)); + } + + // Aiming Lever (convert from unsigned to signed) + SDL_PrivateJoystickAxis(joystick, AXIS_AIM_X, xsbc.aimingLeverX >> 1); + SDL_PrivateJoystickAxis(joystick, AXIS_AIM_Y, xsbc.aimingLeverY >> 1); + + // Turning Lever + SDL_PrivateJoystickAxis(joystick, AXIS_TURN, xsbc.turningLever); + + // Sight Change + SDL_PrivateJoystickAxis(joystick, AXIS_SIGHT_X, xsbc.sightChangeX); + SDL_PrivateJoystickAxis(joystick, AXIS_SIGHT_Y, xsbc.sightChangeY); + + // Pedals (convert from unsigned to signed) + SDL_PrivateJoystickAxis(joystick, AXIS_SLIDE, xsbc.slidePedal >> 1); + SDL_PrivateJoystickAxis(joystick, AXIS_ACCEL, xsbc.accelPedal >> 1); + SDL_PrivateJoystickAxis(joystick, AXIS_BRAKE, xsbc.brakePedal >> 1); + + // Tuner MIN=0, MAX=15 + SDL_PrivateJoystickAxis(joystick, AXIS_TUNER, xsbc.tuner); + + // Shifter MIN=-1, MAX=5 + SDL_PrivateJoystickAxis(joystick, AXIS_SHIFTER, xsbc.shifter); +} + +void sbc_close(SDL_Joystick * joystick) { + +} From 38d77964097d270e954c3c1da56f0624e413537d Mon Sep 17 00:00:00 2001 From: Samuel Deutsch Date: Fri, 27 Jun 2025 02:13:20 -0700 Subject: [PATCH 2/6] Skip first two bytes of SBC input --- src/joystick/xbox/gamepad.c | 23 ++++++++++------------- src/joystick/xbox/sbc.c | 2 +- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/joystick/xbox/gamepad.c b/src/joystick/xbox/gamepad.c index f14239b59cb87..f11d90bd8d3dc 100644 --- a/src/joystick/xbox/gamepad.c +++ b/src/joystick/xbox/gamepad.c @@ -59,13 +59,10 @@ void gamepad_update(SDL_Joystick *joystick) { gamepad->low_frequency_rumble = 0; gamepad->high_frequency_rumble = 0; } - - Uint8 rdata[MAX_PACKET_SIZE]; - SDL_memcpy(rdata, joystick->hwdata->raw_data, MAX_PACKET_SIZE); XINPUT_GAMEPAD xpad; - { + Uint8 * rdata = joystick->hwdata->raw_data; Uint16 wButtons = *((Uint16*)&rdata[2]); xpad.wButtons = 0; @@ -86,17 +83,17 @@ void gamepad_update(SDL_Joystick *joystick) { if (rdata[7] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_Y; if (rdata[8] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; //BLACK if (rdata[9] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; //WHITE - } - //Map the left and right triggers - xpad.bLeftTrigger = rdata[10]; - xpad.bRightTrigger = rdata[11]; + //Map the left and right triggers + xpad.bLeftTrigger = rdata[10]; + xpad.bRightTrigger = rdata[11]; - //Map analog sticks - xpad.sThumbLX = *((Sint16 *)&rdata[12]); - xpad.sThumbLY = *((Sint16 *)&rdata[14]); - xpad.sThumbRX = *((Sint16 *)&rdata[16]); - xpad.sThumbRY = *((Sint16 *)&rdata[18]); + //Map analog sticks + xpad.sThumbLX = *((Sint16 *)&rdata[12]); + xpad.sThumbLY = *((Sint16 *)&rdata[14]); + xpad.sThumbRX = *((Sint16 *)&rdata[16]); + xpad.sThumbRY = *((Sint16 *)&rdata[18]); + } //HAT { diff --git a/src/joystick/xbox/sbc.c b/src/joystick/xbox/sbc.c index acab5583e390d..f0408b585056c 100644 --- a/src/joystick/xbox/sbc.c +++ b/src/joystick/xbox/sbc.c @@ -109,7 +109,7 @@ void sbc_update(SDL_Joystick *joystick) { if (sbc == NULL) return; XINPUT_SBC xsbc; - SDL_memcpy(&xsbc, joystick->hwdata->raw_data, sizeof(XINPUT_SBC)); + SDL_memcpy(&xsbc, joystick->hwdata->raw_data + 2, sizeof(XINPUT_SBC)); for (enum SBC_BUTTON btn = 0; btn < SBC_BUTTON_COUNT; btn++) { SDL_PrivateJoystickButton(joystick, btn, get_sbc_button_pressed(&xsbc, btn)); From e68add6884f154211fdca8624c019263de524135 Mon Sep 17 00:00:00 2001 From: Samuel Deutsch Date: Sat, 28 Jun 2025 00:55:39 -0700 Subject: [PATCH 3/6] Use xid_in structures for input --- src/joystick/xbox/SDL_xboxjoystick.c | 77 ++++++-------- src/joystick/xbox/SDL_xboxjoystick.h | 22 ++-- src/joystick/xbox/gamepad.c | 154 +++++++-------------------- src/joystick/xbox/sbc.c | 51 +++------ 4 files changed, 106 insertions(+), 198 deletions(-) diff --git a/src/joystick/xbox/SDL_xboxjoystick.c b/src/joystick/xbox/SDL_xboxjoystick.c index 7353dda5ce4fa..d33448bcf4427 100644 --- a/src/joystick/xbox/SDL_xboxjoystick.c +++ b/src/joystick/xbox/SDL_xboxjoystick.c @@ -40,14 +40,6 @@ #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 static Sint32 SDL_XBOX_JoystickGetDevicePlayerIndex(Sint32 device_index); @@ -71,22 +63,27 @@ 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 (joy->hwdata != NULL) - { - SDL_memcpy(joy->hwdata->raw_data, utr->buff, data_len); + if (data_len > utr->xfer_len) data_len = utr->xfer_len; + + if (!data_len) return; - //Re-queue the USB transfer - utr->xfer_len = 0; - utr->bIsTransferDone = 0; - usbh_int_xfer(utr); - } + 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); } xid_dev_t * xid_from_joystick(SDL_Joystick * joystick) { @@ -100,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; @@ -195,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; @@ -248,16 +245,12 @@ static SDL_JoystickGUID SDL_XBOX_JoystickGetDeviceGUID(Sint32 device_index) { } static SDL_JoystickID SDL_XBOX_JoystickGetDeviceInstanceID(Sint32 device_index) { + SDL_JoystickID ret = -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); + if (xid_dev != NULL) ret = xid_dev->uid; + + JOY_DBGMSG("SDL_XBOX_JoystickGetDeviceInstanceID: %d\n", ret); return ret; } @@ -270,7 +263,7 @@ static Sint32 SDL_XBOX_JoystickOpen(SDL_Joystick *joystick, Sint32 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; @@ -315,13 +308,9 @@ static Sint32 SDL_XBOX_JoystickRumble(SDL_Joystick *joystick, xid_dev_t * xid_dev = xid_from_joystick(joystick); if (xid_dev == NULL) return -1; - switch (xid_dev->xid_desc.bType) { - case XID_TYPE_GAMECONTROLLER: return gamepad_rumble(joystick, - low_frequency_rumble, - high_frequency_rumble, - duration_ms); - default: 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) { @@ -346,7 +335,7 @@ static void SDL_XBOX_JoystickClose(SDL_Joystick *joystick) { } xid_dev->user_data = NULL; - JOY_DBGMSG("Closing joystick:\n", joystick->hwdata->xid_dev->uid); + JOY_DBGMSG("Closing joystick: %u\n", joystick->hwdata->xid_dev->uid); JOY_DBGMSG("joystick player_index: %i\n", joystick->player_index); } SDL_free(joystick->hwdata); diff --git a/src/joystick/xbox/SDL_xboxjoystick.h b/src/joystick/xbox/SDL_xboxjoystick.h index 69d1a13ccf213..44c8f0cd72552 100644 --- a/src/joystick/xbox/SDL_xboxjoystick.h +++ b/src/joystick/xbox/SDL_xboxjoystick.h @@ -2,29 +2,37 @@ #include -#define MAX_PACKET_SIZE 32 -#define SBC_LIGHT_COUNT 48 +//#define SDL_JOYSTICK_XBOX_DEBUG +#ifdef SDL_JOYSTICK_XBOX_DEBUG +#include +#define JOY_DBGMSG debugPrint +#else +#define JOY_DBGMSG(...) +#endif typedef struct gamepad_data { Uint16 low_frequency_rumble; Uint16 high_frequency_rumble; Uint32 rumble_expiry; -} gamepad_data, *pgamepad_data; +} gamepad_data; typedef struct sbc_data { - Uint8 lights[SBC_LIGHT_COUNT / 2]; -} sbc_data, *psbc_data; + Uint8 lights[STEELBATTALION_LIGHT_BYTES]; +} sbc_data; //Struct linked to SDL_Joystick typedef struct joystick_hwdata { xid_dev_t *xid_dev; - Uint8 raw_data[MAX_PACKET_SIZE]; + union { + xid_gamepad_in gamepad; + xid_steelbattalion_in sbc; + } in; union { gamepad_data gamepad; sbc_data sbc; } data; -} joystick_hwdata, *pjoystick_hwdata; +} joystick_hwdata; xid_dev_t * xid_from_joystick(SDL_Joystick * joystick); diff --git a/src/joystick/xbox/gamepad.c b/src/joystick/xbox/gamepad.c index f11d90bd8d3dc..052c43cd0094b 100644 --- a/src/joystick/xbox/gamepad.c +++ b/src/joystick/xbox/gamepad.c @@ -6,36 +6,7 @@ #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; - -static inline pgamepad_data get_gamepad_data(SDL_Joystick * joystick) { +static inline gamepad_data * get_gamepad_data(SDL_Joystick * joystick) { return (joystick == NULL || joystick->hwdata == NULL) ? NULL : &joystick->hwdata->data.gamepad; } @@ -49,7 +20,7 @@ void gamepad_open(SDL_Joystick * joystick) { } void gamepad_update(SDL_Joystick *joystick) { - pgamepad_data gamepad = get_gamepad_data(joystick); + gamepad_data * gamepad = get_gamepad_data(joystick); if (gamepad == NULL) return; // Check if the rumble timer has expired. @@ -60,105 +31,62 @@ void gamepad_update(SDL_Joystick *joystick) { gamepad->high_frequency_rumble = 0; } - XINPUT_GAMEPAD xpad; - { - Uint8 * rdata = joystick->hwdata->raw_data; - Uint16 wButtons = *((Uint16*)&rdata[2]); - xpad.wButtons = 0; - - // Map digital buttons - if (wButtons & (1 << 0)) xpad.wButtons |= XINPUT_GAMEPAD_DPAD_UP; - if (wButtons & (1 << 1)) xpad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; - if (wButtons & (1 << 2)) xpad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; - if (wButtons & (1 << 3)) xpad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; - if (wButtons & (1 << 4)) xpad.wButtons |= XINPUT_GAMEPAD_START; - if (wButtons & (1 << 5)) xpad.wButtons |= XINPUT_GAMEPAD_BACK; - if (wButtons & (1 << 6)) xpad.wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; - if (wButtons & (1 << 7)) xpad.wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; - - //Analog buttons are converted to digital - if (rdata[4] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_A; - if (rdata[5] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_B; - if (rdata[6] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_X; - if (rdata[7] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_Y; - if (rdata[8] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; //BLACK - if (rdata[9] > BUTTON_DEADZONE) xpad.wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; //WHITE - - //Map the left and right triggers - xpad.bLeftTrigger = rdata[10]; - xpad.bRightTrigger = rdata[11]; - - //Map analog sticks - xpad.sThumbLX = *((Sint16 *)&rdata[12]); - xpad.sThumbLY = *((Sint16 *)&rdata[14]); - xpad.sThumbRX = *((Sint16 *)&rdata[16]); - xpad.sThumbRY = *((Sint16 *)&rdata[18]); - } + 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 (xpad.wButtons & XINPUT_GAMEPAD_DPAD_UP) hat |= SDL_HAT_UP; - if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) hat |= SDL_HAT_DOWN; - if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) hat |= SDL_HAT_LEFT; - if (xpad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) hat |= SDL_HAT_RIGHT; - if (hat != joystick->hats[0]) { - SDL_PrivateJoystickHat(joystick, 0, 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 Sint32 btn_map[10][2] = + static const uint16_t btn_map[10] = { - {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} + 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 (Sint32 i = 0; i < (sizeof(btn_map) / sizeof(btn_map[0])); i++) { - if (joystick->buttons[btn_map[i][0]] != ((xpad.wButtons & btn_map[i][1]) > 0)) - SDL_PrivateJoystickButton(joystick, btn_map[i][0], (xpad.wButtons & btn_map[i][1]) ? SDL_PRESSED : SDL_RELEASED); + 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) - if (xpad.bLeftTrigger != joystick->axes[2].value) - SDL_PrivateJoystickAxis(joystick, 2, ((xpad.bLeftTrigger << 8) | xpad.bLeftTrigger) - (1 << 15)); + SDL_PrivateJoystickAxis(joystick, 2, ((inpad->leftTrigger << 8) | inpad->leftTrigger) - 0x8000); //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)); + SDL_PrivateJoystickAxis(joystick, 5, ((inpad->rightTrigger << 8) | inpad->rightTrigger) - 0x8000); //ANALOG STICKS - { - Sint16 axis; - //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); - } + //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) { - pgamepad_data gamepad = get_gamepad_data(joystick); + gamepad_data * gamepad = get_gamepad_data(joystick); if (gamepad == NULL) return -1; //Check if rumble values are new values. diff --git a/src/joystick/xbox/sbc.c b/src/joystick/xbox/sbc.c index f0408b585056c..cc70ee9c7951d 100644 --- a/src/joystick/xbox/sbc.c +++ b/src/joystick/xbox/sbc.c @@ -68,23 +68,7 @@ enum SBC_AXIS { SBC_AXIS_COUNT }; -// Steel Battalion Controller -typedef struct _XINPUT_SBC -{ - Uint16 buttons[3]; - Uint16 aimingLeverX; // 0 = Left, 0xFFFF = Right - Uint16 aimingLeverY; // 0 = Top, 0xFFFF = Bottom - Sint16 turningLever; - Sint16 sightChangeX; - Sint16 sightChangeY; - Uint16 slidePedal; - Uint16 brakePedal; - Uint16 accelPedal; - Uint8 tuner; // 0-15 is from 9oclock, around clockwise - Sint8 shifter; // -2 = R, -1 = N, 0 = Error, 1 = 1st, 2 = 2nd, 3 = 3rnd, 4 = 4th, 5 = 5th -} XINPUT_SBC, *PXINPUT_SBC; - -static inline psbc_data get_sbc_data(SDL_Joystick * joystick) { +static inline sbc_data * get_sbc_data(SDL_Joystick * joystick) { return (joystick == NULL || joystick->hwdata == NULL) ? NULL : &joystick->hwdata->data.sbc; } @@ -97,45 +81,44 @@ void sbc_open(SDL_Joystick * joystick) { joystick->nbuttons = SBC_BUTTON_COUNT; //This includes the toggle switches } -static SDL_bool get_sbc_button_pressed(PXINPUT_SBC xsbc, enum SBC_BUTTON btn) { +static SDL_bool 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 (xsbc->buttons[button_offset] & button_mask) ? SDL_TRUE : SDL_FALSE; + return (insbc->buttons[button_offset] & button_mask) ? SDL_TRUE : SDL_FALSE; } void sbc_update(SDL_Joystick *joystick) { - psbc_data sbc = get_sbc_data(joystick); + sbc_data * sbc = get_sbc_data(joystick); if (sbc == NULL) return; - XINPUT_SBC xsbc; - SDL_memcpy(&xsbc, joystick->hwdata->raw_data + 2, sizeof(XINPUT_SBC)); + 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(&xsbc, btn)); + SDL_PrivateJoystickButton(joystick, btn, get_sbc_button_pressed(insbc, btn)); } // Aiming Lever (convert from unsigned to signed) - SDL_PrivateJoystickAxis(joystick, AXIS_AIM_X, xsbc.aimingLeverX >> 1); - SDL_PrivateJoystickAxis(joystick, AXIS_AIM_Y, xsbc.aimingLeverY >> 1); + SDL_PrivateJoystickAxis(joystick, AXIS_AIM_X, insbc->aimingLeverX); + SDL_PrivateJoystickAxis(joystick, AXIS_AIM_Y, insbc->aimingLeverY); // Turning Lever - SDL_PrivateJoystickAxis(joystick, AXIS_TURN, xsbc.turningLever); + SDL_PrivateJoystickAxis(joystick, AXIS_TURN, insbc->turningLever); // Sight Change - SDL_PrivateJoystickAxis(joystick, AXIS_SIGHT_X, xsbc.sightChangeX); - SDL_PrivateJoystickAxis(joystick, AXIS_SIGHT_Y, xsbc.sightChangeY); + 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, xsbc.slidePedal >> 1); - SDL_PrivateJoystickAxis(joystick, AXIS_ACCEL, xsbc.accelPedal >> 1); - SDL_PrivateJoystickAxis(joystick, AXIS_BRAKE, xsbc.brakePedal >> 1); + 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, xsbc.tuner); + SDL_PrivateJoystickAxis(joystick, AXIS_TUNER, insbc->tuner); - // Shifter MIN=-1, MAX=5 - SDL_PrivateJoystickAxis(joystick, AXIS_SHIFTER, xsbc.shifter); + // Shifter MIN=-2, MAX=5 + SDL_PrivateJoystickAxis(joystick, AXIS_SHIFTER, insbc->shifter); } void sbc_close(SDL_Joystick * joystick) { From 54591b404eaea41fffa5d28b2cd5b161a5208917 Mon Sep 17 00:00:00 2001 From: Samuel Deutsch Date: Mon, 30 Jun 2025 03:18:54 -0700 Subject: [PATCH 4/6] Expand GUID to include more XID data. Added proper controller mappings --- src/joystick/SDL_gamecontroller.c | 8 ---- src/joystick/SDL_gamecontrollerdb.h | 9 +++- src/joystick/SDL_joystick.c | 34 ++++++++++++++- src/joystick/SDL_joystick_c.h | 3 ++ src/joystick/xbox/SDL_xboxjoystick.c | 65 ++++++++++++++++------------ src/joystick/xbox/SDL_xboxjoystick.h | 8 ---- src/joystick/xbox/sbc.c | 4 +- 7 files changed, 82 insertions(+), 49 deletions(-) diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index 59030efff1093..430ae70067c71 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -1033,14 +1033,6 @@ 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); - } -#endif /* SDL_JOYSTICK_XBOX */ if (!mapping && name) { if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box") || SDL_strstr(name, "XBOX")) { mapping = s_pXInputMapping; diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h index cd2b10ed89a78..9e9859733d6d7 100644 --- a/src/joystick/SDL_gamecontrollerdb.h +++ b/src/joystick/SDL_gamecontrollerdb.h @@ -595,7 +595,14 @@ 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 + "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 d33448bcf4427..8b10f08306207 100644 --- a/src/joystick/xbox/SDL_xboxjoystick.c +++ b/src/joystick/xbox/SDL_xboxjoystick.c @@ -25,7 +25,7 @@ #include "../../SDL_internal.h" -#if SDL_JOYSTICK_XBOX +#ifdef SDL_JOYSTICK_XBOX #include "SDL_joystick.h" #include "SDL_events.h" @@ -46,12 +46,12 @@ 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); } @@ -175,7 +175,7 @@ static Sint32 SDL_XBOX_JoystickGetCount() { } 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; } @@ -221,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; } @@ -229,29 +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 ret = -1; + SDL_JoystickID joyID = -1; xid_dev_t *xid_dev = xid_from_device_index(device_index); - if (xid_dev != NULL) ret = xid_dev->uid; + if (xid_dev != NULL) joyID = xid_dev->uid; - JOY_DBGMSG("SDL_XBOX_JoystickGetDeviceInstanceID: %d\n", ret); - return ret; + SDL_Log("SDL_XBOX_JoystickGetDeviceInstanceID: %d\n", joyID); + return joyID; } static Sint32 SDL_XBOX_JoystickOpen(SDL_Joystick *joystick, Sint32 device_index) { @@ -259,7 +268,7 @@ 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; } @@ -288,11 +297,11 @@ static Sint32 SDL_XBOX_JoystickOpen(SDL_Joystick *joystick, Sint32 device_index) 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); @@ -324,7 +333,7 @@ static void SDL_XBOX_JoystickUpdate(SDL_Joystick *joystick) { } static void SDL_XBOX_JoystickClose(SDL_Joystick *joystick) { - JOY_DBGMSG("SDL_XBOX_JoystickClose:\n"); + SDL_Log("SDL_XBOX_JoystickClose:\n"); xid_dev_t * xid_dev = xid_from_joystick(joystick); if (xid_dev != NULL) @@ -335,8 +344,8 @@ static void SDL_XBOX_JoystickClose(SDL_Joystick *joystick) { } xid_dev->user_data = NULL; - JOY_DBGMSG("Closing joystick: %u\n", joystick->hwdata->xid_dev->uid); - JOY_DBGMSG("joystick player_index: %i\n", joystick->player_index); + 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; @@ -344,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. diff --git a/src/joystick/xbox/SDL_xboxjoystick.h b/src/joystick/xbox/SDL_xboxjoystick.h index 44c8f0cd72552..6b30018b544ad 100644 --- a/src/joystick/xbox/SDL_xboxjoystick.h +++ b/src/joystick/xbox/SDL_xboxjoystick.h @@ -2,14 +2,6 @@ #include -//#define SDL_JOYSTICK_XBOX_DEBUG -#ifdef SDL_JOYSTICK_XBOX_DEBUG -#include -#define JOY_DBGMSG debugPrint -#else -#define JOY_DBGMSG(...) -#endif - typedef struct gamepad_data { Uint16 low_frequency_rumble; Uint16 high_frequency_rumble; diff --git a/src/joystick/xbox/sbc.c b/src/joystick/xbox/sbc.c index cc70ee9c7951d..35bc186cb5c9c 100644 --- a/src/joystick/xbox/sbc.c +++ b/src/joystick/xbox/sbc.c @@ -81,11 +81,11 @@ void sbc_open(SDL_Joystick * joystick) { joystick->nbuttons = SBC_BUTTON_COUNT; //This includes the toggle switches } -static SDL_bool get_sbc_button_pressed(xid_steelbattalion_in * insbc, enum SBC_BUTTON btn) { +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_TRUE : SDL_FALSE; + return (insbc->buttons[button_offset] & button_mask) ? SDL_PRESSED : SDL_RELEASED; } void sbc_update(SDL_Joystick *joystick) { From 85af9f98f13658867ff83d20df426b8912213b06 Mon Sep 17 00:00:00 2001 From: Samuel Deutsch Date: Mon, 30 Jun 2025 03:34:02 -0700 Subject: [PATCH 5/6] Moved default mapping to game controller DB --- src/joystick/SDL_gamecontrollerdb.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h index 9e9859733d6d7..4f16c9fd1a7e1 100644 --- a/src/joystick/SDL_gamecontrollerdb.h +++ b/src/joystick/SDL_gamecontrollerdb.h @@ -597,6 +597,7 @@ static const char *s_ControllerMappings [] = #endif #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,", From 81c948ff5c229b6fbe1b5e86794d958c84bb6ed8 Mon Sep 17 00:00:00 2001 From: Samuel Deutsch Date: Mon, 30 Jun 2025 03:39:08 -0700 Subject: [PATCH 6/6] Do not use default mapping for non-gamecontroller style XID devices --- src/joystick/SDL_gamecontroller.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index 430ae70067c71..3cdf8429288d7 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -1033,6 +1033,14 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const } } #endif /* __LINUX__ */ +#ifdef SDL_JOYSTICK_XBOX + 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) { if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box") || SDL_strstr(name, "XBOX")) { mapping = s_pXInputMapping;