summaryrefslogtreecommitdiffstats
path: root/src/input_common/sdl/sdl_impl.cpp
diff options
context:
space:
mode:
authorJames Rowe <jroweboy@gmail.com>2018-09-20 08:28:05 +0200
committerfearlessTobi <thm.frey@gmail.com>2019-03-02 19:09:34 +0100
commit09ac66388c01187ed6a402efcad76984c8af9a2e (patch)
treebeed8a86e7b7e02e0c5526723bbf812920341d12 /src/input_common/sdl/sdl_impl.cpp
parentInput: Copy current SDL.h/cpp files to impl (diff)
downloadyuzu-09ac66388c01187ed6a402efcad76984c8af9a2e.tar
yuzu-09ac66388c01187ed6a402efcad76984c8af9a2e.tar.gz
yuzu-09ac66388c01187ed6a402efcad76984c8af9a2e.tar.bz2
yuzu-09ac66388c01187ed6a402efcad76984c8af9a2e.tar.lz
yuzu-09ac66388c01187ed6a402efcad76984c8af9a2e.tar.xz
yuzu-09ac66388c01187ed6a402efcad76984c8af9a2e.tar.zst
yuzu-09ac66388c01187ed6a402efcad76984c8af9a2e.zip
Diffstat (limited to 'src/input_common/sdl/sdl_impl.cpp')
-rw-r--r--src/input_common/sdl/sdl_impl.cpp193
1 files changed, 108 insertions, 85 deletions
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 7c1ecc2e0..83fcf354e 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright 2017 Citra Emulator Project
+// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -20,30 +20,13 @@
#include "common/math_util.h"
#include "common/param_package.h"
#include "common/threadsafe_queue.h"
-#include "input_common/main.h"
-#include "input_common/sdl/sdl.h"
+#include "core/frontend/input.h"
+#include "input_common/sdl/sdl_impl.h"
namespace InputCommon {
namespace SDL {
-class SDLJoystick;
-class SDLButtonFactory;
-class SDLAnalogFactory;
-
-/// Map of GUID of a list of corresponding virtual Joysticks
-static std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
-static std::mutex joystick_map_mutex;
-
-static std::shared_ptr<SDLButtonFactory> button_factory;
-static std::shared_ptr<SDLAnalogFactory> analog_factory;
-
-/// Used by the Pollers during config
-static std::atomic<bool> polling;
-static Common::SPSCQueue<SDL_Event> event_queue;
-
-static std::atomic<bool> initialized = false;
-
static std::string GetGUID(SDL_Joystick* joystick) {
SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
char guid_str[33];
@@ -51,6 +34,20 @@ static std::string GetGUID(SDL_Joystick* joystick) {
return guid_str;
}
+/// 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);
+ // 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,
@@ -142,7 +139,7 @@ private:
/**
* Get the nth joystick with the corresponding GUID
*/
-static std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port) {
+std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
std::lock_guard<std::mutex> lock(joystick_map_mutex);
const auto it = joystick_map.find(guid);
if (it != joystick_map.end()) {
@@ -161,7 +158,7 @@ static std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid
* 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
*/
-static std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
+std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
std::lock_guard<std::mutex> lock(joystick_map_mutex);
auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
const std::string guid = GetGUID(sdl_joystick);
@@ -195,7 +192,7 @@ static std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id)
return joystick_map[guid].emplace_back(std::move(joystick));
}
-void InitJoystick(int joystick_index) {
+void SDLState::InitJoystick(int joystick_index) {
std::lock_guard<std::mutex> lock(joystick_map_mutex);
SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
if (!sdl_joystick) {
@@ -220,10 +217,10 @@ void InitJoystick(int joystick_index) {
joystick_guid_list.emplace_back(std::move(joystick));
}
-void CloseJoystick(SDL_Joystick* sdl_joystick) {
+void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
std::lock_guard<std::mutex> lock(joystick_map_mutex);
std::string guid = GetGUID(sdl_joystick);
- // This call to guid is save since the joystick is guranteed to be in that 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_it =
std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
@@ -233,32 +230,28 @@ void CloseJoystick(SDL_Joystick* sdl_joystick) {
(*joystick_it)->SetSDLJoystick(nullptr, [](SDL_Joystick*) {});
}
-void HandleGameControllerEvent(const SDL_Event& event) {
+void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
switch (event.type) {
case SDL_JOYBUTTONUP: {
- auto joystick = GetSDLJoystickBySDLID(event.jbutton.which);
- if (joystick) {
+ if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
joystick->SetButton(event.jbutton.button, false);
}
break;
}
case SDL_JOYBUTTONDOWN: {
- auto joystick = GetSDLJoystickBySDLID(event.jbutton.which);
- if (joystick) {
+ if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) {
joystick->SetButton(event.jbutton.button, true);
}
break;
}
case SDL_JOYHATMOTION: {
- auto joystick = GetSDLJoystickBySDLID(event.jhat.which);
- if (joystick) {
+ if (auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) {
joystick->SetHat(event.jhat.hat, event.jhat.value);
}
break;
}
case SDL_JOYAXISMOTION: {
- auto joystick = GetSDLJoystickBySDLID(event.jaxis.which);
- if (joystick) {
+ if (auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) {
joystick->SetAxis(event.jaxis.axis, event.jaxis.value);
}
break;
@@ -274,33 +267,11 @@ void HandleGameControllerEvent(const SDL_Event& event) {
}
}
-void CloseSDLJoysticks() {
+void SDLState::CloseJoysticks() {
std::lock_guard<std::mutex> lock(joystick_map_mutex);
joystick_map.clear();
}
-void PollLoop() {
- if (SDL_Init(SDL_INIT_JOYSTICK) < 0) {
- LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
- return;
- }
-
- SDL_Event event;
- while (initialized) {
- // Wait for 10 ms or until an event happens
- if (SDL_WaitEventTimeout(&event, 10)) {
- // Don't handle the event if we are configuring
- if (polling) {
- event_queue.Push(event);
- } else {
- HandleGameControllerEvent(event);
- }
- }
- }
- CloseSDLJoysticks();
- SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
-}
-
class SDLButton final : public Input::ButtonDevice {
public:
explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_)
@@ -369,6 +340,8 @@ private:
/// A button device factory that creates button devices from SDL joystick
class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> {
public:
+ explicit SDLButtonFactory(SDLState& state_) : state(state_) {}
+
/**
* Creates a button device from a joystick button
* @param params contains parameters for creating the device:
@@ -389,7 +362,7 @@ public:
const std::string guid = params.Get("guid", "0");
const int port = params.Get("port", 0);
- auto joystick = GetSDLJoystickByGUID(guid, port);
+ auto joystick = state.GetSDLJoystickByGUID(guid, port);
if (params.Has("hat")) {
const int hat = params.Get("hat", 0);
@@ -434,11 +407,15 @@ public:
joystick->SetButton(button, false);
return std::make_unique<SDLButton>(joystick, button);
}
+
+private:
+ SDLState& state;
};
/// An analog device factory that creates analog devices from SDL joystick
class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> {
public:
+ explicit SDLAnalogFactory(SDLState& state_) : state(state_) {}
/**
* Creates analog device from joystick axes
* @param params contains parameters for creating the device:
@@ -453,37 +430,71 @@ public:
const int axis_x = params.Get("axis_x", 0);
const int axis_y = params.Get("axis_y", 1);
- auto joystick = GetSDLJoystickByGUID(guid, port);
+ auto joystick = state.GetSDLJoystickByGUID(guid, port);
// This is necessary so accessing GetAxis with axis_x and axis_y won't crash
joystick->SetAxis(axis_x, 0);
joystick->SetAxis(axis_y, 0);
return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y);
}
+
+private:
+ SDLState& state;
};
-void Init() {
+SDLState::SDLState() {
using namespace Input;
- RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>());
- RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>());
- polling = false;
+ RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>(*this));
+ RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>(*this));
+
+ // If the frontend is going to manage the event loop, then we dont start one here
+ start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK);
+ if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) {
+ LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
+ return;
+ }
+
+ SDL_AddEventWatch(&SDLEventWatcher, this);
+
initialized = true;
+ if (start_thread) {
+ poll_thread = std::thread([&] {
+ using namespace std::chrono_literals;
+ SDL_Event event;
+ while (initialized) {
+ SDL_PumpEvents();
+ std::this_thread::sleep_for(std::chrono::duration(10ms));
+ }
+ });
+ }
+ // Because the events for joystick connection happens before we have our event watcher added, we
+ // can just open all the joysticks right here
+ for (int i = 0; i < SDL_NumJoysticks(); ++i) {
+ InitJoystick(i);
+ }
}
-void Shutdown() {
- if (initialized) {
- using namespace Input;
- UnregisterFactory<ButtonDevice>("sdl");
- UnregisterFactory<AnalogDevice>("sdl");
- initialized = false;
+SDLState::~SDLState() {
+ using namespace Input;
+ UnregisterFactory<ButtonDevice>("sdl");
+ UnregisterFactory<AnalogDevice>("sdl");
+
+ CloseJoysticks();
+ SDL_DelEventWatch(&SDLEventWatcher, this);
+
+ initialized = false;
+ if (start_thread) {
+ poll_thread.join();
+ SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
}
}
-Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) {
+Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
Common::ParamPackage params({{"engine", "sdl"}});
+
switch (event.type) {
case SDL_JOYAXISMOTION: {
- auto joystick = GetSDLJoystickBySDLID(event.jaxis.which);
+ auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
params.Set("port", joystick->GetPort());
params.Set("guid", joystick->GetGUID());
params.Set("axis", event.jaxis.axis);
@@ -497,14 +508,14 @@ Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) {
break;
}
case SDL_JOYBUTTONUP: {
- auto joystick = GetSDLJoystickBySDLID(event.jbutton.which);
+ 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 = GetSDLJoystickBySDLID(event.jhat.which);
+ auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
params.Set("port", joystick->GetPort());
params.Set("guid", joystick->GetGUID());
params.Set("hat", event.jhat.hat);
@@ -534,21 +545,28 @@ namespace Polling {
class SDLPoller : public InputCommon::Polling::DevicePoller {
public:
+ explicit SDLPoller(SDLState& state_) : state(state_) {}
+
void Start() override {
- event_queue.Clear();
- polling = true;
+ state.event_queue.Clear();
+ state.polling = true;
}
void Stop() override {
- polling = false;
+ state.polling = false;
}
+
+protected:
+ SDLState& state;
};
class SDLButtonPoller final : public SDLPoller {
public:
+ explicit SDLButtonPoller(SDLState& state_) : SDLPoller(state_) {}
+
Common::ParamPackage GetNextInput() override {
SDL_Event event;
- while (event_queue.Pop(event)) {
+ while (state.event_queue.Pop(event)) {
switch (event.type) {
case SDL_JOYAXISMOTION:
if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
@@ -556,7 +574,7 @@ public:
}
case SDL_JOYBUTTONUP:
case SDL_JOYHATMOTION:
- return SDLEventToButtonParamPackage(event);
+ return SDLEventToButtonParamPackage(state, event);
}
}
return {};
@@ -565,6 +583,8 @@ public:
class SDLAnalogPoller final : public SDLPoller {
public:
+ explicit SDLAnalogPoller(SDLState& state_) : SDLPoller(state_) {}
+
void Start() override {
SDLPoller::Start();
@@ -576,7 +596,7 @@ public:
Common::ParamPackage GetNextInput() override {
SDL_Event event;
- while (event_queue.Pop(event)) {
+ while (state.event_queue.Pop(event)) {
if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) {
continue;
}
@@ -593,7 +613,7 @@ public:
}
Common::ParamPackage params;
if (analog_xaxis != -1 && analog_yaxis != -1) {
- auto joystick = GetSDLJoystickBySDLID(event.jaxis.which);
+ auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
params.Set("engine", "sdl");
params.Set("port", joystick->GetPort());
params.Set("guid", joystick->GetGUID());
@@ -612,18 +632,21 @@ private:
int analog_yaxis = -1;
SDL_JoystickID analog_axes_joystick = -1;
};
+} // namespace Polling
-void GetPollers(InputCommon::Polling::DeviceType type,
- std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>>& pollers) {
+std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> SDLState::GetPollers(
+ InputCommon::Polling::DeviceType type) {
+ std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> pollers;
switch (type) {
case InputCommon::Polling::DeviceType::Analog:
- pollers.emplace_back(std::make_unique<SDLAnalogPoller>());
+ pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this));
break;
case InputCommon::Polling::DeviceType::Button:
- pollers.emplace_back(std::make_unique<SDLButtonPoller>());
+ pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
break;
+ return pollers;
}
}
-} // namespace Polling
+
} // namespace SDL
} // namespace InputCommon