|
|
|
@ -56,9 +56,9 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) { |
|
|
|
class SDLJoystick { |
|
|
|
public: |
|
|
|
SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, |
|
|
|
SDL_GameController* gamecontroller) |
|
|
|
SDL_GameController* game_controller) |
|
|
|
: guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, |
|
|
|
sdl_controller{gamecontroller, &SDL_GameControllerClose} {} |
|
|
|
sdl_controller{game_controller, &SDL_GameControllerClose} {} |
|
|
|
|
|
|
|
void SetButton(int button, bool value) { |
|
|
|
std::lock_guard lock{mutex}; |
|
|
|
@ -77,10 +77,10 @@ public: |
|
|
|
|
|
|
|
float GetAxis(int axis, float range) const { |
|
|
|
std::lock_guard lock{mutex}; |
|
|
|
return state.axes.at(axis) / (32767.0f * range); |
|
|
|
return static_cast<float>(state.axes.at(axis)) / (32767.0f * range); |
|
|
|
} |
|
|
|
|
|
|
|
bool RumblePlay(f32 amp_low, f32 amp_high, int time) { |
|
|
|
bool RumblePlay(f32 amp_low, f32 amp_high, u32 time) { |
|
|
|
const u16 raw_amp_low = static_cast<u16>(amp_low * 0xFFFF); |
|
|
|
const u16 raw_amp_high = static_cast<u16>(amp_high * 0xFFFF); |
|
|
|
// Lower drastically the number of state changes
|
|
|
|
@ -124,7 +124,7 @@ public: |
|
|
|
return std::make_tuple(x, y); |
|
|
|
} |
|
|
|
|
|
|
|
const InputCommon::MotionInput& GetMotion() const { |
|
|
|
const MotionInput& GetMotion() const { |
|
|
|
return motion; |
|
|
|
} |
|
|
|
|
|
|
|
@ -172,15 +172,15 @@ private: |
|
|
|
} state; |
|
|
|
std::string guid; |
|
|
|
int port; |
|
|
|
u16 last_state_rumble_high; |
|
|
|
u16 last_state_rumble_low; |
|
|
|
u16 last_state_rumble_high = 0; |
|
|
|
u16 last_state_rumble_low = 0; |
|
|
|
std::chrono::time_point<std::chrono::system_clock> last_vibration; |
|
|
|
std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; |
|
|
|
std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; |
|
|
|
mutable std::mutex mutex; |
|
|
|
|
|
|
|
// motion is initalized without PID values as motion input is not aviable for SDL2
|
|
|
|
InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f}; |
|
|
|
// Motion is initialized without PID values as motion input is not aviable for SDL2
|
|
|
|
MotionInput motion{0.0f, 0.0f, 0.0f}; |
|
|
|
}; |
|
|
|
|
|
|
|
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { |
|
|
|
@ -192,7 +192,7 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& g |
|
|
|
nullptr, nullptr); |
|
|
|
it->second.emplace_back(std::move(joystick)); |
|
|
|
} |
|
|
|
return it->second[port]; |
|
|
|
return it->second[static_cast<std::size_t>(port)]; |
|
|
|
} |
|
|
|
auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr); |
|
|
|
return joystick_map[guid].emplace_back(std::move(joystick)); |
|
|
|
@ -212,7 +212,7 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_ |
|
|
|
return sdl_joystick == joystick->GetSDLJoystick(); |
|
|
|
}); |
|
|
|
if (vec_it != map_it->second.end()) { |
|
|
|
// This is the common case: There is already an existing SDL_Joystick maped to a
|
|
|
|
// This is the common case: There is already an existing SDL_Joystick mapped to a
|
|
|
|
// SDLJoystick. return the SDLJoystick
|
|
|
|
return *vec_it; |
|
|
|
} |
|
|
|
@ -220,7 +220,7 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_ |
|
|
|
// Search for a SDLJoystick without a mapped SDL_Joystick...
|
|
|
|
const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(), |
|
|
|
[](const std::shared_ptr<SDLJoystick>& joystick) { |
|
|
|
return !joystick->GetSDLJoystick(); |
|
|
|
return joystick->GetSDLJoystick() == nullptr; |
|
|
|
}); |
|
|
|
if (nullptr_it != map_it->second.end()) { |
|
|
|
// ... and map it
|
|
|
|
@ -273,22 +273,21 @@ void SDLState::InitJoystick(int joystick_index) { |
|
|
|
void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) { |
|
|
|
const std::string guid = GetGUID(sdl_joystick); |
|
|
|
|
|
|
|
std::shared_ptr<SDLJoystick> joystick; |
|
|
|
std::shared_ptr<SDLJoystick> found_joystick; |
|
|
|
{ |
|
|
|
std::lock_guard lock{joystick_map_mutex}; |
|
|
|
// This call to guid is safe since the joystick is guaranteed to be in the map
|
|
|
|
const auto& joystick_guid_list = joystick_map[guid]; |
|
|
|
const auto joystick_it = |
|
|
|
std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), |
|
|
|
[&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) { |
|
|
|
return joystick->GetSDLJoystick() == sdl_joystick; |
|
|
|
}); |
|
|
|
joystick = *joystick_it; |
|
|
|
const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), |
|
|
|
[&sdl_joystick](const auto& joystick) { |
|
|
|
return joystick->GetSDLJoystick() == sdl_joystick; |
|
|
|
}); |
|
|
|
found_joystick = *joystick_it; |
|
|
|
} |
|
|
|
|
|
|
|
// Destruct SDL_Joystick outside the lock guard because SDL can internally call the
|
|
|
|
// event callback which locks the mutex again.
|
|
|
|
joystick->SetSDLJoystick(nullptr, nullptr); |
|
|
|
found_joystick->SetSDLJoystick(nullptr, nullptr); |
|
|
|
} |
|
|
|
|
|
|
|
void SDLState::HandleGameControllerEvent(const SDL_Event& event) { |
|
|
|
@ -392,8 +391,8 @@ private: |
|
|
|
|
|
|
|
class SDLAnalog final : public Input::AnalogDevice { |
|
|
|
public: |
|
|
|
SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_, |
|
|
|
float range_) |
|
|
|
explicit SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, |
|
|
|
float deadzone_, float range_) |
|
|
|
: joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), |
|
|
|
range(range_) {} |
|
|
|
|
|
|
|
@ -672,13 +671,13 @@ SDLState::SDLState() { |
|
|
|
RegisterFactory<ButtonDevice>("sdl", button_factory); |
|
|
|
RegisterFactory<MotionDevice>("sdl", motion_factory); |
|
|
|
|
|
|
|
// If the frontend is going to manage the event loop, then we dont start one here
|
|
|
|
start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK); |
|
|
|
// If the frontend is going to manage the event loop, then we don't start one here
|
|
|
|
start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; |
|
|
|
if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { |
|
|
|
LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); |
|
|
|
return; |
|
|
|
} |
|
|
|
has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER); |
|
|
|
has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0; |
|
|
|
if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) { |
|
|
|
LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError()); |
|
|
|
} |
|
|
|
@ -723,8 +722,8 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() { |
|
|
|
std::vector<Common::ParamPackage> devices; |
|
|
|
for (const auto& [key, value] : joystick_map) { |
|
|
|
for (const auto& joystick : value) { |
|
|
|
auto joy = joystick->GetSDLJoystick(); |
|
|
|
if (auto controller = joystick->GetSDLGameController()) { |
|
|
|
auto* joy = joystick->GetSDLJoystick(); |
|
|
|
if (auto* controller = joystick->GetSDLGameController()) { |
|
|
|
std::string name = |
|
|
|
fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort()); |
|
|
|
devices.emplace_back(Common::ParamPackage{ |
|
|
|
@ -748,7 +747,7 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() { |
|
|
|
} |
|
|
|
|
|
|
|
namespace { |
|
|
|
Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, u8 axis, |
|
|
|
Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, |
|
|
|
float value = 0.1f) { |
|
|
|
Common::ParamPackage params({{"engine", "sdl"}}); |
|
|
|
params.Set("port", port); |
|
|
|
@ -764,7 +763,7 @@ Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid |
|
|
|
return params; |
|
|
|
} |
|
|
|
|
|
|
|
Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, u8 button) { |
|
|
|
Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, s32 button) { |
|
|
|
Common::ParamPackage params({{"engine", "sdl"}}); |
|
|
|
params.Set("port", port); |
|
|
|
params.Set("guid", std::move(guid)); |
|
|
|
@ -772,7 +771,7 @@ Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid |
|
|
|
return params; |
|
|
|
} |
|
|
|
|
|
|
|
Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, u8 hat, u8 value) { |
|
|
|
Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat, s32 value) { |
|
|
|
Common::ParamPackage params({{"engine", "sdl"}}); |
|
|
|
|
|
|
|
params.Set("port", port); |
|
|
|
@ -802,17 +801,19 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve |
|
|
|
case SDL_JOYAXISMOTION: { |
|
|
|
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); |
|
|
|
return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), |
|
|
|
event.jaxis.axis, event.jaxis.value); |
|
|
|
static_cast<s32>(event.jaxis.axis), |
|
|
|
event.jaxis.value); |
|
|
|
} |
|
|
|
case SDL_JOYBUTTONUP: { |
|
|
|
const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); |
|
|
|
return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), |
|
|
|
event.jbutton.button); |
|
|
|
static_cast<s32>(event.jbutton.button)); |
|
|
|
} |
|
|
|
case SDL_JOYHATMOTION: { |
|
|
|
const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); |
|
|
|
return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), |
|
|
|
event.jhat.hat, event.jhat.value); |
|
|
|
static_cast<s32>(event.jhat.hat), |
|
|
|
static_cast<s32>(event.jhat.value)); |
|
|
|
} |
|
|
|
} |
|
|
|
return {}; |
|
|
|
@ -823,17 +824,19 @@ Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Eve |
|
|
|
case SDL_JOYAXISMOTION: { |
|
|
|
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); |
|
|
|
return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), |
|
|
|
event.jaxis.axis, event.jaxis.value); |
|
|
|
static_cast<s32>(event.jaxis.axis), |
|
|
|
event.jaxis.value); |
|
|
|
} |
|
|
|
case SDL_JOYBUTTONUP: { |
|
|
|
const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); |
|
|
|
return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), |
|
|
|
event.jbutton.button); |
|
|
|
static_cast<s32>(event.jbutton.button)); |
|
|
|
} |
|
|
|
case SDL_JOYHATMOTION: { |
|
|
|
const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); |
|
|
|
return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), |
|
|
|
event.jhat.hat, event.jhat.value); |
|
|
|
static_cast<s32>(event.jhat.hat), |
|
|
|
static_cast<s32>(event.jhat.value)); |
|
|
|
} |
|
|
|
} |
|
|
|
return {}; |
|
|
|
@ -1062,7 +1065,7 @@ public: |
|
|
|
if (event.type == SDL_JOYAXISMOTION) { |
|
|
|
const auto axis = event.jaxis.axis; |
|
|
|
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); |
|
|
|
const auto controller = joystick->GetSDLGameController(); |
|
|
|
auto* const controller = joystick->GetSDLGameController(); |
|
|
|
if (controller) { |
|
|
|
const auto axis_left_x = |
|
|
|
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) |
|
|
|
|