Add SDL motion input and rumble support
This commit is contained in:
parent
38cb76dea5
commit
6cb936d0cf
|
@ -56,8 +56,9 @@ static bool HandleEventAndContinue(const SDL_Event& e)
|
||||||
else if (e.type == SDL_JOYDEVICEREMOVED)
|
else if (e.type == SDL_JOYDEVICEREMOVED)
|
||||||
{
|
{
|
||||||
g_controller_interface.RemoveDevice([&e](const auto* device) {
|
g_controller_interface.RemoveDevice([&e](const auto* device) {
|
||||||
const Joystick* joystick = dynamic_cast<const Joystick*>(device);
|
return device->GetSource() == "SDL" &&
|
||||||
return joystick && SDL_JoystickInstanceID(joystick->GetSDLJoystick()) == e.jdevice.which;
|
SDL_JoystickInstanceID(static_cast<const Joystick*>(device)->GetSDLJoystick()) ==
|
||||||
|
e.jdevice.which;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (e.type == s_populate_event_type)
|
else if (e.type == s_populate_event_type)
|
||||||
|
@ -79,7 +80,7 @@ static bool HandleEventAndContinue(const SDL_Event& e)
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 0)
|
#if !SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
if (SDL_Init(SDL_INIT_JOYSTICK) != 0)
|
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) != 0)
|
||||||
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to initialize");
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to initialize");
|
||||||
return;
|
return;
|
||||||
#else
|
#else
|
||||||
|
@ -88,16 +89,20 @@ void Init()
|
||||||
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
|
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
|
||||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 0, 9)
|
||||||
|
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
|
||||||
|
#endif
|
||||||
|
|
||||||
s_hotplug_thread = std::thread([] {
|
s_hotplug_thread = std::thread([] {
|
||||||
Common::ScopeGuard quit_guard([] {
|
Common::ScopeGuard quit_guard([] {
|
||||||
// TODO: there seems to be some sort of memory leak with SDL, quit isn't freeing everything up
|
// TODO: there seems to be some sort of memory leak with SDL, quit isn't freeing everything up
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
});
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
Common::ScopeGuard init_guard([] { s_init_event.Set(); });
|
Common::ScopeGuard init_guard([] { s_init_event.Set(); });
|
||||||
|
|
||||||
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) != 0)
|
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER) != 0)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to initialize");
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to initialize");
|
||||||
return;
|
return;
|
||||||
|
@ -172,25 +177,6 @@ void PopulateDevices()
|
||||||
Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index)
|
Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index)
|
||||||
: m_joystick(joystick), m_name(StripSpaces(GetJoystickName(sdl_index)))
|
: m_joystick(joystick), m_name(StripSpaces(GetJoystickName(sdl_index)))
|
||||||
{
|
{
|
||||||
// really bad HACKS:
|
|
||||||
// to not use SDL for an XInput device
|
|
||||||
// too many people on the forums pick the SDL device and ask:
|
|
||||||
// "why don't my 360 gamepad triggers/rumble work correctly"
|
|
||||||
#ifdef _WIN32
|
|
||||||
// checking the name is probably good (and hacky) enough
|
|
||||||
// but I'll double check with the num of buttons/axes
|
|
||||||
std::string lcasename = GetName();
|
|
||||||
Common::ToLower(&lcasename);
|
|
||||||
|
|
||||||
if ((std::string::npos != lcasename.find("xbox 360")) &&
|
|
||||||
(10 == SDL_JoystickNumButtons(joystick)) && (5 == SDL_JoystickNumAxes(joystick)) &&
|
|
||||||
(1 == SDL_JoystickNumHats(joystick)) && (0 == SDL_JoystickNumBalls(joystick)))
|
|
||||||
{
|
|
||||||
// this device won't be used
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (SDL_JoystickNumButtons(joystick) > 255 || SDL_JoystickNumAxes(joystick) > 255 ||
|
if (SDL_JoystickNumButtons(joystick) > 255 || SDL_JoystickNumAxes(joystick) > 255 ||
|
||||||
SDL_JoystickNumHats(joystick) > 255 || SDL_JoystickNumBalls(joystick) > 255)
|
SDL_JoystickNumHats(joystick) > 255 || SDL_JoystickNumBalls(joystick) > 255)
|
||||||
{
|
{
|
||||||
|
@ -219,11 +205,12 @@ Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index)
|
||||||
AddAnalogInputs(new Axis(i, m_joystick, -32768), new Axis(i, m_joystick, 32767));
|
AddAnalogInputs(new Axis(i, m_joystick, -32768), new Axis(i, m_joystick, 32767));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_haptic = nullptr;
|
||||||
|
|
||||||
#ifdef USE_SDL_HAPTIC
|
#ifdef USE_SDL_HAPTIC
|
||||||
m_haptic = SDL_HapticOpenFromJoystick(m_joystick);
|
m_haptic = SDL_HapticOpenFromJoystick(m_joystick);
|
||||||
if (!m_haptic)
|
if (m_haptic)
|
||||||
return;
|
{
|
||||||
|
|
||||||
const unsigned int supported_effects = SDL_HapticQuery(m_haptic);
|
const unsigned int supported_effects = SDL_HapticQuery(m_haptic);
|
||||||
|
|
||||||
// Disable autocenter:
|
// Disable autocenter:
|
||||||
|
@ -252,6 +239,45 @@ Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index)
|
||||||
AddOutput(new LeftRightEffect(m_haptic, LeftRightEffect::Motor::Strong));
|
AddOutput(new LeftRightEffect(m_haptic, LeftRightEffect::Motor::Strong));
|
||||||
AddOutput(new LeftRightEffect(m_haptic, LeftRightEffect::Motor::Weak));
|
AddOutput(new LeftRightEffect(m_haptic, LeftRightEffect::Motor::Weak));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 0, 9)
|
||||||
|
if (!m_haptic)
|
||||||
|
{
|
||||||
|
AddOutput(new Motor(m_joystick));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_SDL_GAMECONTROLLER
|
||||||
|
m_controller = SDL_GameControllerOpen(sdl_index);
|
||||||
|
|
||||||
|
if (m_controller)
|
||||||
|
{
|
||||||
|
if (SDL_GameControllerSetSensorEnabled(m_controller, SDL_SENSOR_ACCEL, SDL_TRUE) == 0)
|
||||||
|
{
|
||||||
|
AddInput(new MotionInput("Accel Up", m_controller, SDL_SENSOR_ACCEL, 1, 1));
|
||||||
|
AddInput(new MotionInput("Accel Down", m_controller, SDL_SENSOR_ACCEL, 1, -1));
|
||||||
|
|
||||||
|
AddInput(new MotionInput("Accel Left", m_controller, SDL_SENSOR_ACCEL, 0, -1));
|
||||||
|
AddInput(new MotionInput("Accel Right", m_controller, SDL_SENSOR_ACCEL, 0, 1));
|
||||||
|
|
||||||
|
AddInput(new MotionInput("Accel Forward", m_controller, SDL_SENSOR_ACCEL, 2, -1));
|
||||||
|
AddInput(new MotionInput("Accel Backward", m_controller, SDL_SENSOR_ACCEL, 2, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDL_GameControllerSetSensorEnabled(m_controller, SDL_SENSOR_GYRO, SDL_TRUE) == 0)
|
||||||
|
{
|
||||||
|
AddInput(new MotionInput("Gyro Pitch Up", m_controller, SDL_SENSOR_GYRO, 0, 1));
|
||||||
|
AddInput(new MotionInput("Gyro Pitch Down", m_controller, SDL_SENSOR_GYRO, 0, -1));
|
||||||
|
|
||||||
|
AddInput(new MotionInput("Gyro Roll Left", m_controller, SDL_SENSOR_GYRO, 2, 1));
|
||||||
|
AddInput(new MotionInput("Gyro Roll Right", m_controller, SDL_SENSOR_GYRO, 2, -1));
|
||||||
|
|
||||||
|
AddInput(new MotionInput("Gyro Yaw Left", m_controller, SDL_SENSOR_GYRO, 1, 1));
|
||||||
|
AddInput(new MotionInput("Gyro Yaw Right", m_controller, SDL_SENSOR_GYRO, 1, -1));
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,6 +293,11 @@ Joystick::~Joystick()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 0, 9)
|
||||||
|
// stop all rumble
|
||||||
|
SDL_JoystickRumble(m_joystick, 0, 0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
// close joystick
|
// close joystick
|
||||||
SDL_JoystickClose(m_joystick);
|
SDL_JoystickClose(m_joystick);
|
||||||
}
|
}
|
||||||
|
@ -442,6 +473,19 @@ bool Joystick::LeftRightEffect::UpdateParameters(s16 value)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 0, 9)
|
||||||
|
std::string Joystick::Motor::GetName() const
|
||||||
|
{
|
||||||
|
return "Motor";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Joystick::Motor::SetState(ControlState state)
|
||||||
|
{
|
||||||
|
Uint16 rumble = state * std::numeric_limits<Uint16>::max();
|
||||||
|
SDL_JoystickRumble(m_js, rumble, rumble, std::numeric_limits<Uint32>::max());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void Joystick::UpdateInput()
|
void Joystick::UpdateInput()
|
||||||
{
|
{
|
||||||
// TODO: Don't call this for every Joystick, only once per ControllerInterface::UpdateInput()
|
// TODO: Don't call this for every Joystick, only once per ControllerInterface::UpdateInput()
|
||||||
|
@ -492,4 +536,14 @@ ControlState Joystick::Hat::GetState() const
|
||||||
{
|
{
|
||||||
return (SDL_JoystickGetHat(m_js, m_index) & (1 << m_direction)) > 0;
|
return (SDL_JoystickGetHat(m_js, m_index) & (1 << m_direction)) > 0;
|
||||||
}
|
}
|
||||||
|
#ifdef USE_SDL_GAMECONTROLLER
|
||||||
|
|
||||||
|
ControlState Joystick::MotionInput::GetState() const
|
||||||
|
{
|
||||||
|
std::array<float, 3> data{};
|
||||||
|
SDL_GameControllerGetSensorData(m_gc, m_type, data.data(), (int)data.size());
|
||||||
|
return m_scale * data[m_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
} // namespace ciface::SDL
|
} // namespace ciface::SDL
|
||||||
|
|
|
@ -5,14 +5,24 @@
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
|
#define INIT_FLAGS SDL_INIT_JOYSTICK
|
||||||
|
|
||||||
#if SDL_VERSION_ATLEAST(1, 3, 0)
|
#if SDL_VERSION_ATLEAST(1, 3, 0)
|
||||||
#define USE_SDL_HAPTIC
|
#define USE_SDL_HAPTIC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 0, 14)
|
||||||
|
#define USE_SDL_GAMECONTROLLER
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SDL_HAPTIC
|
#ifdef USE_SDL_HAPTIC
|
||||||
#include <SDL_haptic.h>
|
#include <SDL_haptic.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_SDL_GAMECONTROLLER
|
||||||
|
#include <SDL_gamecontroller.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
||||||
|
|
||||||
namespace ciface::SDL
|
namespace ciface::SDL
|
||||||
|
@ -137,6 +147,42 @@ private:
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 0, 9)
|
||||||
|
class Motor : public Output
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Motor(SDL_Joystick* js) : m_js(js){};
|
||||||
|
std::string GetName() const override;
|
||||||
|
void SetState(ControlState state) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDL_Joystick* const m_js;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_SDL_GAMECONTROLLER
|
||||||
|
class MotionInput : public Input
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MotionInput(const char* name, SDL_GameController* gc, SDL_SensorType type, int index,
|
||||||
|
ControlState scale)
|
||||||
|
: m_name(name), m_gc(gc), m_type(type), m_index(index), m_scale(scale){};
|
||||||
|
|
||||||
|
std::string GetName() const override { return m_name; };
|
||||||
|
bool IsDetectable() const override { return false; };
|
||||||
|
ControlState GetState() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* m_name;
|
||||||
|
|
||||||
|
SDL_GameController* const m_gc;
|
||||||
|
SDL_SensorType const m_type;
|
||||||
|
int const m_index;
|
||||||
|
|
||||||
|
ControlState const m_scale;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void UpdateInput() override;
|
void UpdateInput() override;
|
||||||
|
|
||||||
|
@ -154,5 +200,9 @@ private:
|
||||||
#ifdef USE_SDL_HAPTIC
|
#ifdef USE_SDL_HAPTIC
|
||||||
SDL_Haptic* m_haptic;
|
SDL_Haptic* m_haptic;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_SDL_GAMECONTROLLER
|
||||||
|
SDL_GameController* m_controller;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
} // namespace ciface::SDL
|
} // namespace ciface::SDL
|
||||||
|
|
Loading…
Reference in New Issue