Merge pull request #2541 from lioncash/input

input_common/sdl/sdl_impl: Minor cleanup
This commit is contained in:
Zach Hilman 2019-06-05 15:51:03 -04:00 committed by GitHub
commit 6aff1005ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 78 deletions

View File

@ -6,15 +6,8 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "core/frontend/input.h"
#include "input_common/main.h" #include "input_common/main.h"
union SDL_Event;
namespace Common {
class ParamPackage;
} // namespace Common
namespace InputCommon::Polling { namespace InputCommon::Polling {
class DevicePoller; class DevicePoller;
enum class DeviceType; enum class DeviceType;

View File

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

View File

@ -6,7 +6,10 @@
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <mutex>
#include <thread> #include <thread>
#include <unordered_map>
#include "common/common_types.h"
#include "common/threadsafe_queue.h" #include "common/threadsafe_queue.h"
#include "input_common/sdl/sdl.h" #include "input_common/sdl/sdl.h"
@ -16,9 +19,9 @@ using SDL_JoystickID = s32;
namespace InputCommon::SDL { namespace InputCommon::SDL {
class SDLJoystick;
class SDLButtonFactory;
class SDLAnalogFactory; class SDLAnalogFactory;
class SDLButtonFactory;
class SDLJoystick;
class SDLState : public State { class SDLState : public State {
public: public:
@ -31,7 +34,13 @@ public:
/// Handle SDL_Events for joysticks from SDL_PollEvent /// Handle SDL_Events for joysticks from SDL_PollEvent
void HandleGameControllerEvent(const SDL_Event& event); void HandleGameControllerEvent(const SDL_Event& event);
/// Get the nth joystick with the corresponding GUID
std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id); std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id);
/**
* 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> GetSDLJoystickByGUID(const std::string& guid, int port); std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port);
/// Get all DevicePoller that use the SDL backend for a specific device type /// Get all DevicePoller that use the SDL backend for a specific device type