From e32bc1a0a38d466a2c85c0386938119f573ec9ef Mon Sep 17 00:00:00 2001 From: Konstantin Budnikov Date: Thu, 21 Feb 2019 06:22:38 +0300 Subject: [PATCH] SDL_HapticRumblePlay rumble for gamepad without SDL_HAPTIC_LEFTRIGHT support (#181) --- app/streaming/input.cpp | 58 +++++++++++++++++++++++++++++------------ app/streaming/input.h | 8 ++++++ 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/app/streaming/input.cpp b/app/streaming/input.cpp index 8d40a1a5..1bbcc371 100644 --- a/app/streaming/input.cpp +++ b/app/streaming/input.cpp @@ -775,9 +775,21 @@ void SdlInputHandler::handleControllerDeviceEvent(SDL_ControllerDeviceEvent* eve state->jsId = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(state->controller)); state->haptic = SDL_HapticOpenFromJoystick(SDL_GameControllerGetJoystick(state->controller)); state->hapticEffectId = -1; - if (state->haptic != nullptr && (SDL_HapticQuery(state->haptic) & SDL_HAPTIC_LEFTRIGHT) == 0) { - SDL_HapticClose(state->haptic); - state->haptic = nullptr; + state->hapticMethod = GAMEPAD_HAPTIC_METHOD_NONE; + if (state->haptic != nullptr) { + if ((SDL_HapticQuery(state->haptic) & SDL_HAPTIC_LEFTRIGHT) == 0) { + if (SDL_HapticRumbleSupported(state->haptic)) { + if (SDL_HapticRumbleInit(state->haptic) == 0) { + state->hapticMethod = GAMEPAD_HAPTIC_METHOD_SIMPLERUMBLE; + } + } + if (state->hapticMethod == GAMEPAD_HAPTIC_METHOD_NONE) { + SDL_HapticClose(state->haptic); + state->haptic = nullptr; + } + } else { + state->hapticMethod = GAMEPAD_HAPTIC_METHOD_LEFTRIGHT; + } } SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(SDL_GameControllerGetJoystick(state->controller)), @@ -883,8 +895,12 @@ void SdlInputHandler::rumble(unsigned short controllerNumber, unsigned short low } // Stop the last effect we played - if (m_GamepadState[controllerNumber].hapticEffectId >= 0) { - SDL_HapticDestroyEffect(haptic, m_GamepadState[controllerNumber].hapticEffectId); + if (m_GamepadState[controllerNumber].hapticMethod == GAMEPAD_HAPTIC_METHOD_LEFTRIGHT) { + if (m_GamepadState[controllerNumber].hapticEffectId >= 0) { + SDL_HapticDestroyEffect(haptic, m_GamepadState[controllerNumber].hapticEffectId); + } + } else if (m_GamepadState[controllerNumber].hapticMethod == GAMEPAD_HAPTIC_METHOD_SIMPLERUMBLE) { + SDL_HapticRumbleStop(haptic); } // If this callback is telling us to stop both motors, don't bother queuing a new effect @@ -892,22 +908,30 @@ void SdlInputHandler::rumble(unsigned short controllerNumber, unsigned short low return; } - SDL_HapticEffect effect; - SDL_memset(&effect, 0, sizeof(effect)); - effect.type = SDL_HAPTIC_LEFTRIGHT; + if (m_GamepadState[controllerNumber].hapticMethod == GAMEPAD_HAPTIC_METHOD_LEFTRIGHT) { + SDL_HapticEffect effect; + SDL_memset(&effect, 0, sizeof(effect)); + effect.type = SDL_HAPTIC_LEFTRIGHT; - // The effect should last until we are instructed to stop or change it - effect.leftright.length = SDL_HAPTIC_INFINITY; + // The effect should last until we are instructed to stop or change it + effect.leftright.length = SDL_HAPTIC_INFINITY; - // SDL haptics range from 0-32767 but XInput uses 0-65535, so divide by 2 to correct for SDL's scaling - effect.leftright.large_magnitude = lowFreqMotor / 2; - effect.leftright.small_magnitude = highFreqMotor / 2; + // SDL haptics range from 0-32767 but XInput uses 0-65535, so divide by 2 to correct for SDL's scaling + effect.leftright.large_magnitude = lowFreqMotor / 2; + effect.leftright.small_magnitude = highFreqMotor / 2; - // Play the new effect - m_GamepadState[controllerNumber].hapticEffectId = SDL_HapticNewEffect(haptic, &effect); - if (m_GamepadState[controllerNumber].hapticEffectId >= 0) { - SDL_HapticRunEffect(haptic, m_GamepadState[controllerNumber].hapticEffectId, 1); + // Play the new effect + m_GamepadState[controllerNumber].hapticEffectId = SDL_HapticNewEffect(haptic, &effect); + if (m_GamepadState[controllerNumber].hapticEffectId >= 0) { + SDL_HapticRunEffect(haptic, m_GamepadState[controllerNumber].hapticEffectId, 1); + } + } else if (m_GamepadState[controllerNumber].hapticMethod == GAMEPAD_HAPTIC_METHOD_SIMPLERUMBLE) { + SDL_HapticRumblePlay(haptic, + std::min(1.0, (GAMEPAD_HAPTIC_SIMPLE_HIFREQ_MOTOR_WEIGHT*highFreqMotor + + GAMEPAD_HAPTIC_SIMPLE_LOWFREQ_MOTOR_WEIGHT*lowFreqMotor) / 65535.0), + SDL_HAPTIC_INFINITY); } + } void SdlInputHandler::handleTouchFingerEvent(SDL_TouchFingerEvent* event) diff --git a/app/streaming/input.h b/app/streaming/input.h index c29a8636..e55b7d64 100644 --- a/app/streaming/input.h +++ b/app/streaming/input.h @@ -9,6 +9,7 @@ struct GamepadState { SDL_GameController* controller; SDL_JoystickID jsId; SDL_Haptic* haptic; + int hapticMethod; int hapticEffectId; short index; @@ -21,6 +22,13 @@ struct GamepadState { #define MAX_GAMEPADS 4 #define MAX_FINGERS 2 +#define GAMEPAD_HAPTIC_METHOD_NONE 0 +#define GAMEPAD_HAPTIC_METHOD_LEFTRIGHT 1 +#define GAMEPAD_HAPTIC_METHOD_SIMPLERUMBLE 2 + +#define GAMEPAD_HAPTIC_SIMPLE_HIFREQ_MOTOR_WEIGHT 0.33 +#define GAMEPAD_HAPTIC_SIMPLE_LOWFREQ_MOTOR_WEIGHT 0.8 + class SdlInputHandler { public: