diff --git a/.gitmodules b/.gitmodules
index 01e2ced8b6..d27084a9a6 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -23,3 +23,8 @@
url = https://github.com/KhronosGroup/SPIRV-Cross.git
branch = master
shallow = true
+[submodule "SDL"]
+ path = Externals/SDL/SDL
+ url = https://github.com/libsdl-org/SDL.git
+ branch = main
+ shallow = true
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ae835b0f39..e3602d8bc5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -84,8 +84,8 @@ option(OPROFILING "Enable profiling" OFF)
# TODO: Add DSPSpy
option(DSPTOOL "Build dsptool" OFF)
-# Enable SDL for default on operating systems that aren't Android, Linux or Windows.
-if(NOT ANDROID AND NOT CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT MSVC)
+# Enable SDL for default on operating systems that aren't Android or Linux.
+if(NOT ANDROID AND NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
option(ENABLE_SDL "Enables SDL as a generic controller backend" ON)
else()
option(ENABLE_SDL "Enables SDL as a generic controller backend" OFF)
@@ -612,6 +612,23 @@ if(UNIX)
add_definitions(-DUSE_MEMORYWATCHER=1)
endif()
+if(ENABLE_SDL)
+ find_package(SDL2)
+
+ if(SDL2_FOUND)
+ message(STATUS "Using system SDL2")
+ else()
+ message(STATUS "Using static SDL2 from Externals")
+ set(SDL_SHARED OFF)
+ set(SDL_SHARED_ENABLED_BY_DEFAULT OFF)
+ set(SDL_STATIC ON)
+ set(SDL_STATIC_ENABLED_BY_DEFAULT ON)
+ add_subdirectory(Externals/SDL/SDL)
+ set(SDL2_FOUND TRUE)
+ endif()
+ add_definitions(-DHAVE_SDL2=1)
+endif()
+
if(ENABLE_ANALYTICS)
message(STATUS "Enabling analytics collection (subject to end-user opt-in)")
add_definitions(-DUSE_ANALYTICS=1)
diff --git a/Externals/ExternalsReferenceAll.props b/Externals/ExternalsReferenceAll.props
index f3a19282e4..2566a4a4a0 100644
--- a/Externals/ExternalsReferenceAll.props
+++ b/Externals/ExternalsReferenceAll.props
@@ -94,5 +94,8 @@
{1bea10f3-80ce-4bc4-9331-5769372cdf99}
+
+ {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}
+
diff --git a/Externals/SDL/SDL b/Externals/SDL/SDL
new file mode 160000
index 0000000000..cd2dcf54af
--- /dev/null
+++ b/Externals/SDL/SDL
@@ -0,0 +1 @@
+Subproject commit cd2dcf54afaa6d640abf8b83855f6c4b5cda457d
diff --git a/Externals/SDL/SDL2.vcxproj b/Externals/SDL/SDL2.vcxproj
new file mode 100644
index 0000000000..ebc599029a
--- /dev/null
+++ b/Externals/SDL/SDL2.vcxproj
@@ -0,0 +1,412 @@
+
+
+
+
+
+ {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SDL\include;%(AdditionalIncludeDirectories)
+ HAVE_LIBC=1;%(PreprocessorDefinitions)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props
index 8cb5919edf..2e7e546c78 100644
--- a/Source/Core/DolphinLib.props
+++ b/Source/Core/DolphinLib.props
@@ -493,6 +493,7 @@
+
@@ -1104,6 +1105,7 @@
+
diff --git a/Source/Core/InputCommon/CMakeLists.txt b/Source/Core/InputCommon/CMakeLists.txt
index 06f959a91a..9cca78b65d 100644
--- a/Source/Core/InputCommon/CMakeLists.txt
+++ b/Source/Core/InputCommon/CMakeLists.txt
@@ -174,32 +174,12 @@ if(UNIX)
)
endif()
-if(ENABLE_SDL)
- find_package(SDL2)
- if(SDL2_FOUND)
- message(STATUS "Using shared SDL2")
- set(SDL_TARGET SDL2::SDL2)
- else()
- # SDL2 not found, try SDL
- find_package(SDL)
- if(SDL_FOUND)
- message(STATUS "Using shared SDL")
- add_library(System_SDL INTERFACE)
- target_include_directories(System_SDL INTERFACE ${SDL_INCLUDE_DIR})
- target_link_libraries(System_SDL INTERFACE ${SDL_LIBRARY})
- set(SDL_TARGET System_SDL)
- endif()
- endif()
- if(SDL_TARGET AND TARGET ${SDL_TARGET})
- target_sources(inputcommon PRIVATE
- ControllerInterface/SDL/SDL.cpp
- ControllerInterface/SDL/SDL.h
- )
- target_link_libraries(inputcommon PRIVATE ${SDL_TARGET})
- target_compile_definitions(inputcommon PRIVATE "CIFACE_USE_SDL=1")
- else()
- message(STATUS "SDL NOT found, disabling SDL input")
- endif()
+if(SDL2_FOUND)
+ target_sources(inputcommon PRIVATE
+ ControllerInterface/SDL/SDL.cpp
+ ControllerInterface/SDL/SDL.h
+ )
+ target_link_libraries(inputcommon PRIVATE SDL2::SDL2)
endif()
if(MSVC)
diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h
index 7a5ee0ad26..2f43cacc42 100644
--- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h
+++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h
@@ -30,6 +30,9 @@
#define CIFACE_USE_PIPES
#endif
#define CIFACE_USE_DUALSHOCKUDPCLIENT
+#if defined(HAVE_SDL2)
+#define CIFACE_USE_SDL
+#endif
namespace ciface
{
diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp
index a2e6893801..6dec6003fd 100644
--- a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.cpp
@@ -15,6 +15,8 @@
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#ifdef _WIN32
+#include
+
#pragma comment(lib, "SDL2.lib")
#endif
@@ -56,8 +58,9 @@ static bool HandleEventAndContinue(const SDL_Event& e)
else if (e.type == SDL_JOYDEVICEREMOVED)
{
g_controller_interface.RemoveDevice([&e](const auto* device) {
- const Joystick* joystick = dynamic_cast(device);
- return joystick && SDL_JoystickInstanceID(joystick->GetSDLJoystick()) == e.jdevice.which;
+ return device->GetSource() == "SDL" &&
+ SDL_JoystickInstanceID(static_cast(device)->GetSDLJoystick()) ==
+ e.jdevice.which;
});
}
else if (e.type == s_populate_event_type)
@@ -76,10 +79,77 @@ static bool HandleEventAndContinue(const SDL_Event& e)
}
#endif
+static void EnableSDLLogging()
+{
+ SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
+ SDL_LogSetOutputFunction(
+ [](void*, int category, SDL_LogPriority priority, const char* message) {
+ std::string category_name;
+ switch (category)
+ {
+ case SDL_LOG_CATEGORY_APPLICATION:
+ category_name = "app";
+ break;
+ case SDL_LOG_CATEGORY_ERROR:
+ category_name = "error";
+ break;
+ case SDL_LOG_CATEGORY_ASSERT:
+ category_name = "assert";
+ break;
+ case SDL_LOG_CATEGORY_SYSTEM:
+ category_name = "system";
+ break;
+ case SDL_LOG_CATEGORY_AUDIO:
+ category_name = "audio";
+ break;
+ case SDL_LOG_CATEGORY_VIDEO:
+ category_name = "video";
+ break;
+ case SDL_LOG_CATEGORY_RENDER:
+ category_name = "render";
+ break;
+ case SDL_LOG_CATEGORY_INPUT:
+ category_name = "input";
+ break;
+ case SDL_LOG_CATEGORY_TEST:
+ category_name = "test";
+ break;
+ default:
+ category_name = fmt::format("unknown({})", category);
+ break;
+ }
+
+ auto log_level = Common::Log::LogLevel::LNOTICE;
+ switch (priority)
+ {
+ case SDL_LOG_PRIORITY_VERBOSE:
+ case SDL_LOG_PRIORITY_DEBUG:
+ log_level = Common::Log::LogLevel::LDEBUG;
+ break;
+ case SDL_LOG_PRIORITY_INFO:
+ log_level = Common::Log::LogLevel::LINFO;
+ break;
+ case SDL_LOG_PRIORITY_WARN:
+ log_level = Common::Log::LogLevel::LWARNING;
+ break;
+ case SDL_LOG_PRIORITY_ERROR:
+ log_level = Common::Log::LogLevel::LERROR;
+ break;
+ case SDL_LOG_PRIORITY_CRITICAL:
+ log_level = Common::Log::LogLevel::LNOTICE;
+ break;
+ }
+
+ GENERIC_LOG_FMT(Common::Log::LogType::CONTROLLERINTERFACE, log_level, "{}: {}",
+ category_name, message);
+ },
+ nullptr);
+}
+
void Init()
{
#if !SDL_VERSION_ATLEAST(2, 0, 0)
- if (SDL_Init(SDL_INIT_JOYSTICK) != 0)
+ if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) != 0)
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to initialize");
return;
#else
@@ -88,16 +158,27 @@ void Init()
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
#endif
+
+ EnableSDLLogging();
+
+#if SDL_VERSION_ATLEAST(2, 0, 14)
+ // This is required on windows so that SDL's joystick code properly pumps window messages
+ SDL_SetHint(SDL_HINT_JOYSTICK_THREAD, "1");
+#endif
+
+#if SDL_VERSION_ATLEAST(2, 0, 9)
+ SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
+#endif
+
s_hotplug_thread = std::thread([] {
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(); });
- if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) != 0)
+ if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER) != 0)
{
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to initialize");
return;
@@ -125,11 +206,34 @@ void Init()
}
}
+#ifdef _WIN32
+ // This is a hack to workaround SDL_hidapi using window messages to detect device
+ // removal/arrival, yet no part of SDL pumps messages for it. It can hopefully be removed in the
+ // future when SDL fixes the issue. Note this is a separate issue from SDL_HINT_JOYSTICK_THREAD.
+ // Also note that SDL_WaitEvent may block while device detection window messages get queued up,
+ // causing some noticible stutter. This is just another reason it should be fixed properly by
+ // SDL...
+ const auto window_handle =
+ FindWindowEx(HWND_MESSAGE, nullptr, TEXT("SDL_HIDAPI_DEVICE_DETECTION"), nullptr);
+#endif
+
SDL_Event e;
while (SDL_WaitEvent(&e) != 0)
{
if (!HandleEventAndContinue(e))
return;
+
+#ifdef _WIN32
+ MSG msg;
+ while (window_handle && PeekMessage(&msg, window_handle, 0, 0, PM_NOREMOVE))
+ {
+ if (GetMessageA(&msg, window_handle, 0, 0) != 0)
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+#endif
}
});
@@ -172,10 +276,13 @@ void PopulateDevices()
Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index)
: m_joystick(joystick), m_name(StripSpaces(GetJoystickName(sdl_index)))
{
-// really bad HACKS:
-// to not use SDL for an XInput device
-// too many people on the forums pick the SDL device and ask:
-// "why don't my 360 gamepad triggers/rumble work correctly"
+ // really bad HACKS:
+ // to not use SDL for an XInput device
+ // too many people on the forums pick the SDL device and ask:
+ // "why don't my 360 gamepad triggers/rumble work correctly"
+ // XXX x360 controllers _should_ work on modern SDL2, so it's unclear why they're
+ // still broken. Perhaps it's because we're not pumping window messages, which SDL seems to
+ // expect.
#ifdef _WIN32
// checking the name is probably good (and hacky) enough
// but I'll double check with the num of buttons/axes
@@ -183,7 +290,7 @@ Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index)
Common::ToLower(&lcasename);
if ((std::string::npos != lcasename.find("xbox 360")) &&
- (10 == SDL_JoystickNumButtons(joystick)) && (5 == SDL_JoystickNumAxes(joystick)) &&
+ (11 == SDL_JoystickNumButtons(joystick)) && (6 == SDL_JoystickNumAxes(joystick)) &&
(1 == SDL_JoystickNumHats(joystick)) && (0 == SDL_JoystickNumBalls(joystick)))
{
// this device won't be used
@@ -220,53 +327,110 @@ Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index)
}
#ifdef USE_SDL_HAPTIC
- m_haptic = SDL_HapticOpenFromJoystick(m_joystick);
- if (!m_haptic)
- return;
-
- const unsigned int supported_effects = SDL_HapticQuery(m_haptic);
-
- // Disable autocenter:
- if (supported_effects & SDL_HAPTIC_AUTOCENTER)
- SDL_HapticSetAutocenter(m_haptic, 0);
-
- // Constant
- if (supported_effects & SDL_HAPTIC_CONSTANT)
- AddOutput(new ConstantEffect(m_haptic));
-
- // Ramp
- if (supported_effects & SDL_HAPTIC_RAMP)
- AddOutput(new RampEffect(m_haptic));
-
- // Periodic
- for (auto waveform :
- {SDL_HAPTIC_SINE, SDL_HAPTIC_TRIANGLE, SDL_HAPTIC_SAWTOOTHUP, SDL_HAPTIC_SAWTOOTHDOWN})
+ if (SDL_JoystickIsHaptic(m_joystick))
{
- if (supported_effects & waveform)
- AddOutput(new PeriodicEffect(m_haptic, waveform));
+ m_haptic = SDL_HapticOpenFromJoystick(m_joystick);
+ if (m_haptic)
+ {
+ const unsigned int supported_effects = SDL_HapticQuery(m_haptic);
+
+ // Disable autocenter:
+ if (supported_effects & SDL_HAPTIC_AUTOCENTER)
+ SDL_HapticSetAutocenter(m_haptic, 0);
+
+ // Constant
+ if (supported_effects & SDL_HAPTIC_CONSTANT)
+ AddOutput(new ConstantEffect(m_haptic));
+
+ // Ramp
+ if (supported_effects & SDL_HAPTIC_RAMP)
+ AddOutput(new RampEffect(m_haptic));
+
+ // Periodic
+ for (auto waveform :
+ {SDL_HAPTIC_SINE, SDL_HAPTIC_TRIANGLE, SDL_HAPTIC_SAWTOOTHUP, SDL_HAPTIC_SAWTOOTHDOWN})
+ {
+ if (supported_effects & waveform)
+ AddOutput(new PeriodicEffect(m_haptic, waveform));
+ }
+
+ // LeftRight
+ if (supported_effects & SDL_HAPTIC_LEFTRIGHT)
+ {
+ AddOutput(new LeftRightEffect(m_haptic, LeftRightEffect::Motor::Strong));
+ AddOutput(new LeftRightEffect(m_haptic, LeftRightEffect::Motor::Weak));
+ }
+ }
}
+#endif
- // LeftRight
- if (supported_effects & SDL_HAPTIC_LEFTRIGHT)
+#if SDL_VERSION_ATLEAST(2, 0, 9)
+ if (!m_haptic)
{
- AddOutput(new LeftRightEffect(m_haptic, LeftRightEffect::Motor::Strong));
- AddOutput(new LeftRightEffect(m_haptic, LeftRightEffect::Motor::Weak));
+ AddOutput(new Motor(m_joystick));
+ }
+#endif
+
+#ifdef USE_SDL_GAMECONTROLLER
+ if (SDL_IsGameController(sdl_index))
+ {
+ m_controller = SDL_GameControllerOpen(sdl_index);
+ if (m_controller)
+ {
+ if (SDL_GameControllerSetSensorEnabled(m_controller, SDL_SENSOR_ACCEL, SDL_TRUE) == 0)
+ {
+ AddInput(new MotionInput("Accel Up", m_controller, SDL_SENSOR_ACCEL, 1, 1));
+ AddInput(new MotionInput("Accel Down", m_controller, SDL_SENSOR_ACCEL, 1, -1));
+
+ AddInput(new MotionInput("Accel Left", m_controller, SDL_SENSOR_ACCEL, 0, -1));
+ AddInput(new MotionInput("Accel Right", m_controller, SDL_SENSOR_ACCEL, 0, 1));
+
+ AddInput(new MotionInput("Accel Forward", m_controller, SDL_SENSOR_ACCEL, 2, -1));
+ AddInput(new MotionInput("Accel Backward", m_controller, SDL_SENSOR_ACCEL, 2, 1));
+ }
+
+ if (SDL_GameControllerSetSensorEnabled(m_controller, SDL_SENSOR_GYRO, SDL_TRUE) == 0)
+ {
+ AddInput(new MotionInput("Gyro Pitch Up", m_controller, SDL_SENSOR_GYRO, 0, 1));
+ AddInput(new MotionInput("Gyro Pitch Down", m_controller, SDL_SENSOR_GYRO, 0, -1));
+
+ AddInput(new MotionInput("Gyro Roll Left", m_controller, SDL_SENSOR_GYRO, 2, 1));
+ AddInput(new MotionInput("Gyro Roll Right", m_controller, SDL_SENSOR_GYRO, 2, -1));
+
+ AddInput(new MotionInput("Gyro Yaw Left", m_controller, SDL_SENSOR_GYRO, 1, 1));
+ AddInput(new MotionInput("Gyro Yaw Right", m_controller, SDL_SENSOR_GYRO, 1, -1));
+ }
+ }
}
#endif
}
Joystick::~Joystick()
{
+#ifdef USE_SDL_GAMECONTROLLER
+ if (m_controller)
+ {
+ SDL_GameControllerClose(m_controller);
+ m_controller = nullptr;
+ }
+#endif
+
#ifdef USE_SDL_HAPTIC
if (m_haptic)
{
// stop/destroy all effects
SDL_HapticStopAll(m_haptic);
- // close haptic first
+ // close haptic before joystick
SDL_HapticClose(m_haptic);
+ m_haptic = nullptr;
}
#endif
+#if SDL_VERSION_ATLEAST(2, 0, 9)
+ // stop all rumble
+ SDL_JoystickRumble(m_joystick, 0, 0, 0);
+#endif
+
// close joystick
SDL_JoystickClose(m_joystick);
}
@@ -442,6 +606,19 @@ bool Joystick::LeftRightEffect::UpdateParameters(s16 value)
}
#endif
+#if SDL_VERSION_ATLEAST(2, 0, 9)
+std::string Joystick::Motor::GetName() const
+{
+ return "Motor";
+}
+
+void Joystick::Motor::SetState(ControlState state)
+{
+ Uint16 rumble = state * std::numeric_limits::max();
+ SDL_JoystickRumble(m_js, rumble, rumble, std::numeric_limits::max());
+}
+#endif
+
void Joystick::UpdateInput()
{
// TODO: Don't call this for every Joystick, only once per ControllerInterface::UpdateInput()
@@ -492,4 +669,14 @@ ControlState Joystick::Hat::GetState() const
{
return (SDL_JoystickGetHat(m_js, m_index) & (1 << m_direction)) > 0;
}
+#ifdef USE_SDL_GAMECONTROLLER
+
+ControlState Joystick::MotionInput::GetState() const
+{
+ std::array data{};
+ SDL_GameControllerGetSensorData(m_gc, m_type, data.data(), (int)data.size());
+ return m_scale * data[m_index];
+}
+
+#endif
} // namespace ciface::SDL
diff --git a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h
index 7fbf7cf23e..f789c8846a 100644
--- a/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h
+++ b/Source/Core/InputCommon/ControllerInterface/SDL/SDL.h
@@ -9,10 +9,18 @@
#define USE_SDL_HAPTIC
#endif
+#if SDL_VERSION_ATLEAST(2, 0, 14)
+#define USE_SDL_GAMECONTROLLER
+#endif
+
#ifdef USE_SDL_HAPTIC
#include
#endif
+#ifdef USE_SDL_GAMECONTROLLER
+#include
+#endif
+
#include "InputCommon/ControllerInterface/CoreDevice.h"
namespace ciface::SDL
@@ -137,6 +145,42 @@ private:
};
#endif
+#if SDL_VERSION_ATLEAST(2, 0, 9)
+ class Motor : public Output
+ {
+ public:
+ explicit Motor(SDL_Joystick* js) : m_js(js){};
+ std::string GetName() const override;
+ void SetState(ControlState state) override;
+
+ private:
+ SDL_Joystick* const m_js;
+ };
+#endif
+
+#ifdef USE_SDL_GAMECONTROLLER
+ class MotionInput : public Input
+ {
+ public:
+ MotionInput(const char* name, SDL_GameController* gc, SDL_SensorType type, int index,
+ ControlState scale)
+ : m_name(name), m_gc(gc), m_type(type), m_index(index), m_scale(scale){};
+
+ std::string GetName() const override { return m_name; };
+ bool IsDetectable() const override { return false; };
+ ControlState GetState() const override;
+
+ private:
+ const char* m_name;
+
+ SDL_GameController* const m_gc;
+ SDL_SensorType const m_type;
+ int const m_index;
+
+ ControlState const m_scale;
+ };
+#endif
+
public:
void UpdateInput() override;
@@ -152,7 +196,11 @@ private:
std::string m_name;
#ifdef USE_SDL_HAPTIC
- SDL_Haptic* m_haptic;
+ SDL_Haptic* m_haptic = nullptr;
+#endif
+
+#ifdef USE_SDL_GAMECONTROLLER
+ SDL_GameController* m_controller = nullptr;
#endif
};
} // namespace ciface::SDL
diff --git a/Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp b/Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp
index a9c28efdc0..42aa12a141 100644
--- a/Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/Win32/Win32.cpp
@@ -73,11 +73,13 @@ void ciface::Win32::Init(void* hwnd)
}
Common::ScopeGuard uninit([] { CoUninitialize(); });
+ const auto window_name = TEXT("DolphinWin32ControllerInterface");
+
WNDCLASSEX window_class_info{};
window_class_info.cbSize = sizeof(window_class_info);
window_class_info.lpfnWndProc = WindowProc;
window_class_info.hInstance = GetModuleHandle(nullptr);
- window_class_info.lpszClassName = L"Message";
+ window_class_info.lpszClassName = window_name;
ATOM window_class = RegisterClassEx(&window_class_info);
if (!window_class)
@@ -92,7 +94,7 @@ void ciface::Win32::Init(void* hwnd)
Common::HRWrap(GetLastError()));
});
- message_window = CreateWindowEx(0, L"Message", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr,
+ message_window = CreateWindowEx(0, window_name, nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr,
nullptr, nullptr);
promise_guard.Exit();
if (!message_window)
diff --git a/Source/VSProps/Base.props b/Source/VSProps/Base.props
index 49f546d39f..ae821339cc 100644
--- a/Source/VSProps/Base.props
+++ b/Source/VSProps/Base.props
@@ -52,6 +52,7 @@
$(ExternalsDir)picojson;%(AdditionalIncludeDirectories)
$(ExternalsDir)pugixml;%(AdditionalIncludeDirectories)
$(ExternalsDir)rangeset\include;%(AdditionalIncludeDirectories)
+ $(ExternalsDir)SDL\SDL\include;%(AdditionalIncludeDirectories)
$(ExternalsDir)SFML\include;%(AdditionalIncludeDirectories)
$(ExternalsDir)soundtouch;%(AdditionalIncludeDirectories)
$(ExternalsDir)Vulkan\include;%(AdditionalIncludeDirectories)
@@ -91,6 +92,7 @@
HAS_LIBMGBA;%(PreprocessorDefinitions)
AUTOUPDATE=1;%(PreprocessorDefinitions)
SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS;%(PreprocessorDefinitions)
+ HAVE_SDL2=1;%(PreprocessorDefinitions)
diff --git a/Source/dolphin-emu.sln b/Source/dolphin-emu.sln
index 89df520d9b..b289f27548 100644
--- a/Source/dolphin-emu.sln
+++ b/Source/dolphin-emu.sln
@@ -81,6 +81,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "..\Externals\fmt\fmt
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spirv_cross", "..\Externals\spirv_cross\spirv_cross.vcxproj", "{3d780617-ec8c-4721-b9fd-dfc9bb658c7c}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL2", "..\Externals\SDL\SDL2.vcxproj", "{8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -389,6 +391,14 @@ Global
{3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Release|ARM64.Build.0 = Release|ARM64
{3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Release|x64.ActiveCfg = Release|x64
{3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Release|x64.Build.0 = Release|x64
+ {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Debug|ARM64.Build.0 = Debug|ARM64
+ {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Debug|x64.ActiveCfg = Debug|x64
+ {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Debug|x64.Build.0 = Debug|x64
+ {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Release|ARM64.ActiveCfg = Release|ARM64
+ {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Release|ARM64.Build.0 = Release|ARM64
+ {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Release|x64.ActiveCfg = Release|x64
+ {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -422,6 +432,7 @@ Global
{864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
{4BC5A148-0AB3-440F-A980-A29B4B999190} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
{3D780617-EC8C-4721-B9FD-DFC9BB658C7C} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
+ {8DC244EE-A0BD-4038-BAF7-CFAFA5EB2BAA} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {64B0A343-3B94-4522-9C24-6937FE5EFB22}