Gamepad/joystick porting to SDL3

This commit is contained in:
Adrian Conlon committed 2026-08-24 07:51:54 +01:00
1 parent 6dd115db64
commit 3a64cc74d1
4 files changed
+18 -78

No files matched your search

+2 -4
View File
@@ -48,8 +48,8 @@ namespace Gaming {
virtual void runRasterLines() {};
virtual void runVerticalBlank() {}
void addJoystick(SDL_Event& e);
void removeJoystick(SDL_Event& e);
void addGamepad(SDL_Event& e);
void removeGamepad(SDL_Event& e);
virtual void updateTexture();
virtual void renderTexture();
@@ -69,7 +69,6 @@ namespace Gaming {
void toggleFullscreen();
[[nodiscard]] std::shared_ptr<GameController> gamepad(int which) const;
[[nodiscard]] int mappedController(const SDL_JoystickID which) const;
[[nodiscard]] int chooseControllerIndex(int who) const;
[[nodiscard]] std::shared_ptr<GameController> chooseController(int who) const;
@@ -95,7 +94,6 @@ namespace Gaming {
Uint64 m_frameEndTime = 0; // in performance frequency
std::map<int, std::shared_ptr<GameController>> m_gameControllers;
std::map<SDL_JoystickID, int> m_mappedControllers;
void configureBackground() const;
void createBitmapTexture();
-16
View File
@@ -15,27 +15,11 @@ namespace Gaming {
void startRumble() noexcept;
void stopRumble() noexcept;
[[nodiscard]] static auto buildJoystickId(SDL_Gamepad* gamepad) noexcept {
auto* joystick = ::SDL_GetGamepadJoystick(gamepad);
Wrapper::maybeThrowException(joystick, "Unable to obtain joystick from gamepad");
return ::SDL_GetJoystickID(joystick);
}
[[nodiscard]] auto getJoystickId() const noexcept {
return buildJoystickId(m_gamepad.get());
}
private:
int m_index;
std::shared_ptr<SDL_Gamepad> m_gamepad;
void open();
void close() noexcept;
std::shared_ptr<SDL_Haptic> m_haptic;
bool m_hapticRumbleSupported = false;
void openHaptic();
void closeHaptic() noexcept;
};
}
+8 -22
View File
@@ -119,11 +119,11 @@ void Game::handleEvents() {
case SDL_EVENT_GAMEPAD_BUTTON_UP:
handleGamepadButtonUp(e.gbutton);
break;
case SDL_EVENT_JOYSTICK_ADDED:
addJoystick(e);
case SDL_EVENT_GAMEPAD_ADDED:
addGamepad(e);
break;
case SDL_EVENT_JOYSTICK_REMOVED:
removeJoystick(e);
case SDL_EVENT_GAMEPAD_REMOVED:
removeGamepad(e);
break;
}
}
@@ -166,26 +166,19 @@ void Game::synchronise() {
}
}
void Game::removeJoystick(SDL_Event& e) {
const auto which = e.jdevice.which;
void Game::removeGamepad(SDL_Event& e) {
const auto which = e.gdevice.which;
const auto found = m_gameControllers.find(which);
assert(found != m_gameControllers.end());
auto& controller = found->second;
const auto joystickId = controller->getJoystickId();
m_mappedControllers.erase(joystickId);
m_gameControllers.erase(which);
SDL_Log("Joystick device %d removed (%zd controllers)", which, m_gameControllers.size());
}
void Game::addJoystick(SDL_Event& e) {
const auto which = e.jdevice.which;
void Game::addGamepad(SDL_Event& e) {
const auto which = e.gdevice.which;
assert(m_gameControllers.find(which) == m_gameControllers.end());
auto controller = std::make_shared<GameController>(which);
const auto joystickId = controller->getJoystickId();
m_gameControllers[which] = controller;
assert(m_mappedControllers.contains(joystickId));
m_mappedControllers[joystickId] = which;
SDL_Log("Joystick device %d added (%zd controllers)", which, m_gameControllers.size());
}
std::shared_ptr<GameController> Game::gamepad(const int which) const {
@@ -195,13 +188,6 @@ std::shared_ptr<GameController> Game::gamepad(const int which) const {
return i->second;
}
int Game::mappedController(const SDL_JoystickID which) const {
const auto i = m_mappedControllers.find(which);
if (i == m_mappedControllers.cend())
throw std::runtime_error("Unknown joystick");
return i->second;
}
// -1 if no controllers, otherwise index
int Game::chooseControllerIndex(const int who) const {
const auto count = m_gameControllers.size();
+8 -36
View File
@@ -14,51 +14,23 @@ namespace Gaming {
}
void GameController::open() {
int count;
auto* joysticks = SDL_GetJoysticks(&count);
Wrapper::maybeThrowException(joysticks, "Unable to obtain joystick information");
::SDL_free(joysticks);
assert(count > 0);
assert(m_index < count);
if (::SDL_IsGamepad(m_index)) {
m_gamepad.reset(::SDL_OpenGamepad(m_index), ::SDL_CloseGamepad);
Wrapper::maybeThrowException(m_gamepad.get(), "Unable to open gamepad");
openHaptic();
const auto* name = ::SDL_GetGamepadName(m_gamepad.get());
Wrapper::maybeThrowException(name, "Unable to obtain gamepad name");
::SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "Game controller name: %s", name);
} else {
::SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Joystick is not a game controller");
}
}
void GameController::openHaptic() {
m_haptic.reset(::SDL_OpenHaptic(m_index), ::SDL_CloseHaptic);
Wrapper::maybeThrowException(m_haptic.get(), "Unable to open haptic gamepad");
const auto success = ::SDL_InitHapticRumble(m_haptic.get());
Wrapper::maybeThrowException(success, "Unable to initialise haptic gamepad");
m_hapticRumbleSupported = ::SDL_HapticRumbleSupported(m_haptic.get());
}
void GameController::closeHaptic() noexcept {
m_haptic.reset();
m_hapticRumbleSupported = false;
assert(::SDL_IsGamepad(m_index));
m_gamepad.reset(::SDL_OpenGamepad(m_index), ::SDL_CloseGamepad);
Wrapper::maybeThrowException(m_gamepad.get(), "Unable to open gamepad");
const auto* name = ::SDL_GetGamepadName(m_gamepad.get());
Wrapper::maybeThrowException(name, "Unable to obtain gamepad name");
::SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "Game controller name: %s", name);
}
void GameController::close() noexcept {
m_gamepad.reset();
closeHaptic();
}
void GameController::startRumble() noexcept {
if (m_hapticRumbleSupported && !::SDL_PlayHapticRumble(m_haptic.get(), 1.0, 1000))
::SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Unable to start haptic rumble: %s", ::SDL_GetError());
const auto success = ::SDL_RumbleGamepad(m_gamepad.get(), 0xFFFF, 0x0000, 1000);
Wrapper::maybeThrowException(success, "Unable to start haptic rumble");
}
void GameController::stopRumble() noexcept {
if (m_hapticRumbleSupported && !::SDL_StopHapticRumble(m_haptic.get()))
::SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Unable to stop haptic rumble: %s", ::SDL_GetError());
}
}