ControllerInterface: Add InputBackend interface and SDL implementation.

This commit is contained in:
Jordan Woyak 2022-10-22 16:13:35 -05:00
parent dc046a2470
commit 44a4573303
8 changed files with 125 additions and 46 deletions

View File

@ -487,6 +487,7 @@
<ClInclude Include="InputCommon\ControllerEmu\StickGate.h" /> <ClInclude Include="InputCommon\ControllerEmu\StickGate.h" />
<ClInclude Include="InputCommon\ControllerInterface\ControllerInterface.h" /> <ClInclude Include="InputCommon\ControllerInterface\ControllerInterface.h" />
<ClInclude Include="InputCommon\ControllerInterface\CoreDevice.h" /> <ClInclude Include="InputCommon\ControllerInterface\CoreDevice.h" />
<ClInclude Include="InputCommon\ControllerInterface\InputBackend.h" />
<ClInclude Include="InputCommon\ControllerInterface\DInput\DInput.h" /> <ClInclude Include="InputCommon\ControllerInterface\DInput\DInput.h" />
<ClInclude Include="InputCommon\ControllerInterface\DInput\DInput8.h" /> <ClInclude Include="InputCommon\ControllerInterface\DInput\DInput8.h" />
<ClInclude Include="InputCommon\ControllerInterface\DInput\DInputJoystick.h" /> <ClInclude Include="InputCommon\ControllerInterface\DInput\DInputJoystick.h" />
@ -1111,6 +1112,7 @@
<ClCompile Include="InputCommon\ControllerEmu\StickGate.cpp" /> <ClCompile Include="InputCommon\ControllerEmu\StickGate.cpp" />
<ClCompile Include="InputCommon\ControllerInterface\ControllerInterface.cpp" /> <ClCompile Include="InputCommon\ControllerInterface\ControllerInterface.cpp" />
<ClCompile Include="InputCommon\ControllerInterface\CoreDevice.cpp" /> <ClCompile Include="InputCommon\ControllerInterface\CoreDevice.cpp" />
<ClCompile Include="InputCommon\ControllerInterface\InputBackend.cpp" />
<ClCompile Include="InputCommon\ControllerInterface\DInput\DInput.cpp" /> <ClCompile Include="InputCommon\ControllerInterface\DInput\DInput.cpp" />
<ClCompile Include="InputCommon\ControllerInterface\DInput\DInputJoystick.cpp" /> <ClCompile Include="InputCommon\ControllerInterface\DInput\DInputJoystick.cpp" />
<ClCompile Include="InputCommon\ControllerInterface\DInput\DInputKeyboardMouse.cpp" /> <ClCompile Include="InputCommon\ControllerInterface\DInput\DInputKeyboardMouse.cpp" />

View File

@ -56,6 +56,8 @@ add_library(inputcommon
ControllerInterface/ControllerInterface.h ControllerInterface/ControllerInterface.h
ControllerInterface/CoreDevice.cpp ControllerInterface/CoreDevice.cpp
ControllerInterface/CoreDevice.h ControllerInterface/CoreDevice.h
ControllerInterface/InputBackend.cpp
ControllerInterface/InputBackend.h
ControllerInterface/MappingCommon.cpp ControllerInterface/MappingCommon.cpp
ControllerInterface/MappingCommon.h ControllerInterface/MappingCommon.h
ControllerInterface/Wiimote/WiimoteController.cpp ControllerInterface/Wiimote/WiimoteController.cpp

View File

@ -64,7 +64,7 @@ void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
// nothing needed for OSX and Quartz // nothing needed for OSX and Quartz
#endif #endif
#ifdef CIFACE_USE_SDL #ifdef CIFACE_USE_SDL
ciface::SDL::Init(); m_input_backends.emplace_back(ciface::SDL::CreateInputBackend(this));
#endif #endif
#ifdef CIFACE_USE_ANDROID #ifdef CIFACE_USE_ANDROID
// nothing needed // nothing needed
@ -181,9 +181,6 @@ void ControllerInterface::RefreshDevices(RefreshReason reason)
ciface::Quartz::PopulateDevices(m_wsi.render_window); ciface::Quartz::PopulateDevices(m_wsi.render_window);
} }
#endif #endif
#ifdef CIFACE_USE_SDL
ciface::SDL::PopulateDevices();
#endif
#ifdef CIFACE_USE_ANDROID #ifdef CIFACE_USE_ANDROID
ciface::Android::PopulateDevices(); ciface::Android::PopulateDevices();
#endif #endif
@ -197,6 +194,9 @@ void ControllerInterface::RefreshDevices(RefreshReason reason)
ciface::DualShockUDPClient::PopulateDevices(); ciface::DualShockUDPClient::PopulateDevices();
#endif #endif
for (auto& backend : m_input_backends)
backend->PopulateDevices();
WiimoteReal::PopulateDevices(); WiimoteReal::PopulateDevices();
if (m_populating_devices_counter.fetch_sub(1) == 1) if (m_populating_devices_counter.fetch_sub(1) == 1)
@ -242,9 +242,6 @@ void ControllerInterface::Shutdown()
ciface::OSX::DeInit(); ciface::OSX::DeInit();
ciface::Quartz::DeInit(); ciface::Quartz::DeInit();
#endif #endif
#ifdef CIFACE_USE_SDL
ciface::SDL::DeInit();
#endif
#ifdef CIFACE_USE_ANDROID #ifdef CIFACE_USE_ANDROID
// nothing needed // nothing needed
#endif #endif
@ -255,6 +252,8 @@ void ControllerInterface::Shutdown()
ciface::DualShockUDPClient::DeInit(); ciface::DualShockUDPClient::DeInit();
#endif #endif
m_input_backends.clear();
// Make sure no devices had been added within Shutdown() in the time // 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. // 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() // 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 // 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) // 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); // Theoretically we could avoid updating input on devices that don't have any references to
for (const auto& d : m_devices) // 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();
}
} }
} }

View File

@ -12,6 +12,7 @@
#include "Common/Matrix.h" #include "Common/Matrix.h"
#include "Common/WindowSystemInfo.h" #include "Common/WindowSystemInfo.h"
#include "InputCommon/ControllerInterface/CoreDevice.h" #include "InputCommon/ControllerInterface/CoreDevice.h"
#include "InputCommon/ControllerInterface/InputBackend.h"
// enable disable sources // enable disable sources
#ifdef _WIN32 #ifdef _WIN32
@ -133,6 +134,8 @@ private:
WindowSystemInfo m_wsi; WindowSystemInfo m_wsi;
std::atomic<float> m_aspect_ratio_adjustment = 1; std::atomic<float> m_aspect_ratio_adjustment = 1;
std::atomic<bool> m_requested_mouse_centering = false; std::atomic<bool> m_requested_mouse_centering = false;
std::vector<std::unique_ptr<ciface::InputBackend>> m_input_backends;
}; };
namespace ciface namespace ciface

View File

@ -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

View File

@ -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

View File

