input+build: Make SDL optional

This commit is contained in:
SSimco 2026-05-08 21:02:34 +03:00
parent f3fecba313
commit c83ba4ada8
18 changed files with 89 additions and 58 deletions

View File

@ -246,7 +246,7 @@ Example usage: `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DENABLE_SDL=ON -
| ENABLE_DISCORD_RPC | | Enable Discord Rich presence support | ON | |
| ENABLE_OPENGL | | Enable OpenGL graphics backend | ON | Currently required |
| ENABLE_HIDAPI | | Enable HIDAPI (used for Wiimote controller API) | ON | |
| ENABLE_SDL | | Enable SDLController controller API | ON | Currently required |
| ENABLE_SDL | | Enable SDLController controller API | ON | |
| ENABLE_VCPKG | | Use VCPKG package manager to obtain dependencies | ON | |
| ENABLE_VULKAN | | Enable the Vulkan graphics backend | ON | |
| ENABLE_WXWIDGETS | | Enable wxWidgets UI | ON | Currently required |

View File

@ -148,7 +148,6 @@ option(ENABLE_CUBEB "Enabled cubeb backend" ON)
option(ENABLE_WXWIDGETS "Build with wxWidgets UI (Currently required)" ON)
find_package(Threads REQUIRED)
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3)
find_package(CURL REQUIRED)
find_package(pugixml REQUIRED)
find_package(RapidJSON REQUIRED)
@ -162,6 +161,11 @@ find_package(glm REQUIRED)
find_package(fmt 9 REQUIRED)
find_package(PNG REQUIRED)
if(ENABLE_SDL)
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3)
add_compile_definitions(HAS_SDL)
endif()
# glslang versions older than 11.11.0 define targets without a namespace
if (NOT TARGET glslang::SPIRV AND TARGET SPIRV)
add_library(glslang::SPIRV ALIAS SPIRV)

View File

@ -207,9 +207,12 @@ target_link_libraries(CemuBin PRIVATE
CemuGui
CemuInput
CemuUtil
SDL3::SDL3
)
if(ENABLE_SDL)
target_link_libraries(CemuBin PRIVATE SDL3::SDL3)
endif()
if(UNIX AND NOT APPLE)
# due to nasm output some linkers will make stack executable
# cemu does not require this so we explicity disable it

View File

@ -147,7 +147,6 @@ target_link_libraries(CemuWxGui PRIVATE
libzip::zip
ZArchive::zarchive
CemuComponents
SDL3::SDL3
pugixml::pugixml
CemuCafe
PUBLIC
@ -166,6 +165,10 @@ if(ENABLE_CUBEB)
target_link_libraries(CemuWxGui PRIVATE cubeb::cubeb)
endif()
if(ENABLE_SDL)
target_link_libraries(CemuWxGui PRIVATE SDL3::SDL3)
endif()
if(UNIX AND NOT APPLE)
if(ENABLE_FERAL_GAMEMODE)
target_link_libraries(CemuWxGui PRIVATE gamemode)

View File

@ -15,10 +15,6 @@ add_library(CemuInput
api/DSU/DSUControllerProvider.h
api/DSU/DSUMessages.h
api/DSU/DSUMessages.cpp
api/SDL/SDLController.cpp
api/SDL/SDLControllerProvider.cpp
api/SDL/SDLController.h
api/SDL/SDLControllerProvider.h
api/Keyboard/KeyboardControllerProvider.h
api/Keyboard/KeyboardControllerProvider.cpp
api/Keyboard/KeyboardController.cpp
@ -92,6 +88,16 @@ if (SUPPORTS_WIIMOTE)
endif ()
if(ENABLE_SDL)
target_sources(CemuInput PRIVATE
api/SDL/SDLController.cpp
api/SDL/SDLControllerProvider.cpp
api/SDL/SDLController.h
api/SDL/SDLControllerProvider.h
)
target_link_libraries(CemuInput PRIVATE SDL3::SDL3)
endif()
target_include_directories(CemuInput PUBLIC "../")
target_link_libraries(CemuInput PRIVATE

View File

@ -5,7 +5,6 @@
#include "input/emulated/ClassicController.h"
#include "input/emulated/WiimoteController.h"
#include "input/api/SDL/SDLController.h"
#include "input/api/Keyboard/KeyboardController.h"
#include "input/api/DSU/DSUController.h"
#include "input/api/GameCube/GameCubeController.h"
@ -19,6 +18,10 @@
#include "input/api/Wiimote/NativeWiimoteController.h"
#endif
#ifdef HAS_SDL
#include "input/api/SDL/SDLController.h"
#endif
ControllerPtr ControllerFactory::CreateController(InputAPI::Type api, std::string_view uuid,
std::string_view display_name)
{
@ -59,7 +62,7 @@ ControllerPtr ControllerFactory::CreateController(InputAPI::Type api, std::strin
return std::make_shared<XInputController>(index);
}
#endif
#if HAS_SDL
#ifdef HAS_SDL
case InputAPI::SDLController:
{
// diid_guid
@ -137,7 +140,7 @@ ControllerProviderPtr ControllerFactory::CreateControllerProvider(InputAPI::Type
case InputAPI::Keyboard:
return std::make_shared<KeyboardControllerProvider>();
#endif
#if HAS_SDL
#ifdef HAS_SDL
case InputAPI::SDLController:
return std::make_shared<SDLControllerProvider>();
#endif

View File

@ -28,7 +28,7 @@ InputManager::InputManager()
#if HAS_KEYBOARD
create_provider<KeyboardControllerProvider>();
#endif
#if HAS_SDL
#ifdef HAS_SDL
create_provider<SDLControllerProvider>();
#endif
#if HAS_XINPUT

View File

@ -9,9 +9,10 @@
#include "input/api/Wiimote/WiimoteControllerProvider.h"
#endif
#include "util/helpers/Singleton.h"
#ifdef HAS_SDL
#include "input/api/SDL/SDLControllerProvider.h"
#endif
#include "input/api/Keyboard/KeyboardControllerProvider.h"
#include "input/api/DSU/DSUControllerProvider.h"
#include "input/api/GameCube/GameCubeControllerProvider.h"
@ -19,8 +20,7 @@
#include "input/emulated/VPADController.h"
#include "input/emulated/WPADController.h"
#include <atomic>
#include <optional>
#include "util/helpers/Singleton.h"
class InputManager : public Singleton<InputManager>
{
@ -108,16 +108,14 @@ private:
std::array<bool, kMaxController> m_is_gameprofile_set{};
template <typename TProvider>
void create_provider() // lambda templates only work in c++20 -> define locally in ctor
template<std::derived_from<ControllerProviderBase> TProvider>
void create_provider()
{
static_assert(std::is_base_of_v<ControllerProviderBase, TProvider>);
try
{
auto controller = std::make_shared<TProvider>();
m_api_available[controller->api()] = std::vector<ControllerProviderPtr>{ controller };
}
catch (const std::exception& ex)
m_api_available[controller->api()] = std::vector<ControllerProviderPtr>{controller};
} catch (const std::exception& ex)
{
cemuLog_log(LogType::Force, ex.what());
}

View File

@ -7,6 +7,19 @@ ControllerBase::ControllerBase(std::string_view uuid, std::string_view display_n
{
}
inline void apply_axis_button(ControllerButtonState& buttons, const glm::vec2& axis, int flag)
{
if (axis.x < -ControllerState::kAxisThreshold)
buttons.SetButtonState(flag + (kAxisXN - kAxisXP), true);
else if (axis.x > ControllerState::kAxisThreshold)
buttons.SetButtonState(flag, true);
if (axis.y < -ControllerState::kAxisThreshold)
buttons.SetButtonState(flag + 1 + (kAxisXN - kAxisXP), true);
else if (axis.y > ControllerState::kAxisThreshold)
buttons.SetButtonState(flag + 1, true);
}
const ControllerState& ControllerBase::update_state()
{
if (!m_is_calibrated)
@ -21,26 +34,9 @@ const ControllerState& ControllerBase::update_state()
apply_axis_setting(result.rotation, m_default_state.rotation, m_settings.rotation);
apply_axis_setting(result.trigger, m_default_state.trigger, m_settings.trigger);
#define APPLY_AXIS_BUTTON(_axis_, _flag_) \
if (result._axis_.x < -ControllerState::kAxisThreshold) \
result.buttons.SetButtonState((_flag_) + (kAxisXN - kAxisXP), true); \
else if (result._axis_.x > ControllerState::kAxisThreshold) \
result.buttons.SetButtonState((_flag_), true); \
if (result._axis_.y < -ControllerState::kAxisThreshold) \
result.buttons.SetButtonState((_flag_) + 1 + (kAxisXN - kAxisXP), true); \
else if (result._axis_.y > ControllerState::kAxisThreshold) \
result.buttons.SetButtonState((_flag_) + 1, true);
if (result.axis.x < -ControllerState::kAxisThreshold)
result.buttons.SetButtonState((kAxisXP) + (kAxisXN - kAxisXP), true);
else if (result.axis.x > ControllerState::kAxisThreshold)
result.buttons.SetButtonState((kAxisXP), true);
if (result.axis.y < -ControllerState::kAxisThreshold)
result.buttons.SetButtonState((kAxisXP) + 1 + (kAxisXN - kAxisXP), true);
else if (result.axis.y > ControllerState::kAxisThreshold)
result.buttons.SetButtonState((kAxisXP) + 1, true);
APPLY_AXIS_BUTTON(rotation, kRotationXP);
APPLY_AXIS_BUTTON(trigger, kTriggerXP);
apply_axis_button(result.buttons, result.axis, kAxisXP);
apply_axis_button(result.buttons, result.rotation, kRotationXP);
apply_axis_button(result.buttons, result.trigger, kTriggerXP);
/*
// positive values
@ -64,9 +60,6 @@ const ControllerState& ControllerBase::update_state()
kTriggerYN,
*/
#undef APPLY_AXIS_BUTTON
WindowSystem::CaptureInput(result, m_last_state);
m_last_state = std::move(result);
@ -200,7 +193,6 @@ std::string ControllerBase::get_button_name(uint64 button) const
case kTriggerYN: return "y-Trigger-";
}
return fmt::format("Button {}", (uint64)button);
}

View File

@ -168,14 +168,13 @@ protected:
Settings m_settings{};
};
template<class TProvider>
template<std::derived_from<ControllerProviderBase> TProvider>
class Controller : public ControllerBase
{
public:
Controller(std::string_view uuid, std::string_view display_name)
: ControllerBase(uuid, display_name)
{
static_assert(std::is_base_of_v<ControllerProviderBase, TProvider>);
m_provider = std::dynamic_pointer_cast<TProvider>(InputManager::instance().get_api_provider(TProvider::kAPIType));
cemu_assert_debug(m_provider != nullptr);
}
@ -183,7 +182,6 @@ public:
Controller(std::string_view uuid, std::string_view display_name, const ControllerProviderSettings& settings)
: ControllerBase(uuid, display_name)
{
static_assert(std::is_base_of_v<ControllerProviderBase, TProvider>);
m_provider = std::dynamic_pointer_cast<TProvider>(InputManager::instance().get_api_provider(TProvider::kAPIType, settings));
cemu_assert_debug(m_provider != nullptr);
}

View File

@ -3,10 +3,6 @@
#include "input/motion/MotionHandler.h"
#include "input/api/ControllerProvider.h"
#ifndef HAS_SDL
#define HAS_SDL 1
#endif
static bool operator==(const SDL_GUID& g1, const SDL_GUID& g2)
{
return memcmp(&g1, &g2, sizeof(SDL_GUID)) == 0;

View File

@ -1,4 +1,5 @@
#include "HidapiWiimote.h"
#include <SDL3/SDL.h>
#include <cwchar>
static constexpr uint16 WIIMOTE_VENDOR_ID = 0x057e;

View File

@ -1,11 +1,10 @@
#pragma once
#include <api/Wiimote/WiimoteDevice.h>
#include <SDL3/SDL.h>
class HidapiWiimote : public WiimoteDevice {
public:
HidapiWiimote(SDL_hid_device* dev, std::string_view path);
HidapiWiimote(struct SDL_hid_device* dev, std::string_view path);
~HidapiWiimote() override;
bool write_data(const std::vector<uint8> &data) override;
@ -15,7 +14,7 @@ public:
static std::vector<WiimoteDevicePtr> get_devices();
private:
SDL_hid_device* m_handle;
struct SDL_hid_device* m_handle;
const std::string m_path;
};

View File

@ -1,7 +1,9 @@
#include "input/emulated/ClassicController.h"
#include "input/api/Controller.h"
#ifdef HAS_SDL
#include "input/api/SDL/SDLController.h"
#endif
ClassicController::ClassicController(size_t player_index)
: WPADController(player_index, kDataFormat_CLASSIC)
@ -130,6 +132,7 @@ bool ClassicController::set_default_mapping(const std::shared_ptr<ControllerBase
std::vector<std::pair<uint64, uint64>> mapping;
switch (controller->api())
{
#ifdef HAS_SDL
case InputAPI::SDLController: {
const auto sdl_controller = std::static_pointer_cast<SDLController>(controller);
if (sdl_controller->get_guid() == SDLController::kLeftJoyCon)
@ -206,6 +209,7 @@ bool ClassicController::set_default_mapping(const std::shared_ptr<ControllerBase
};
}
}
#endif
case InputAPI::XInput:
{
mapping =

View File

@ -1,7 +1,9 @@
#include "input/emulated/ProController.h"
#include "input/api/Controller.h"
#ifdef HAS_SDL
#include "input/api/SDL/SDLController.h"
#endif
ProController::ProController(size_t player_index)
: WPADController(player_index, kDataFormat_URCC)
@ -135,6 +137,7 @@ bool ProController::set_default_mapping(const std::shared_ptr<ControllerBase>& c
std::vector<std::pair<uint64, uint64>> mapping;
switch (controller->api())
{
#ifdef HAS_SDL
case InputAPI::SDLController: {
const auto sdl_controller = std::static_pointer_cast<SDLController>(controller);
if (sdl_controller->get_guid() == SDLController::kLeftJoyCon)
@ -219,6 +222,7 @@ bool ProController::set_default_mapping(const std::shared_ptr<ControllerBase>& c
}
break;
}
#endif
case InputAPI::XInput:
{
mapping =

View File

@ -1,6 +1,8 @@
#include "input/emulated/VPADController.h"
#include "input/api/Controller.h"
#ifdef HAS_SDL
#include "input/api/SDL/SDLController.h"
#endif
#include "WindowSystem.h"
#include "input/InputManager.h"
#include "Cafe/HW/Latte/Core/Latte.h"
@ -510,6 +512,7 @@ bool VPADController::set_default_mapping(const std::shared_ptr<ControllerBase>&
std::vector<std::pair<uint64, uint64>> mapping;
switch (controller->api())
{
#ifdef HAS_SDL
case InputAPI::SDLController: {
const auto sdl_controller = std::static_pointer_cast<SDLController>(controller);
if (sdl_controller->get_guid() == SDLController::kLeftJoyCon)
@ -633,6 +636,7 @@ bool VPADController::set_default_mapping(const std::shared_ptr<ControllerBase>&
}
break;
}
#endif
case InputAPI::XInput:
{
mapping =

View File

@ -30,9 +30,11 @@
#pragma comment(lib,"Dbghelp.lib")
#endif
#ifdef HAS_SDL
#define SDL_MAIN_HANDLED
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#endif
#if BOOST_OS_LINUX
#define _putenv(__s) putenv((char*)(__s))
@ -235,7 +237,9 @@ int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int
{
if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE)))
cemuLog_log(LogType::Force, "CoInitializeEx() failed");
#ifdef HAS_SDL
SDL_SetMainReady();
#endif
if (!LaunchSettings::HandleCommandline(lpCmdLine))
return 0;
WindowSystem::Create();
@ -247,7 +251,9 @@ int main(int argc, char* argv[])
{
if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE)))
cemuLog_log(LogType::Force, "CoInitializeEx() failed");
#ifdef HAS_SDL
SDL_SetMainReady();
#endif
if (!LaunchSettings::HandleCommandline(argc, argv))
return 0;
WindowSystem::Create();

View File

@ -1,9 +1,13 @@
#include "Cemu/Logging/CemuLogging.h"
#ifdef HAS_SDL
#include <SDL3/SDL.h>
#endif
class ScreenSaver
{
public:
#ifdef HAS_SDL
public:
static void SetInhibit(bool inhibit)
{
bool* inhibitArg = new bool(inhibit);
@ -15,7 +19,7 @@ public:
}
}
private:
private:
static void SDLCALL SetInhibitCallback(void* userdata)
{
if (!userdata)
@ -59,4 +63,10 @@ private:
}
}
}
#else
public:
static void SetInhibit(bool /*inhibit*/)
{
}
#endif
};