From 8d7f469fb5404fdcc2b5efa64873d24ca317edb9 Mon Sep 17 00:00:00 2001 From: Sanjay Govind Date: Sat, 4 Apr 2026 12:02:14 +1300 Subject: [PATCH] Add support for GIP guitars via gameinput (#15301) (cherry picked from commit 7f86f9107d0270f963a7896180e80dc6ed28ea9e) --- include/SDL3/SDL_hints.h | 20 ++ src/joystick/gdk/SDL_gameinputjoystick.cpp | 396 ++++++++++++++------- src/joystick/usb_ids.h | 8 + 3 files changed, 303 insertions(+), 121 deletions(-) diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index 44454f5909..74f5bca07e 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -1412,6 +1412,26 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_GAMEINPUT "SDL_JOYSTICK_GAMEINPUT" +/** + * A variable controlling whether GameInput should be used for handling + * GIP devices that require raw report processing, but aren't supported + * by HIDRAW, such as Xbox One Guitars. + * + * Note that this is only supported with GameInput 3 or newer. + * + * The variable can be set to the following values: + * + * - "0": GameInput is not used to handle raw GIP devices. + * - "1": GameInput is used. + * + * The default is "1" when using GameInput 3 or newer, and is "0" otherwise. + * + * This hint should be set before SDL is initialized. + * + * \since This hint is available since SDL 3.4.4. + */ +#define SDL_HINT_JOYSTICK_GAMEINPUT_RAW "SDL_JOYSTICK_GAMEINPUT_RAW" + /** * A variable containing a list of devices known to have a GameCube form * factor. diff --git a/src/joystick/gdk/SDL_gameinputjoystick.cpp b/src/joystick/gdk/SDL_gameinputjoystick.cpp index d60251a71e..5d373a2550 100644 --- a/src/joystick/gdk/SDL_gameinputjoystick.cpp +++ b/src/joystick/gdk/SDL_gameinputjoystick.cpp @@ -44,6 +44,15 @@ enum SDL_GAMEPAD_BUTTON_GAMEINPUT_SHARE = 11 }; +enum +{ + SDL_GAMEINPUT_RAWTYPE_NONE, + SDL_GAMEINPUT_RAWTYPE_ROCK_BAND_GUITAR, + SDL_GAMEINPUT_RAWTYPE_ROCK_BAND_DRUM_KIT, + SDL_GAMEINPUT_RAWTYPE_GUITAR_HERO_LIVE_GUITAR, + SDL_GAMEINPUT_RAWTYPE_LEGACY_ADAPTER, +}; + typedef struct GAMEINPUT_InternalDevice { IGameInputDevice *device; @@ -52,6 +61,7 @@ typedef struct GAMEINPUT_InternalDevice SDL_GUID guid; // generated by SDL SDL_JoystickID device_instance; // generated by SDL const GameInputDeviceInfo *info; + int raw_type; int steam_virtual_gamepad_slot; bool isAdded; bool isDeleteRequested; @@ -89,9 +99,66 @@ static bool GAMEINPUT_InternalIsGamepad(const GameInputDeviceInfo *info) return false; } +static Uint8 GAMEINPUT_GetDeviceRawType(const GameInputDeviceInfo *info) +{ +#if GAMEINPUT_API_VERSION >= 3 + GameInputKind supportedInput = info->supportedInput; + if (supportedInput & GameInputKindRawDeviceReport) { + switch (info->vendorId) { + case USB_VENDOR_MADCATZ: + switch (info->productId) { + case USB_PRODUCT_MADCATZ_XB1_STRATOCASTER_GUITAR: + return SDL_GAMEINPUT_RAWTYPE_ROCK_BAND_GUITAR; + case USB_PRODUCT_MADCATZ_XB1_DRUM_KIT: + return SDL_GAMEINPUT_RAWTYPE_ROCK_BAND_DRUM_KIT; + case USB_PRODUCT_MADCATZ_XB1_LEGACY_ADAPTER: + return SDL_GAMEINPUT_RAWTYPE_LEGACY_ADAPTER; + default: + break; + } + break; + case USB_VENDOR_PDP: + switch (info->productId) { + case USB_PRODUCT_PDP_XB1_JAGUAR_GUITAR: + case USB_PRODUCT_PDP_XB1_RIFFMASTER_GUITAR: + return SDL_GAMEINPUT_RAWTYPE_ROCK_BAND_GUITAR; + case USB_PRODUCT_PDP_XB1_DRUM_KIT: + return SDL_GAMEINPUT_RAWTYPE_ROCK_BAND_DRUM_KIT; + default: + break; + } + break; + case USB_VENDOR_CRKD: + switch (info->productId) { + case USB_PRODUCT_PDP_XB1_JAGUAR_GUITAR: + return SDL_GAMEINPUT_RAWTYPE_ROCK_BAND_GUITAR; + default: + break; + } + break; + case USB_VENDOR_RED_OCTANE: + switch (info->productId) { + case USB_PRODUCT_RED_OCTANE_XB1_GUITAR_HERO_LIVE_GUITAR: + return SDL_GAMEINPUT_RAWTYPE_GUITAR_HERO_LIVE_GUITAR; + default: + break; + } + break; + } + } +#endif // GAMEINPUT_API_VERSION >= 3 + return SDL_GAMEINPUT_RAWTYPE_NONE; +} static Uint8 GAMEINPUT_GetDeviceSubtype(const GameInputDeviceInfo *info) { GameInputKind supportedInput = info->supportedInput; + Uint8 rawType = GAMEINPUT_GetDeviceRawType(info); + if (rawType == SDL_GAMEINPUT_RAWTYPE_ROCK_BAND_GUITAR || rawType == SDL_GAMEINPUT_RAWTYPE_GUITAR_HERO_LIVE_GUITAR) { + return SDL_JOYSTICK_TYPE_GUITAR; + } + if (rawType == SDL_GAMEINPUT_RAWTYPE_ROCK_BAND_DRUM_KIT) { + return SDL_JOYSTICK_TYPE_DRUM_KIT; + } if (supportedInput & GameInputKindRacingWheel) { return SDL_JOYSTICK_TYPE_WHEEL; } @@ -132,6 +199,7 @@ static bool GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice) const char *product_string = NULL; Uint8 driver_signature = 'g'; Uint8 subtype = 0; + int raw_type = SDL_GAMEINPUT_RAWTYPE_NONE; char tmp[4]; int idx = 0; @@ -154,6 +222,7 @@ static bool GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice) product = info->productId; //version = (info->firmwareVersion.major << 8) | info->firmwareVersion.minor; subtype = GAMEINPUT_GetDeviceSubtype(info); + raw_type = GAMEINPUT_GetDeviceRawType(info); #if GAMEINPUT_API_VERSION >= 1 if (info->displayName) { @@ -177,7 +246,7 @@ static bool GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice) } #endif - if (!GAMEINPUT_InternalIsGamepad(info)) { + if (!GAMEINPUT_InternalIsGamepad(info) && raw_type == SDL_GAMEINPUT_RAWTYPE_NONE) { #if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) if (SDL_GetHintBoolean(SDL_HINT_JOYSTICK_DIRECTINPUT, true) || SDL_XINPUT_Enabled()) { // Let other backends handle non-gamepad controllers to possibly avoid bugs and/or regressions. @@ -226,6 +295,7 @@ static bool GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice) elem->guid = SDL_CreateJoystickGUID(bus, vendor, product, version, NULL, product_string, driver_signature, subtype); elem->device_instance = SDL_GetNextObjectID(); elem->info = info; + elem->raw_type = raw_type; #if GAMEINPUT_API_VERSION >= 1 elem->steam_virtual_gamepad_slot = GetSteamVirtualGamepadSlot(info->pnpPath); #else @@ -318,11 +388,20 @@ static void CALLBACK GAMEINPUT_InternalJoystickDeviceCallback( static void GAMEINPUT_JoystickDetect(void); static void GAMEINPUT_JoystickQuit(void); +static bool GAMEINPUT_IsRawGameInputEnabled(void) +{ +#if GAMEINPUT_API_VERSION >= 3 + return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_GAMEINPUT_RAW, true); +#else + return false; +#endif +} + static bool GAMEINPUT_JoystickInit(void) { HRESULT hr; - if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_GAMEINPUT, SDL_GAMEINPUT_DEFAULT)) { + if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_GAMEINPUT, SDL_GAMEINPUT_DEFAULT) && !GAMEINPUT_IsRawGameInputEnabled()) { return true; } @@ -336,8 +415,16 @@ static bool GAMEINPUT_JoystickInit(void) g_pGameInput->SetFocusPolicy(GameInputEnableBackgroundInput | GameInputEnableBackgroundGuideButton | GameInputEnableBackgroundShareButton); #endif + GameInputKind kind = GameInputKindUnknown; + if (SDL_GetHintBoolean(SDL_HINT_JOYSTICK_GAMEINPUT, SDL_GAMEINPUT_DEFAULT)) { + kind |= GameInputKindController; + } + if (GAMEINPUT_IsRawGameInputEnabled()) { + kind |= GameInputKindRawDeviceReport; + } + hr = g_pGameInput->RegisterDeviceCallback(NULL, - GameInputKindController, + kind, GameInputDeviceConnected, GameInputBlockingEnumeration, NULL, @@ -527,7 +614,7 @@ static bool GAMEINPUT_JoystickOpen(SDL_Joystick *joystick, int device_index) hwdata->devref = elem; joystick->hwdata = hwdata; - if (GAMEINPUT_InternalIsGamepad(info)) { + if (GAMEINPUT_InternalIsGamepad(info) || GAMEINPUT_GetDeviceRawType(info) != SDL_GAMEINPUT_RAWTYPE_NONE) { joystick->naxes = 6; joystick->nbuttons = 11; joystick->nhats = 1; @@ -612,14 +699,191 @@ static bool GAMEINPUT_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool ena return true; } +static void GAMEINPUT_GuitarUpdate(SDL_Joystick *joystick, IGameInputReading *reading, Uint64 timestamp) +{ + IGameInputRawDeviceReport* rawState; + if (reading->GetRawReport(&rawState)) { + static WORD s_GuitarButtons[] = { + 0x0010, // SDL_GAMEPAD_BUTTON_SOUTH + 0x0020, // SDL_GAMEPAD_BUTTON_EAST + 0x0040, // SDL_GAMEPAD_BUTTON_WEST + 0x0080, // SDL_GAMEPAD_BUTTON_NORTH + 0x0008, // SDL_GAMEPAD_BUTTON_BACK + 0, // The guide button is not available + 0x0004, // SDL_GAMEPAD_BUTTON_START + 0, // right joystick click unavailable + 0x4000, // SDL_GAMEPAD_BUTTON_RIGHT_STICK + 0x1000, // SDL_GAMEPAD_BUTTON_LEFT_SHOULDER + 0, // right shoulder unavailable + }; + Uint8 btnidx = 0, hat = 0; + uint8_t rawData[40]; + SDL_memset(rawData, 0, sizeof(rawData)); + size_t len = rawState->GetRawData(sizeof(rawData), rawData); + uint16_t buttons = rawData[0] | rawData[1] << 8; + if (len >= 10) { + for (btnidx = 0; btnidx < SDL_arraysize(s_GuitarButtons); ++btnidx) { + WORD button_mask = s_GuitarButtons[btnidx]; + if (!button_mask) { + continue; + } + bool down = ((buttons & button_mask) != 0); + SDL_SendJoystickButton(timestamp, joystick, btnidx, down); + } + if (buttons & 0x0100) { + hat |= SDL_HAT_UP; + } + if (buttons & 0x0200) { + hat |= SDL_HAT_DOWN; + } + if (buttons & 0x0400) { + hat |= SDL_HAT_LEFT; + } + if (buttons & 0x0800) { + hat |= SDL_HAT_RIGHT; + } + SDL_SendJoystickHat(timestamp, joystick, 0, hat); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, (rawData[3] * 257) - 32768); + // PS3 RB guitars had tilt on right shoulder + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, rawData[2] >= 0xD0); + // PS3 RB guitars send L2 when using solo buttons + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, (rawData[6]) ? 32767 : -32768); + // Align pickup selector mappings with PS3 instruments + static const Sint16 effects_mappings[] = {-26880, -13568, -1792, 11008, 24576}; + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, effects_mappings[rawData[4] >> 4]); + } + } +} + +static void GAMEINPUT_GamepadUpdate(SDL_Joystick *joystick, IGameInputReading *reading, Uint64 timestamp) { + GameInputGamepadState state; + static WORD s_XInputButtons[] = { + GameInputGamepadA, // SDL_GAMEPAD_BUTTON_SOUTH + GameInputGamepadB, // SDL_GAMEPAD_BUTTON_EAST + GameInputGamepadX, // SDL_GAMEPAD_BUTTON_WEST + GameInputGamepadY, // SDL_GAMEPAD_BUTTON_NORTH + GameInputGamepadView, // SDL_GAMEPAD_BUTTON_BACK + 0, // The guide button is not available + GameInputGamepadMenu, // SDL_GAMEPAD_BUTTON_START + GameInputGamepadLeftThumbstick, // SDL_GAMEPAD_BUTTON_LEFT_STICK + GameInputGamepadRightThumbstick, // SDL_GAMEPAD_BUTTON_RIGHT_STICK + GameInputGamepadLeftShoulder, // SDL_GAMEPAD_BUTTON_LEFT_SHOULDER + GameInputGamepadRightShoulder, // SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER + }; + Uint8 btnidx = 0, hat = 0; + + if (reading->GetGamepadState(&state)) { + for (btnidx = 0; btnidx < SDL_arraysize(s_XInputButtons); ++btnidx) { + WORD button_mask = s_XInputButtons[btnidx]; + if (!button_mask) { + continue; + } + bool down = ((state.buttons & button_mask) != 0); + SDL_SendJoystickButton(timestamp, joystick, btnidx, down); + } + + if (state.buttons & GameInputGamepadDPadUp) { + hat |= SDL_HAT_UP; + } + if (state.buttons & GameInputGamepadDPadDown) { + hat |= SDL_HAT_DOWN; + } + if (state.buttons & GameInputGamepadDPadLeft) { + hat |= SDL_HAT_LEFT; + } + if (state.buttons & GameInputGamepadDPadRight) { + hat |= SDL_HAT_RIGHT; + } + SDL_SendJoystickHat(timestamp, joystick, 0, hat); + +#define CONVERT_AXIS(v) (Sint16)(((v) < 0.0f) ? ((v)*32768.0f) : ((v)*32767.0f)) + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, CONVERT_AXIS(state.leftThumbstickX)); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, CONVERT_AXIS(-state.leftThumbstickY)); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, CONVERT_AXIS(state.rightThumbstickX)); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, CONVERT_AXIS(-state.rightThumbstickY)); +#undef CONVERT_AXIS +#define CONVERT_TRIGGER(v) (Sint16)((v)*65535.0f - 32768.0f) + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, CONVERT_TRIGGER(state.leftTrigger)); + SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, CONVERT_TRIGGER(state.rightTrigger)); +#undef CONVERT_TRIGGER + } +} + +static void GAMEINPUT_ControllerUpdate(SDL_Joystick *joystick, IGameInputReading *reading, Uint64 timestamp) +{ + bool *button_state = SDL_stack_alloc(bool, joystick->nbuttons); + float *axis_state = SDL_stack_alloc(float, joystick->naxes); + GameInputSwitchPosition *switch_state = SDL_stack_alloc(GameInputSwitchPosition, joystick->nhats); + + if (button_state) { + uint32_t i; + uint32_t button_count = reading->GetControllerButtonState(joystick->nbuttons, button_state); + for (i = 0; i < button_count; ++i) { + SDL_SendJoystickButton(timestamp, joystick, (Uint8)i, button_state[i]); + } + SDL_stack_free(button_state); + } + +#define CONVERT_AXIS(v) (Sint16)((v)*65535.0f - 32768.0f) + if (axis_state) { + uint32_t i; + uint32_t axis_count = reading->GetControllerAxisState(joystick->naxes, axis_state); + for (i = 0; i < axis_count; ++i) { + SDL_SendJoystickAxis(timestamp, joystick, (Uint8)i, CONVERT_AXIS(axis_state[i])); + } + SDL_stack_free(axis_state); + } +#undef CONVERT_AXIS + + if (switch_state) { + uint32_t i; + uint32_t switch_count = reading->GetControllerSwitchState(joystick->nhats, switch_state); + for (i = 0; i < switch_count; ++i) { + Uint8 hat; + switch (switch_state[i]) { + case GameInputSwitchUp: + hat = SDL_HAT_UP; + break; + case GameInputSwitchUpRight: + hat = SDL_HAT_UP | SDL_HAT_RIGHT; + break; + case GameInputSwitchRight: + hat = SDL_HAT_RIGHT; + break; + case GameInputSwitchDownRight: + hat = SDL_HAT_DOWN | SDL_HAT_RIGHT; + break; + case GameInputSwitchDown: + hat = SDL_HAT_DOWN; + break; + case GameInputSwitchDownLeft: + hat = SDL_HAT_DOWN | SDL_HAT_LEFT; + break; + case GameInputSwitchLeft: + hat = SDL_HAT_LEFT; + break; + case GameInputSwitchUpLeft: + hat = SDL_HAT_UP | SDL_HAT_LEFT; + break; + case GameInputSwitchCenter: + default: + hat = SDL_HAT_CENTERED; + break; + } + SDL_SendJoystickHat(timestamp, joystick, (Uint8)i, hat); + } + SDL_stack_free(switch_state); + } +} + static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick) { GAMEINPUT_InternalJoystickHwdata *hwdata = joystick->hwdata; + GAMEINPUT_InternalDevice *internal_device = hwdata->devref; IGameInputDevice *device = hwdata->devref->device; const GameInputDeviceInfo *info = hwdata->devref->info; IGameInputReading *reading = NULL; Uint64 timestamp; - GameInputGamepadState state; HRESULT hr; hr = g_pGameInput->GetCurrentReading(info->supportedInput, device, &reading); @@ -629,122 +893,12 @@ static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick) } timestamp = SDL_US_TO_NS(reading->GetTimestamp() + g_GameInputTimestampOffset); - - if (GAMEINPUT_InternalIsGamepad(info)) { - static WORD s_XInputButtons[] = { - GameInputGamepadA, // SDL_GAMEPAD_BUTTON_SOUTH - GameInputGamepadB, // SDL_GAMEPAD_BUTTON_EAST - GameInputGamepadX, // SDL_GAMEPAD_BUTTON_WEST - GameInputGamepadY, // SDL_GAMEPAD_BUTTON_NORTH - GameInputGamepadView, // SDL_GAMEPAD_BUTTON_BACK - 0, // The guide button is not available - GameInputGamepadMenu, // SDL_GAMEPAD_BUTTON_START - GameInputGamepadLeftThumbstick, // SDL_GAMEPAD_BUTTON_LEFT_STICK - GameInputGamepadRightThumbstick, // SDL_GAMEPAD_BUTTON_RIGHT_STICK - GameInputGamepadLeftShoulder, // SDL_GAMEPAD_BUTTON_LEFT_SHOULDER - GameInputGamepadRightShoulder, // SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER - }; - Uint8 btnidx = 0, hat = 0; - - if (reading->GetGamepadState(&state)) { - for (btnidx = 0; btnidx < SDL_arraysize(s_XInputButtons); ++btnidx) { - WORD button_mask = s_XInputButtons[btnidx]; - if (!button_mask) { - continue; - } - bool down = ((state.buttons & button_mask) != 0); - SDL_SendJoystickButton(timestamp, joystick, btnidx, down); - } - - if (state.buttons & GameInputGamepadDPadUp) { - hat |= SDL_HAT_UP; - } - if (state.buttons & GameInputGamepadDPadDown) { - hat |= SDL_HAT_DOWN; - } - if (state.buttons & GameInputGamepadDPadLeft) { - hat |= SDL_HAT_LEFT; - } - if (state.buttons & GameInputGamepadDPadRight) { - hat |= SDL_HAT_RIGHT; - } - SDL_SendJoystickHat(timestamp, joystick, 0, hat); - -#define CONVERT_AXIS(v) (Sint16)(((v) < 0.0f) ? ((v)*32768.0f) : ((v)*32767.0f)) - SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, CONVERT_AXIS(state.leftThumbstickX)); - SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, CONVERT_AXIS(-state.leftThumbstickY)); - SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, CONVERT_AXIS(state.rightThumbstickX)); - SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, CONVERT_AXIS(-state.rightThumbstickY)); -#undef CONVERT_AXIS -#define CONVERT_TRIGGER(v) (Sint16)((v)*65535.0f - 32768.0f) - SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, CONVERT_TRIGGER(state.leftTrigger)); - SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, CONVERT_TRIGGER(state.rightTrigger)); -#undef CONVERT_TRIGGER - } + if (internal_device->raw_type == SDL_GAMEINPUT_RAWTYPE_ROCK_BAND_GUITAR) { + GAMEINPUT_GuitarUpdate(joystick, reading, timestamp); + } else if (GAMEINPUT_InternalIsGamepad(info)) { + GAMEINPUT_GamepadUpdate(joystick, reading, timestamp); } else { - bool *button_state = SDL_stack_alloc(bool, joystick->nbuttons); - float *axis_state = SDL_stack_alloc(float, joystick->naxes); - GameInputSwitchPosition *switch_state = SDL_stack_alloc(GameInputSwitchPosition, joystick->nhats); - - if (button_state) { - uint32_t i; - uint32_t button_count = reading->GetControllerButtonState(joystick->nbuttons, button_state); - for (i = 0; i < button_count; ++i) { - SDL_SendJoystickButton(timestamp, joystick, (Uint8)i, button_state[i]); - } - SDL_stack_free(button_state); - } - -#define CONVERT_AXIS(v) (Sint16)((v)*65535.0f - 32768.0f) - if (axis_state) { - uint32_t i; - uint32_t axis_count = reading->GetControllerAxisState(joystick->naxes, axis_state); - for (i = 0; i < axis_count; ++i) { - SDL_SendJoystickAxis(timestamp, joystick, (Uint8)i, CONVERT_AXIS(axis_state[i])); - } - SDL_stack_free(axis_state); - } -#undef CONVERT_AXIS - - if (switch_state) { - uint32_t i; - uint32_t switch_count = reading->GetControllerSwitchState(joystick->nhats, switch_state); - for (i = 0; i < switch_count; ++i) { - Uint8 hat; - switch (switch_state[i]) { - case GameInputSwitchUp: - hat = SDL_HAT_UP; - break; - case GameInputSwitchUpRight: - hat = SDL_HAT_UP | SDL_HAT_RIGHT; - break; - case GameInputSwitchRight: - hat = SDL_HAT_RIGHT; - break; - case GameInputSwitchDownRight: - hat = SDL_HAT_DOWN | SDL_HAT_RIGHT; - break; - case GameInputSwitchDown: - hat = SDL_HAT_DOWN; - break; - case GameInputSwitchDownLeft: - hat = SDL_HAT_DOWN | SDL_HAT_LEFT; - break; - case GameInputSwitchLeft: - hat = SDL_HAT_LEFT; - break; - case GameInputSwitchUpLeft: - hat = SDL_HAT_UP | SDL_HAT_LEFT; - break; - case GameInputSwitchCenter: - default: - hat = SDL_HAT_CENTERED; - break; - } - SDL_SendJoystickHat(timestamp, joystick, (Uint8)i, hat); - } - SDL_stack_free(switch_state); - } + GAMEINPUT_ControllerUpdate(joystick, reading, timestamp); } #ifdef GAMEINPUT_SENSOR_SUPPORT @@ -821,7 +975,7 @@ static bool GAMEINPUT_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap { GAMEINPUT_InternalDevice *elem = GAMEINPUT_InternalFindByIndex(device_index); - if (!GAMEINPUT_InternalIsGamepad(elem->info)) { + if (!GAMEINPUT_InternalIsGamepad(elem->info) && elem->raw_type == SDL_GAMEINPUT_RAWTYPE_NONE) { return false; } diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h index 55eb92b87e..f916e6cb8b 100644 --- a/src/joystick/usb_ids.h +++ b/src/joystick/usb_ids.h @@ -53,6 +53,7 @@ #define USB_VENDOR_POWERA_ALT 0x20d6 #define USB_VENDOR_QANBA 0x2c22 #define USB_VENDOR_RAZER 0x1532 +#define USB_VENDOR_RED_OCTANE 0x1430 #define USB_VENDOR_SAITEK 0x06a3 #define USB_VENDOR_SCEA 0x12ba #define USB_VENDOR_SHANWAN 0x2563 @@ -101,6 +102,9 @@ #define USB_PRODUCT_LOGITECH_F310 0xc216 #define USB_PRODUCT_LOGITECH_CHILLSTREAM 0xcad1 #define USB_PRODUCT_MADCATZ_SAITEK_SIDE_PANEL_CONTROL_DECK 0x2218 +#define USB_PRODUCT_MADCATZ_XB1_STRATOCASTER_GUITAR 0x4161 +#define USB_PRODUCT_MADCATZ_XB1_DRUM_KIT 0x4262 +#define USB_PRODUCT_MADCATZ_XB1_LEGACY_ADAPTER 0x4164 #define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS4_WIRELESS 0x0d16 #define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS4_WIRED 0x0d17 #define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS 0x0d18 @@ -126,6 +130,9 @@ #define USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V104 0x7214 #define USB_PRODUCT_PDP_ROCK_CANDY 0x0246 #define USB_PRODUCT_PDP_REALMZ_WIRELESS 0x018c +#define USB_PRODUCT_PDP_XB1_DRUM_KIT 0x0171 +#define USB_PRODUCT_PDP_XB1_JAGUAR_GUITAR 0x0170 +#define USB_PRODUCT_PDP_XB1_RIFFMASTER_GUITAR 0x0248 #define USB_PRODUCT_POWERA_MINI 0x541a #define USB_PRODUCT_RAZER_ATROX 0x0a00 #define USB_PRODUCT_RAZER_KITSUNE 0x1012 @@ -145,6 +152,7 @@ #define USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_XBOX_WIRED 0x1010 #define USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_XBOX_WIRELESS 0x1011 #define USB_PRODUCT_RAZER_WOLVERINE_V3_PRO 0x0a3f +#define USB_PRODUCT_RED_OCTANE_XB1_GUITAR_HERO_LIVE_GUITAR 0x0170 #define USB_PRODUCT_SAITEK_CYBORG_V3 0xf622 #define USB_PRODUCT_SCEA_PS3_GH_GUITAR 0x0100 #define USB_PRODUCT_SCEA_PS3_GH_DRUMS 0x0120