@ -29,7 +29,33 @@ static std::string GetJoystickName(int index)
#endif #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<ciface::InputBackend> CreateInputBackend(ControllerInterface* controller_interface)
{
return std::make_unique<InputBackend>(controller_interface);
}
void InputBackend::OpenAndAddDevice(int index)
{ {
SDL_Joystick* const dev = SDL_JoystickOpen(index); SDL_Joystick* const dev = SDL_JoystickOpen(index);
if (dev) if (dev)
@ -37,17 +63,13 @@ static void OpenAndAddDevice(int index)
auto js = std::make_shared<Joystick>(dev, index); auto js = std::make_shared<Joystick>(dev, index);
// only add if it has some inputs/outputs // only add if it has some inputs/outputs
if (!js->Inputs().empty() || !js->Outputs().empty()) 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) #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) if (e.type == SDL_JOYDEVICEADDED)
{ {
@ -55,20 +77,20 @@ static bool HandleEventAndContinue(const SDL_Event& e)
} }
else if (e.type == SDL_JOYDEVICEREMOVED) else if (e.type == SDL_JOYDEVICEREMOVED)
{ {
g_controller_interface.RemoveDevice([&e](const auto* device) { GetControllerInterface().RemoveDevice([&e](const auto* device) {
return device->GetSource() == "SDL" && return device->GetSource() == "SDL" &&
SDL_JoystickInstanceID(static_cast<const Joystick*>(device)->GetSDLJoystick()) == SDL_JoystickInstanceID(static_cast<const Joystick*>(device)->GetSDLJoystick()) ==
e.jdevice.which; 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) for (int i = 0; i < SDL_NumJoysticks(); ++i)
OpenAndAddDevice(i); OpenAndAddDevice(i);
}); });
} }
else if (e.type == s_stop_event_type) else if (e.type == m_stop_event_type)
{ {
return false; return false;
} }
@ -144,7 +166,8 @@ static void EnableSDLLogging()
nullptr); nullptr);
} }
void Init() InputBackend::InputBackend(ControllerInterface* controller_interface)
: ciface::InputBackend(controller_interface)
{ {
#if !SDL_VERSION_ATLEAST(2, 0, 0) #if !SDL_VERSION_ATLEAST(2, 0, 0)
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) != 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"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
#endif #endif
s_hotplug_thread = std::thread([] { m_hotplug_thread = std::thread([this] {
Common::ScopeGuard quit_guard([] { Common::ScopeGuard quit_guard([] {
// TODO: there seems to be some sort of memory leak with SDL, quit isn't freeing everything up // TODO: there seems to be some sort of memory leak with SDL, quit isn't freeing everything up
SDL_Quit(); 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) 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"); ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to register custom events");
return; return;
} }
s_stop_event_type = custom_events_start; m_stop_event_type = custom_events_start;
s_populate_event_type = custom_events_start + 1; m_populate_event_type = custom_events_start + 1;
// Drain all of the events and add the initial joysticks before returning. Otherwise, the // 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_ // 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 #endif
} }
void DeInit() InputBackend::~InputBackend()
{ {
#if !SDL_VERSION_ATLEAST(2, 0, 0) #if !SDL_VERSION_ATLEAST(2, 0, 0)
SDL_Quit(); SDL_Quit();
#else #else
if (!s_hotplug_thread.joinable()) if (!m_hotplug_thread.joinable())
return; return;
SDL_Event stop_event{s_stop_event_type}; SDL_Event stop_event{m_stop_event_type};
SDL_PushEvent(&stop_event); SDL_PushEvent(&stop_event);
s_hotplug_thread.join(); m_hotplug_thread.join();
#endif #endif
} }
void PopulateDevices() void InputBackend::PopulateDevices()
{ {
#if !SDL_VERSION_ATLEAST(2, 0, 0) #if !SDL_VERSION_ATLEAST(2, 0, 0)
if (!SDL_WasInit(SDL_INIT_JOYSTICK)) if (!SDL_WasInit(SDL_INIT_JOYSTICK))
@ -263,10 +286,10 @@ void PopulateDevices()
for (int i = 0; i < SDL_NumJoysticks(); ++i) for (int i = 0; i < SDL_NumJoysticks(); ++i)
OpenAndAddDevice(i); OpenAndAddDevice(i);
#else #else
if (!s_hotplug_thread.joinable()) if (!m_hotplug_thread.joinable())
return; return;
SDL_Event populate_event{s_populate_event_type}; SDL_Event populate_event{m_populate_event_type};
SDL_PushEvent(&populate_event); SDL_PushEvent(&populate_event);
#endif #endif
} }
@ -617,9 +640,8 @@ void Joystick::Motor::SetState(ControlState state)
} }
#endif #endif
void Joystick::UpdateInput() void InputBackend::UpdateInput()
{ {
// TODO: Don't call this for every Joystick, only once per ControllerInterface::UpdateInput()
SDL_JoystickUpdate(); SDL_JoystickUpdate();
} }

View File

@ -22,12 +22,11 @@
#endif #endif
#include "InputCommon/ControllerInterface/CoreDevice.h" #include "InputCommon/ControllerInterface/CoreDevice.h"
#include "InputCommon/ControllerInterface/InputBackend.h"
namespace ciface::SDL namespace ciface::SDL
{ {
void Init(); std::unique_ptr<ciface::InputBackend> CreateInputBackend(ControllerInterface* controller_interface);
void DeInit();
void PopulateDevices();
class Joystick : public Core::Device class Joystick : public Core::Device
{ {
@ -182,8 +181,6 @@ private:
#endif #endif
public: public:
void UpdateInput() override;
Joystick(SDL_Joystick* const joystick, const int sdl_index); Joystick(SDL_Joystick* const joystick, const int sdl_index);
~Joystick(); ~Joystick();