|
|
|
@ -6,7 +6,6 @@
|
|
|
|
|
#include <atomic>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <functional>
|
|
|
|
|
#include <iterator>
|
|
|
|
|
#include <mutex>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <thread>
|
|
|
|
@ -15,7 +14,6 @@
|
|
|
|
|
#include <utility>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <SDL.h>
|
|
|
|
|
#include "common/assert.h"
|
|
|
|
|
#include "common/logging/log.h"
|
|
|
|
|
#include "common/math_util.h"
|
|
|
|
|
#include "common/param_package.h"
|
|
|
|
@ -23,12 +21,10 @@
|
|
|
|
|
#include "core/frontend/input.h"
|
|
|
|
|
#include "input_common/sdl/sdl_impl.h"
|
|
|
|
|
|
|
|
|
|
namespace InputCommon {
|
|
|
|
|
|
|
|
|
|
namespace SDL {
|
|
|
|
|
namespace InputCommon::SDL {
|
|
|
|
|
|
|
|
|
|
static std::string GetGUID(SDL_Joystick* joystick) {
|
|
|
|
|
SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
|
|
|
|
|
const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
|
|
|
|
|
char guid_str[33];
|
|
|
|
|
SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
|
|
|
|
|
return guid_str;
|
|
|
|
@ -37,26 +33,27 @@ static std::string GetGUID(SDL_Joystick* joystick) {
|
|
|
|
|
/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice
|
|
|
|
|
static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
|
|
|
|
|
|
|
|
|
|
static int SDLEventWatcher(void* userdata, SDL_Event* event) {
|
|
|
|
|
SDLState* sdl_state = reinterpret_cast<SDLState*>(userdata);
|
|
|
|
|
static int SDLEventWatcher(void* user_data, SDL_Event* event) {
|
|
|
|
|
auto* const sdl_state = static_cast<SDLState*>(user_data);
|
|
|
|
|
|
|
|
|
|
// Don't handle the event if we are configuring
|
|
|
|
|
if (sdl_state->polling) {
|
|
|
|
|
sdl_state->event_queue.Push(*event);
|
|
|
|
|
} else {
|
|
|
|
|
sdl_state->HandleGameControllerEvent(*event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class SDLJoystick {
|
|
|
|
|
public:
|
|
|
|
|
SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
|
|
|
|
|
decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose)
|
|
|
|
|
: guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, deleter} {}
|
|
|
|
|
SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick)
|
|
|
|
|
: guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose} {}
|
|
|
|
|
|
|
|
|
|
void SetButton(int button, bool value) {
|
|
|
|
|
std::lock_guard lock{mutex};
|
|
|
|
|
state.buttons[button] = value;
|
|
|
|
|
state.buttons.insert_or_assign(button, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GetButton(int button) const {
|
|
|
|
@ -66,7 +63,7 @@ public:
|
|
|
|
|
|
|
|
|
|
void SetAxis(int axis, Sint16 value) {
|
|
|
|
|
std::lock_guard lock{mutex};
|
|
|
|
|
state.axes[axis] = value;
|
|
|
|
|
state.axes.insert_or_assign(axis, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float GetAxis(int axis) const {
|
|
|
|
@ -93,7 +90,7 @@ public:
|
|
|
|
|
|
|
|
|
|
void SetHat(int hat, Uint8 direction) {
|
|
|
|
|
std::lock_guard lock{mutex};
|
|
|
|
|
state.hats[hat] = direction;
|
|
|
|
|
state.hats.insert_or_assign(hat, direction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GetHatDirection(int hat, Uint8 direction) const {
|
|
|
|
@ -118,10 +115,8 @@ public:
|
|
|
|
|
return sdl_joystick.get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetSDLJoystick(SDL_Joystick* joystick,
|
|
|
|
|
decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose) {
|
|
|
|
|
sdl_joystick =
|
|
|
|
|
std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)>(joystick, deleter);
|
|
|
|
|
void SetSDLJoystick(SDL_Joystick* joystick) {
|
|
|
|
|
sdl_joystick.reset(joystick);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
@ -136,59 +131,57 @@ private:
|
|
|
|
|
mutable std::mutex mutex;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the nth joystick with the corresponding GUID
|
|
|
|
|
*/
|
|
|
|
|
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
|
|
|
|
|
std::lock_guard lock{joystick_map_mutex};
|
|
|
|
|
const auto it = joystick_map.find(guid);
|
|
|
|
|
if (it != joystick_map.end()) {
|
|
|
|
|
while (it->second.size() <= static_cast<std::size_t>(port)) {
|
|
|
|
|
auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
|
|
|
|
|
nullptr, [](SDL_Joystick*) {});
|
|
|
|
|
auto joystick =
|
|
|
|
|
std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()), nullptr);
|
|
|
|
|
it->second.emplace_back(std::move(joystick));
|
|
|
|
|
}
|
|
|
|
|
return it->second[port];
|
|
|
|
|
}
|
|
|
|
|
auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, [](SDL_Joystick*) {});
|
|
|
|
|
auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr);
|
|
|
|
|
return joystick_map[guid].emplace_back(std::move(joystick));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check how many identical joysticks (by guid) were connected before the one with sdl_id and so tie
|
|
|
|
|
* it to a SDLJoystick with the same guid and that port
|
|
|
|
|
*/
|
|
|
|
|
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
|
|
|
|
|
auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
|
|
|
|
|
const std::string guid = GetGUID(sdl_joystick);
|
|
|
|
|
|
|
|
|
|
std::lock_guard lock{joystick_map_mutex};
|
|
|
|
|
auto map_it = joystick_map.find(guid);
|
|
|
|
|
const auto map_it = joystick_map.find(guid);
|
|
|
|
|
if (map_it != joystick_map.end()) {
|
|
|
|
|
auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(),
|
|
|
|
|
[&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
|
|
|
|
|
return sdl_joystick == joystick->GetSDLJoystick();
|
|
|
|
|
});
|
|
|
|
|
const auto vec_it =
|
|
|
|
|
std::find_if(map_it->second.begin(), map_it->second.end(),
|
|
|
|
|
[&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
|
|
|
|
|
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
|
|
|
|
|
// SDLJoystick. return the SDLJoystick
|
|
|
|
|
return *vec_it;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Search for a SDLJoystick without a mapped SDL_Joystick...
|
|
|
|
|
auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(),
|
|
|
|
|
[](const std::shared_ptr<SDLJoystick>& joystick) {
|
|
|
|
|
return !joystick->GetSDLJoystick();
|
|
|
|
|
});
|
|
|
|
|
const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(),
|
|
|
|
|
[](const std::shared_ptr<SDLJoystick>& joystick) {
|
|
|
|
|
return !joystick->GetSDLJoystick();
|
|
|
|
|
});
|
|
|
|
|
if (nullptr_it != map_it->second.end()) {
|
|
|
|
|
// ... and map it
|
|
|
|
|
(*nullptr_it)->SetSDLJoystick(sdl_joystick);
|
|
|
|
|
return *nullptr_it;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// There is no SDLJoystick without a mapped SDL_Joystick
|
|
|
|
|
// Create a new SDLJoystick
|
|
|
|
|
auto joystick = std::make_shared<SDLJoystick>(guid, map_it->second.size(), sdl_joystick);
|
|
|
|
|
const int port = static_cast<int>(map_it->second.size());
|
|
|
|
|
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick);
|
|
|
|
|
return map_it->second.emplace_back(std::move(joystick));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick);
|
|
|
|
|
return joystick_map[guid].emplace_back(std::move(joystick));
|
|
|
|
|
}
|
|
|
|
@ -215,17 +208,19 @@ void SDLState::InitJoystick(int joystick_index) {
|
|
|
|
|
(*it)->SetSDLJoystick(sdl_joystick);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
auto joystick = std::make_shared<SDLJoystick>(guid, joystick_guid_list.size(), sdl_joystick);
|
|
|
|
|
const int port = static_cast<int>(joystick_guid_list.size());
|
|
|
|
|
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick);
|
|
|
|
|
joystick_guid_list.emplace_back(std::move(joystick));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
|
|
|
|
|
std::string guid = GetGUID(sdl_joystick);
|
|
|
|
|
const std::string guid = GetGUID(sdl_joystick);
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<SDLJoystick> joystick;
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard lock{joystick_map_mutex};
|
|
|
|
|
// This call to guid is safe since the joystick is guaranteed to be in the map
|
|
|
|
|
auto& joystick_guid_list = joystick_map[guid];
|
|
|
|
|
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) {
|
|
|
|
@ -233,9 +228,10 @@ void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
|
|
|
|
|
});
|
|
|
|
|
joystick = *joystick_it;
|
|
|
|
|
}
|
|
|
|
|
// Destruct SDL_Joystick outside the lock guard because SDL can internally call event calback
|
|
|
|
|
// which locks the mutex again
|
|
|
|
|
joystick->SetSDLJoystick(nullptr, [](SDL_Joystick*) {});
|
|
|
|
|
|
|
|
|
|
// Destruct SDL_Joystick outside the lock guard because SDL can internally call the
|
|
|
|
|
// event callback which locks the mutex again.
|
|
|
|
|
joystick->SetSDLJoystick(nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
|
|
|
|
@ -317,9 +313,10 @@ public:
|
|
|
|
|
trigger_if_greater(trigger_if_greater_) {}
|
|
|
|
|
|
|
|
|
|
bool GetStatus() const override {
|
|
|
|
|
float axis_value = joystick->GetAxis(axis);
|
|
|
|
|
if (trigger_if_greater)
|
|
|
|
|
const float axis_value = joystick->GetAxis(axis);
|
|
|
|
|
if (trigger_if_greater) {
|
|
|
|
|
return axis_value > threshold;
|
|
|
|
|
}
|
|
|
|
|
return axis_value < threshold;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -444,7 +441,7 @@ public:
|
|
|
|
|
const int port = params.Get("port", 0);
|
|
|
|
|
const int axis_x = params.Get("axis_x", 0);
|
|
|
|
|
const int axis_y = params.Get("axis_y", 1);
|
|
|
|
|
float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
|
|
|
|
|
const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
|
|
|
|
|
|
|
|
|
|
auto joystick = state.GetSDLJoystickByGUID(guid, port);
|
|
|
|
|
|
|
|
|
@ -470,7 +467,7 @@ SDLState::SDLState() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
|
|
|
|
|
LOG_ERROR(Input, "Failed to set Hint for background events", SDL_GetError());
|
|
|
|
|
LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SDL_AddEventWatch(&SDLEventWatcher, this);
|
|
|
|
@ -507,12 +504,12 @@ SDLState::~SDLState() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
|
|
|
|
|
static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
|
|
|
|
|
Common::ParamPackage params({{"engine", "sdl"}});
|
|
|
|
|
|
|
|
|
|
switch (event.type) {
|
|
|
|
|
case SDL_JOYAXISMOTION: {
|
|
|
|
|
auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
|
|
|
|
|
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
|
|
|
|
|
params.Set("port", joystick->GetPort());
|
|
|
|
|
params.Set("guid", joystick->GetGUID());
|
|
|
|
|
params.Set("axis", event.jaxis.axis);
|
|
|
|
@ -526,14 +523,14 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SDL_JOYBUTTONUP: {
|
|
|
|
|
auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
|
|
|
|
|
const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
|
|
|
|
|
params.Set("port", joystick->GetPort());
|
|
|
|
|
params.Set("guid", joystick->GetGUID());
|
|
|
|
|
params.Set("button", event.jbutton.button);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SDL_JOYHATMOTION: {
|
|
|
|
|
auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
|
|
|
|
|
const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
|
|
|
|
|
params.Set("port", joystick->GetPort());
|
|
|
|
|
params.Set("guid", joystick->GetGUID());
|
|
|
|
|
params.Set("hat", event.jhat.hat);
|
|
|
|
@ -607,8 +604,8 @@ public:
|
|
|
|
|
SDLPoller::Start();
|
|
|
|
|
|
|
|
|
|
// Reset stored axes
|
|
|
|
|
analog_xaxis = -1;
|
|
|
|
|
analog_yaxis = -1;
|
|
|
|
|
analog_x_axis = -1;
|
|
|
|
|
analog_y_axis = -1;
|
|
|
|
|
analog_axes_joystick = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -620,25 +617,25 @@ public:
|
|
|
|
|
}
|
|
|
|
|
// An analog device needs two axes, so we need to store the axis for later and wait for
|
|
|
|
|
// a second SDL event. The axes also must be from the same joystick.
|
|
|
|
|
int axis = event.jaxis.axis;
|
|
|
|
|
if (analog_xaxis == -1) {
|
|
|
|
|
analog_xaxis = axis;
|
|
|
|
|
const int axis = event.jaxis.axis;
|
|
|
|
|
if (analog_x_axis == -1) {
|
|
|
|
|
analog_x_axis = axis;
|
|
|
|
|
analog_axes_joystick = event.jaxis.which;
|
|
|
|
|
} else if (analog_yaxis == -1 && analog_xaxis != axis &&
|
|
|
|
|
} else if (analog_y_axis == -1 && analog_x_axis != axis &&
|
|
|
|
|
analog_axes_joystick == event.jaxis.which) {
|
|
|
|
|
analog_yaxis = axis;
|
|
|
|
|
analog_y_axis = axis;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Common::ParamPackage params;
|
|
|
|
|
if (analog_xaxis != -1 && analog_yaxis != -1) {
|
|
|
|
|
auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
|
|
|
|
|
if (analog_x_axis != -1 && analog_y_axis != -1) {
|
|
|
|
|
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
|
|
|
|
|
params.Set("engine", "sdl");
|
|
|
|
|
params.Set("port", joystick->GetPort());
|
|
|
|
|
params.Set("guid", joystick->GetGUID());
|
|
|
|
|
params.Set("axis_x", analog_xaxis);
|
|
|
|
|
params.Set("axis_y", analog_yaxis);
|
|
|
|
|
analog_xaxis = -1;
|
|
|
|
|
analog_yaxis = -1;
|
|
|
|
|
params.Set("axis_x", analog_x_axis);
|
|
|
|
|
params.Set("axis_y", analog_y_axis);
|
|
|
|
|
analog_x_axis = -1;
|
|
|
|
|
analog_y_axis = -1;
|
|
|
|
|
analog_axes_joystick = -1;
|
|
|
|
|
return params;
|
|
|
|
|
}
|
|
|
|
@ -646,8 +643,8 @@ public:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
int analog_xaxis = -1;
|
|
|
|
|
int analog_yaxis = -1;
|
|
|
|
|
int analog_x_axis = -1;
|
|
|
|
|
int analog_y_axis = -1;
|
|
|
|
|
SDL_JoystickID analog_axes_joystick = -1;
|
|
|
|
|
};
|
|
|
|
|
} // namespace Polling
|
|
|
|
@ -667,5 +664,4 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
|
|
|
|
|
return pollers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace SDL
|
|
|
|
|
} // namespace InputCommon
|
|
|
|
|
} // namespace InputCommon::SDL
|
|
|
|
|