diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props
index ec5342b71f..d79af3b78c 100644
--- a/Source/Core/DolphinLib.props
+++ b/Source/Core/DolphinLib.props
@@ -487,6 +487,7 @@
+
@@ -1111,6 +1112,7 @@
+
diff --git a/Source/Core/InputCommon/CMakeLists.txt b/Source/Core/InputCommon/CMakeLists.txt
index 2caa334cca..20ae0f3f17 100644
--- a/Source/Core/InputCommon/CMakeLists.txt
+++ b/Source/Core/InputCommon/CMakeLists.txt
@@ -56,6 +56,8 @@ add_library(inputcommon
ControllerInterface/ControllerInterface.h
ControllerInterface/CoreDevice.cpp
ControllerInterface/CoreDevice.h
+ ControllerInterface/InputBackend.cpp
+ ControllerInterface/InputBackend.h
ControllerInterface/MappingCommon.cpp
ControllerInterface/MappingCommon.h
ControllerInterface/Wiimote/WiimoteController.cpp
diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp
index 442e5502fa..d1ee02370a 100644
--- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp
@@ -64,7 +64,7 @@ void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
// nothing needed for OSX and Quartz
#endif
#ifdef CIFACE_USE_SDL
- ciface::SDL::Init();
+ m_input_backends.emplace_back(ciface::SDL::CreateInputBackend(this));
#endif
#ifdef CIFACE_USE_ANDROID
// nothing needed
@@ -181,9 +181,6 @@ void ControllerInterface::RefreshDevices(RefreshReason reason)
ciface::Quartz::PopulateDevices(m_wsi.render_window);
}
#endif
-#ifdef CIFACE_USE_SDL
- ciface::SDL::PopulateDevices();
-#endif
#ifdef CIFACE_USE_ANDROID
ciface::Android::PopulateDevices();
#endif
@@ -197,6 +194,9 @@ void ControllerInterface::RefreshDevices(RefreshReason reason)
ciface::DualShockUDPClient::PopulateDevices();
#endif
+ for (auto& backend : m_input_backends)
+ backend->PopulateDevices();
+
WiimoteReal::PopulateDevices();
if (m_populating_devices_counter.fetch_sub(1) == 1)
@@ -242,9 +242,6 @@ void ControllerInterface::Shutdown()
ciface::OSX::DeInit();
ciface::Quartz::DeInit();
#endif
-#ifdef CIFACE_USE_SDL
- ciface::SDL::DeInit();
-#endif
#ifdef CIFACE_USE_ANDROID
// nothing needed
#endif
@@ -255,6 +252,8 @@ void ControllerInterface::Shutdown()
ciface::DualShockUDPClient::DeInit();
#endif
+ m_input_backends.clear();
+
// Make sure no devices had been added within Shutdown() in the time
// between checking they checked atomic m_is_init bool and we changed it.
// We couldn't have locked m_devices_population_mutex for the whole Shutdown()
@@ -384,15 +383,19 @@ void ControllerInterface::UpdateInput()
// TODO: if we are an emulation input channel, we should probably always lock
// Prefer outdated values over blocking UI or CPU thread (avoids short but noticeable frame drop)
- if (m_devices_mutex.try_lock())
+ if (!m_devices_mutex.try_lock())
+ return;
+
+ std::lock_guard lk(m_devices_mutex, std::adopt_lock);
+
+ for (auto& backend : m_input_backends)
+ backend->UpdateInput();
+
+ for (const auto& d : m_devices)
{
- std::lock_guard lk(m_devices_mutex, std::adopt_lock);
- for (const auto& d : m_devices)
- {
- // Theoretically we could avoid updating input on devices that don't have any references to
- // them, but in practice a few devices types could break in different ways, so we don't
- d->UpdateInput();
- }
+ // Theoretically we could avoid updating input on devices that don't have any references to
+ // them, but in practice a few devices types could break in different ways, so we don't
+ d->UpdateInput();
}
}
diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h
index 3a0276de41..59909aeec8 100644
--- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h
+++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h
@@ -12,6 +12,7 @@
#include "Common/Matrix.h"
#include "Common/WindowSystemInfo.h"
#include "InputCommon/ControllerInterface/CoreDevice.h"
+#include "InputCommon/ControllerInterface/InputBackend.h"
// enable disable sources
#ifdef _WIN32
@@ -133,6 +134,8 @@ private:
WindowSystemInfo m_wsi;
std::atomic m_aspect_ratio_adjustment = 1;
std::atomic m_requested_mouse_centering = false;
+
+ std::vector> m_input_backends;
};
namespace ciface
diff --git a/Source/Core/InputCommon/ControllerInterface/InputBackend.cpp b/Source/Core/InputCommon/ControllerInterface/InputBackend.cpp
new file mode 100644
index 0000000000..91685eea00
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerInterface/InputBackend.cpp
@@ -0,0 +1,24 @@
+// Copyright 2022 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "InputCommon/ControllerInterface/InputBackend.h"
+
+namespace ciface
+{
+InputBackend::InputBackend(ControllerInterface* controller_interface)
+ : m_controller_interface(*controller_interface)
+{
+}
+
+InputBackend::~InputBackend() = default;
+
+void InputBackend::UpdateInput()
+{
+}
+
+ControllerInterface& InputBackend::GetControllerInterface()
+{
+ return m_controller_interface;
+}
+
+} // namespace ciface
diff --git a/Source/Core/InputCommon/ControllerInterface/InputBackend.h b/Source/Core/InputCommon/ControllerInterface/InputBackend.h
new file mode 100644
index 0000000000..653bc16df1
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerInterface/InputBackend.h
@@ -0,0 +1,26 @@
+// Copyright 2022 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+class ControllerInterface;
+
+namespace ciface
+{
+class InputBackend
+{
+public:
+ InputBackend(ControllerInterface* controller_interface);
+
+ virtual ~InputBackend();
+
+ virtual void PopulateDevices() = 0;
+ virtual void UpdateInput();
+
+ ControllerInterface& GetControllerInterface();
+
+private:
+ ControllerInterface& m_controller_interface;
+};
+
+} // namespace ciface
diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp
index 0ea15251ad..327002c3a3 100644
--- a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp
@@ -29,7 +29,33 @@ static std::string GetJoystickName(int index)
#endif
}
-static void OpenAndAddDevice(int index)
+class InputBackend final : public ciface::InputBackend
+{
+public:
+ InputBackend(ControllerInterface* controller_interface);
+ ~InputBackend();
+ void PopulateDevices() override;
+ void UpdateInput() override;
+
+private:
+ void OpenAndAddDevice(int index);
+
+#if SDL_VERSION_ATLEAST(2, 0, 0)
+ bool HandleEventAndContinue(const SDL_Event& e);
+
+ Common::Event m_init_event;
+ Uint32 m_stop_event_type;
+ Uint32 m_populate_event_type;
+ std::thread m_hotplug_thread;
+#endif
+};
+
+std::unique_ptr CreateInputBackend(ControllerInterface* controller_interface)
+{
+ return std::make_unique(controller_interface);
+}
+
+void InputBackend::OpenAndAddDevice(int index)
{
SDL_Joystick* const dev = SDL_JoystickOpen(index);
if (dev)
@@ -37,17 +63,13 @@ static void OpenAndAddDevice(int index)
auto js = std::make_shared(dev, index);
// only add if it has some inputs/outputs
if (!js->Inputs().empty() || !js->Outputs().empty())
- g_controller_interface.AddDevice(std::move(js));
+ GetControllerInterface().AddDevice(std::move(js));
}
}
#if SDL_VERSION_ATLEAST(2, 0, 0)
-static Common::Event s_init_event;
-static Uint32 s_stop_event_type;
-static Uint32 s_populate_event_type;
-static std::thread s_hotplug_thread;
-static bool HandleEventAndContinue(const SDL_Event& e)
+bool InputBackend::HandleEventAndContinue(const SDL_Event& e)
{
if (e.type == SDL_JOYDEVICEADDED)
{
@@ -55,20 +77,20 @@ static bool HandleEventAndContinue(const SDL_Event& e)
}
else if (e.type == SDL_JOYDEVICEREMOVED)
{
- g_controller_interface.RemoveDevice([&e](const auto* device) {
+ GetControllerInterface().RemoveDevice([&e](const auto* device) {
return device->GetSource() == "SDL" &&
SDL_JoystickInstanceID(static_cast(device)->GetSDLJoystick()) ==
e.jdevice.which;
});
}
- else if (e.type == s_populate_event_type)
+ else if (e.type == m_populate_event_type)
{
- g_controller_interface.PlatformPopulateDevices([] {
+ GetControllerInterface().PlatformPopulateDevices([this] {
for (int i = 0; i < SDL_NumJoysticks(); ++i)
OpenAndAddDevice(i);
});
}
- else if (e.type == s_stop_event_type)
+ else if (e.type == m_stop_event_type)
{
return false;
}
@@ -144,7 +166,8 @@ static void EnableSDLLogging()
nullptr);
}
-void Init()
+InputBackend::InputBackend(ControllerInterface* controller_interface)
+ : ciface::InputBackend(controller_interface)
{
#if !SDL_VERSION_ATLEAST(2, 0, 0)
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) != 0)
@@ -168,13 +191,13 @@ void Init()
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
#endif
- s_hotplug_thread = std::thread([] {
+ m_hotplug_thread = std::thread([this] {
Common::ScopeGuard quit_guard([] {
// TODO: there seems to be some sort of memory leak with SDL, quit isn't freeing everything up
SDL_Quit();
});
{
- Common::ScopeGuard init_guard([] { s_init_event.Set(); });
+ Common::ScopeGuard init_guard([this] { m_init_event.Set(); });
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER) != 0)
{
@@ -188,8 +211,8 @@ void Init()
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to register custom events");
return;
}
- s_stop_event_type = custom_events_start;
- s_populate_event_type = custom_events_start + 1;
+ m_stop_event_type = custom_events_start;
+ m_populate_event_type = custom_events_start + 1;
// Drain all of the events and add the initial joysticks before returning. Otherwise, the
// individual joystick events as well as the custom populate event will be handled _after_
@@ -235,26 +258,26 @@ void Init()
}
});
- s_init_event.Wait();
+ m_init_event.Wait();
#endif
}
-void DeInit()
+InputBackend::~InputBackend()
{
#if !SDL_VERSION_ATLEAST(2, 0, 0)
SDL_Quit();
#else
- if (!s_hotplug_thread.joinable())
+ if (!m_hotplug_thread.joinable())
return;
- SDL_Event stop_event{s_stop_event_type};
+ SDL_Event stop_event{m_stop_event_type};
SDL_PushEvent(&stop_event);
- s_hotplug_thread.join();
+ m_hotplug_thread.join();
#endif
}
-void PopulateDevices()
+void InputBackend::PopulateDevices()
{
#if !SDL_VERSION_ATLEAST(2, 0, 0)
if (!SDL_WasInit(SDL_INIT_JOYSTICK))
@@ -263,10 +286,10 @@ void PopulateDevices()
for (int i = 0; i < SDL_NumJoysticks(); ++i)
OpenAndAddDevice(i);
#else
- if (!s_hotplug_thread.joinable())
+ if (!m_hotplug_thread.joinable())
return;
- SDL_Event populate_event{s_populate_event_type};
+ SDL_Event populate_event{m_populate_event_type};
SDL_PushEvent(&populate_event);
#endif
}
@@ -617,9 +640,8 @@ void Joystick::Motor::SetState(ControlState state)
}
#endif
-void Joystick::UpdateInput()
+void InputBackend::UpdateInput()
{
- // TODO: Don't call this for every Joystick, only once per ControllerInterface::UpdateInput()
SDL_JoystickUpdate();
}
diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h
index f789c8846a..1b37a22b9e 100644
--- a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h
+++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h
@@ -22,12 +22,11 @@
#endif
#include "InputCommon/ControllerInterface/CoreDevice.h"
+#include "InputCommon/ControllerInterface/InputBackend.h"
namespace ciface::SDL
{
-void Init();
-void DeInit();
-void PopulateDevices();
+std::unique_ptr CreateInputBackend(ControllerInterface* controller_interface);
class Joystick : public Core::Device
{
@@ -182,8 +181,6 @@ private:
#endif
public:
- void UpdateInput() override;
-
Joystick(SDL_Joystick* const joystick, const int sdl_index);
~Joystick();