ControllerInterface: Add InputBackend interface and SDL implementation.
This commit is contained in:
parent
dc046a2470
commit
44a4573303
|
@ -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" />
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue