diff --git a/README.md b/README.md
index 5b78ebf41..7d738a5eb 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,7 @@ A "BIOS" ROM image is required to to start the emulator and to play games. You c
## Latest News
+- 2020/08/22: XInput controller backend added.
- 2020/08/20: Per-game setting overrides added. Mostly for compatibility, but some options are customizable.
- 2020/08/19: CPU PGXP mode added. It is very slow and incompatible with the recompiler, only use for games which need it.
- 2020/08/15: Playlist support/single memcard for multi-disc games in Qt frontend added.
diff --git a/src/duckstation-qt/duckstation-qt.vcxproj b/src/duckstation-qt/duckstation-qt.vcxproj
index 7f75cbbad..29441b4f3 100644
--- a/src/duckstation-qt/duckstation-qt.vcxproj
+++ b/src/duckstation-qt/duckstation-qt.vcxproj
@@ -364,7 +364,7 @@
Level4
Disabled
- WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
true
ProgramDatabase
$(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x86\include;%(AdditionalIncludeDirectories)
@@ -386,7 +386,7 @@
Level4
Disabled
- WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
true
ProgramDatabase
$(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x64\include;%(AdditionalIncludeDirectories)
@@ -408,7 +408,7 @@
Level4
Disabled
- WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
true
ProgramDatabase
$(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x86\include;%(AdditionalIncludeDirectories)
@@ -432,7 +432,7 @@
Level4
Disabled
- WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
true
ProgramDatabase
$(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x64\include;%(AdditionalIncludeDirectories)
@@ -457,7 +457,7 @@
MaxSpeed
true
- WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
$(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x86\include;%(AdditionalIncludeDirectories)
true
false
@@ -481,7 +481,7 @@
MaxSpeed
true
- WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
$(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x86\include;%(AdditionalIncludeDirectories)
true
true
@@ -506,7 +506,7 @@
MaxSpeed
true
- WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
$(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x64\include;%(AdditionalIncludeDirectories)
true
false
@@ -530,7 +530,7 @@
MaxSpeed
true
- WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
$(SolutionDir)dep\glad\Include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\minizip\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;$(SolutionDir)dep\msvc\qt5-x64\include;%(AdditionalIncludeDirectories)
true
true
diff --git a/src/duckstation-qt/generalsettingswidget.cpp b/src/duckstation-qt/generalsettingswidget.cpp
index 6ed0929a7..efe38d487 100644
--- a/src/duckstation-qt/generalsettingswidget.cpp
+++ b/src/duckstation-qt/generalsettingswidget.cpp
@@ -1,5 +1,6 @@
#include "generalsettingswidget.h"
#include "autoupdaterdialog.h"
+#include "frontend-common/controller_interface.h"
#include "settingsdialog.h"
#include "settingwidgetbinder.h"
@@ -8,6 +9,12 @@ GeneralSettingsWidget::GeneralSettingsWidget(QtHostInterface* host_interface, QW
{
m_ui.setupUi(this);
+ for (u32 i = 0; i < static_cast(ControllerInterface::Backend::Count); i++)
+ {
+ m_ui.controllerBackend->addItem(qApp->translate(
+ "ControllerInterface", ControllerInterface::GetBackendName(static_cast(i))));
+ }
+
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.pauseOnStart, "Main", "StartPaused", false);
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.startFullscreen, "Main", "StartFullscreen",
false);
@@ -32,6 +39,9 @@ GeneralSettingsWidget::GeneralSettingsWidget(QtHostInterface* host_interface, QW
"IncreaseTimerResolution", true);
SettingWidgetBinder::BindWidgetToNormalizedSetting(m_host_interface, m_ui.emulationSpeed, "Main", "EmulationSpeed",
100.0f, 1.0f);
+ SettingWidgetBinder::BindWidgetToEnumSetting(
+ m_host_interface, m_ui.controllerBackend, "Main", "ControllerBackend", &ControllerInterface::ParseBackendName,
+ &ControllerInterface::GetBackendName, ControllerInterface::GetDefaultBackend());
connect(m_ui.enableSpeedLimiter, &QCheckBox::stateChanged, this,
&GeneralSettingsWidget::onEnableSpeedLimiterStateChanged);
@@ -87,6 +97,11 @@ GeneralSettingsWidget::GeneralSettingsWidget(QtHostInterface* host_interface, QW
dialog->registerWidgetHelp(
m_ui.showSpeed, tr("Show Speed"), tr("Unchecked"),
tr("Shows the current emulation speed of the system in the top-right corner of the display as a percentage."));
+ dialog->registerWidgetHelp(m_ui.controllerBackend, tr("Controller Backend"),
+ qApp->translate("ControllerInterface", ControllerInterface::GetBackendName(
+ ControllerInterface::GetDefaultBackend())),
+ tr("Determines the backend which is used for controller input. Windows users may prefer "
+ "to use XInput over SDL2 for compatibility."));
// Since this one is compile-time selected, we don't put it in the .ui file.
int current_col = 1;
diff --git a/src/duckstation-qt/generalsettingswidget.ui b/src/duckstation-qt/generalsettingswidget.ui
index 40489f03d..9d3b09b68 100644
--- a/src/duckstation-qt/generalsettingswidget.ui
+++ b/src/duckstation-qt/generalsettingswidget.ui
@@ -6,8 +6,8 @@
0
0
- 502
- 358
+ 652
+ 483
@@ -190,6 +190,29 @@
+ -
+
+
+ Miscellaneous
+
+
+
-
+
+
-
+
+
+ Controller Backend:
+
+
+
+ -
+
+
+
+
+
+
+
-
diff --git a/src/duckstation-sdl/duckstation-sdl.vcxproj b/src/duckstation-sdl/duckstation-sdl.vcxproj
index 076a94b33..3537042ac 100644
--- a/src/duckstation-sdl/duckstation-sdl.vcxproj
+++ b/src/duckstation-sdl/duckstation-sdl.vcxproj
@@ -222,7 +222,7 @@
Level4
Disabled
- WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
true
ProgramDatabase
$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)
@@ -244,7 +244,7 @@
Level4
Disabled
- WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
true
ProgramDatabase
$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)
@@ -266,7 +266,7 @@
Level4
Disabled
- WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
true
ProgramDatabase
$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)
@@ -291,7 +291,7 @@
Level4
Disabled
- WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
true
ProgramDatabase
$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)
@@ -317,7 +317,7 @@
MaxSpeed
true
- WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)
true
false
@@ -341,7 +341,7 @@
MaxSpeed
true
- WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)
true
true
@@ -366,7 +366,7 @@
MaxSpeed
true
- WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)
true
false
@@ -390,7 +390,7 @@
MaxSpeed
true
- WITH_DISCORD_PRESENCE=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
+ WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\nativefiledialog\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)
true
true
diff --git a/src/duckstation-sdl/sdl_host_interface.cpp b/src/duckstation-sdl/sdl_host_interface.cpp
index b4d6bd393..84b20e750 100644
--- a/src/duckstation-sdl/sdl_host_interface.cpp
+++ b/src/duckstation-sdl/sdl_host_interface.cpp
@@ -277,11 +277,6 @@ std::unique_ptr SDLHostInterface::CreateAudioStream(AudioBackend ba
}
}
-std::unique_ptr SDLHostInterface::CreateControllerInterface()
-{
- return std::make_unique();
-}
-
std::optional SDLHostInterface::GetHostKeyCode(const std::string_view key_code) const
{
const std::optional code = SDLKeyNames::ParseKeyString(key_code);
diff --git a/src/duckstation-sdl/sdl_host_interface.h b/src/duckstation-sdl/sdl_host_interface.h
index ac0eae485..538728111 100644
--- a/src/duckstation-sdl/sdl_host_interface.h
+++ b/src/duckstation-sdl/sdl_host_interface.h
@@ -46,7 +46,6 @@ protected:
bool AcquireHostDisplay() override;
void ReleaseHostDisplay() override;
std::unique_ptr CreateAudioStream(AudioBackend backend) override;
- std::unique_ptr CreateControllerInterface() override;
void OnSystemCreated() override;
void OnSystemPaused(bool paused) override;
diff --git a/src/frontend-common/CMakeLists.txt b/src/frontend-common/CMakeLists.txt
index 81f74a4b6..ddae45acc 100644
--- a/src/frontend-common/CMakeLists.txt
+++ b/src/frontend-common/CMakeLists.txt
@@ -23,6 +23,8 @@ if(WIN32)
target_sources(frontend-common PRIVATE
d3d11_host_display.cpp
d3d11_host_display.h
+ xinput_controller_interface.cpp
+ xinput_controller_interface.h
)
target_link_libraries(frontend-common PRIVATE d3d11.lib dxgi.lib)
endif()
@@ -36,7 +38,7 @@ if(SDL2_FOUND AND NOT BUILD_LIBRETRO_CORE)
sdl_initializer.cpp
sdl_initializer.h
)
- target_compile_definitions(frontend-common PRIVATE "WITH_SDL2=1")
+ target_compile_definitions(frontend-common PUBLIC "WITH_SDL2=1")
target_include_directories(frontend-common PRIVATE ${SDL2_INCLUDE_DIRS})
target_link_libraries(frontend-common PRIVATE ${SDL2_LIBRARIES})
diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp
index b9181a44c..b29b205fb 100644
--- a/src/frontend-common/common_host_interface.cpp
+++ b/src/frontend-common/common_host_interface.cpp
@@ -30,7 +30,6 @@
#ifdef WITH_SDL2
#include "sdl_audio_stream.h"
-#include "sdl_controller_interface.h"
#endif
#ifdef WITH_DISCORD_PRESENCE
@@ -81,17 +80,7 @@ bool CommonHostInterface::Initialize()
RegisterSaveStateHotkeys();
RegisterAudioHotkeys();
- m_controller_interface = CreateControllerInterface();
- if (m_controller_interface && !m_controller_interface->Initialize(this))
- {
- Log_WarningPrintf("Failed to initialize controller bindings are not possible.");
- m_controller_interface.reset();
- }
- else if (!m_controller_interface)
- {
- Log_WarningPrintf("No controller interface created, controller bindings are not possible.");
- }
-
+ UpdateControllerInterface();
return true;
}
@@ -459,14 +448,45 @@ std::unique_ptr CommonHostInterface::CreateAudioStream(AudioBackend
}
}
-std::unique_ptr CommonHostInterface::CreateControllerInterface()
+void CommonHostInterface::UpdateControllerInterface()
{
- // In the future we might want to use different controller interfaces.
-#ifdef WITH_SDL2
- return std::make_unique();
-#else
- return nullptr;
-#endif
+ const std::string backend_str = GetStringSettingValue(
+ "Main", "ControllerBackend", ControllerInterface::GetBackendName(ControllerInterface::GetDefaultBackend()));
+ const std::optional new_backend =
+ ControllerInterface::ParseBackendName(backend_str.c_str());
+ const ControllerInterface::Backend current_backend =
+ (m_controller_interface ? m_controller_interface->GetBackend() : ControllerInterface::Backend::None);
+ if (new_backend == current_backend)
+ return;
+
+ if (m_controller_interface)
+ {
+ m_controller_interface->Shutdown();
+ m_controller_interface.reset();
+ }
+
+ if (!new_backend.has_value())
+ {
+ Log_ErrorPrintf("Invalid controller interface type: '%s'", backend_str.c_str());
+ return;
+ }
+
+ if (new_backend == ControllerInterface::Backend::None)
+ {
+ Log_WarningPrintf("No controller interface created, controller bindings are not possible.");
+ return;
+ }
+
+ m_controller_interface = ControllerInterface::Create(new_backend.value());
+ if (!m_controller_interface || !m_controller_interface->Initialize(this))
+ {
+ Log_WarningPrintf("Failed to initialize controller interface, bindings are not possible.");
+ if (m_controller_interface)
+ {
+ m_controller_interface->Shutdown();
+ m_controller_interface.reset();
+ }
+ }
}
bool CommonHostInterface::LoadState(bool global, s32 slot)
@@ -1831,6 +1851,9 @@ void CommonHostInterface::SetDefaultSettings(SettingsInterface& si)
si.SetStringValue("Hotkeys", "DecreaseResolutionScale", "Keyboard/PageDown");
si.SetStringValue("Hotkeys", "ToggleSoftwareRendering", "Keyboard/End");
+ si.SetStringValue("Main", "ControllerBackend",
+ ControllerInterface::GetBackendName(ControllerInterface::GetDefaultBackend()));
+
#ifdef WITH_DISCORD_PRESENCE
si.SetBoolValue("Main", "EnableDiscordPresence", false);
#endif
@@ -1854,6 +1877,8 @@ void CommonHostInterface::CheckForSettingsChanges(const Settings& old_settings)
{
HostInterface::CheckForSettingsChanges(old_settings);
+ UpdateControllerInterface();
+
if (System::IsValid())
{
if (g_settings.audio_backend != old_settings.audio_backend ||
diff --git a/src/frontend-common/common_host_interface.h b/src/frontend-common/common_host_interface.h
index b365f5dd3..0c110dac5 100644
--- a/src/frontend-common/common_host_interface.h
+++ b/src/frontend-common/common_host_interface.h
@@ -182,7 +182,7 @@ protected:
virtual bool SetFullscreen(bool enabled);
virtual std::unique_ptr CreateAudioStream(AudioBackend backend) override;
- virtual std::unique_ptr CreateControllerInterface();
+ virtual void UpdateControllerInterface();
virtual void OnSystemCreated() override;
virtual void OnSystemPaused(bool paused);
diff --git a/src/frontend-common/controller_interface.cpp b/src/frontend-common/controller_interface.cpp
index 8816454f1..0cfc58e8f 100644
--- a/src/frontend-common/controller_interface.cpp
+++ b/src/frontend-common/controller_interface.cpp
@@ -1,6 +1,7 @@
#include "controller_interface.h"
#include "common/assert.h"
#include "common/log.h"
+#include "common/string_util.h"
#include "core/controller.h"
#include "core/system.h"
#include
@@ -79,3 +80,61 @@ bool ControllerInterface::BindControllerAxisToButton(int controller_index, int a
return false;
}
+static constexpr std::array(ControllerInterface::Backend::Count)> s_backend_names = {{
+ TRANSLATABLE("ControllerInterface", "None"),
+#ifdef WITH_SDL2
+ TRANSLATABLE("ControllerInterface", "SDL"),
+#endif
+#ifdef WIN32
+ TRANSLATABLE("ControllerInterface", "XInput"),
+#endif
+}};
+
+std::optional ControllerInterface::ParseBackendName(const char* name)
+{
+ for (u32 i = 0; i < static_cast(s_backend_names.size()); i++)
+ {
+ if (StringUtil::Strcasecmp(name, s_backend_names[i]) == 0)
+ return static_cast(i);
+ }
+
+ return std::nullopt;
+}
+
+const char* ControllerInterface::GetBackendName(Backend type)
+{
+ return s_backend_names[static_cast(type)];
+}
+
+ControllerInterface::Backend ControllerInterface::GetDefaultBackend()
+{
+#ifdef WITH_SDL2
+ return Backend::SDL;
+#endif
+#ifdef WIN32
+ return Backend::XInput;
+#else
+ return Backend::None;
+#endif
+}
+
+#ifdef WITH_SDL2
+#include "sdl_controller_interface.h"
+#endif
+#ifdef WIN32
+#include "xinput_controller_interface.h"
+#endif
+
+std::unique_ptr ControllerInterface::Create(Backend type)
+{
+#ifdef WITH_SDL2
+ if (type == Backend::SDL)
+ return std::make_unique();
+#endif
+#ifdef WIN32
+ if (type == Backend::XInput)
+ return std::make_unique();
+#endif
+
+ return {};
+}
diff --git a/src/frontend-common/controller_interface.h b/src/frontend-common/controller_interface.h
index 6f9af9247..ab877a72a 100644
--- a/src/frontend-common/controller_interface.h
+++ b/src/frontend-common/controller_interface.h
@@ -3,6 +3,7 @@
#include "core/types.h"
#include
#include
+#include
#include