WIP SDL3 compatibility

This commit is contained in:
Cameron Gutman
2025-01-31 01:13:17 -06:00
parent 5290305944
commit 231a67946d
34 changed files with 772 additions and 497 deletions

View File

@@ -37,7 +37,7 @@ void SdlGamepadKeyNavigation::enable()
// arrival events. Additionally, there's a race condition between
// our QML objects being destroyed and SDL being deinitialized that
// this solves too.
if (SDLC_FAILURE(SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER))) {
if (SDLC_FAILURE(SDL_InitSubSystem(SDL_INIT_GAMEPAD))) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) failed: %s",
SDL_GetError());
@@ -52,18 +52,18 @@ void SdlGamepadKeyNavigation::enable()
// overlapping lifetimes of SdlGamepadKeyNavigation instances, so we
// will attach ourselves.
SDL_PumpEvents();
SDL_FlushEvent(SDL_CONTROLLERDEVICEADDED);
SDL_FlushEvent(SDL_EVENT_GAMEPAD_ADDED);
// Open all currently attached game controllers
int numJoysticks = SDL_NumJoysticks();
for (int i = 0; i < numJoysticks; i++) {
if (SDL_IsGameController(i)) {
SDL_GameController* gc = SDL_GameControllerOpen(i);
if (gc != nullptr) {
m_Gamepads.append(gc);
}
int numGamepads = 0;
SDL_JoystickID* gamepads = SDL_GetGamepads(&numGamepads);
for (int i = 0; i < numGamepads; i++) {
SDL_Gamepad * gc = SDL_OpenGamepad(i);
if (gc != nullptr) {
m_Gamepads.append(gc);
}
}
SDL_free(gamepads);
m_Enabled = true;
@@ -82,11 +82,11 @@ void SdlGamepadKeyNavigation::disable()
Q_ASSERT(!m_PollingTimer->isActive());
while (!m_Gamepads.isEmpty()) {
SDL_GameControllerClose(m_Gamepads[0]);
SDL_CloseGamepad(m_Gamepads[0]);
m_Gamepads.removeAt(0);
}
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
SDL_QuitSubSystem(SDL_INIT_GAMEPAD);
}
void SdlGamepadKeyNavigation::notifyWindowFocus(bool hasFocus)
@@ -103,47 +103,47 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
// stale input data from the stream session (like the quit combo).
if (m_FirstPoll) {
SDL_PumpEvents();
SDL_FlushEvent(SDL_CONTROLLERBUTTONDOWN);
SDL_FlushEvent(SDL_CONTROLLERBUTTONUP);
SDL_FlushEvent(SDL_EVENT_GAMEPAD_BUTTON_DOWN);
SDL_FlushEvent(SDL_EVENT_GAMEPAD_BUTTON_UP);
m_FirstPoll = false;
}
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
case SDL_EVENT_QUIT :
// SDL may send us a quit event since we initialize
// the video subsystem on startup. If we get one,
// forward it on for Qt to take care of.
QCoreApplication::instance()->quit();
break;
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
case SDL_EVENT_GAMEPAD_BUTTON_DOWN :
case SDL_EVENT_GAMEPAD_BUTTON_UP :
{
QEvent::Type type =
event.type == SDL_CONTROLLERBUTTONDOWN ?
event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN ?
QEvent::Type::KeyPress : QEvent::Type::KeyRelease;
// Swap face buttons if needed
if (m_Prefs->swapFaceButtons) {
switch (event.cbutton.button) {
case SDL_CONTROLLER_BUTTON_A:
event.cbutton.button = SDL_CONTROLLER_BUTTON_B;
switch (event.gbutton.button) {
case SDL_GAMEPAD_BUTTON_SOUTH :
event.gbutton.button = SDL_GAMEPAD_BUTTON_EAST;
break;
case SDL_CONTROLLER_BUTTON_B:
event.cbutton.button = SDL_CONTROLLER_BUTTON_A;
case SDL_GAMEPAD_BUTTON_EAST :
event.gbutton.button = SDL_GAMEPAD_BUTTON_SOUTH;
break;
case SDL_CONTROLLER_BUTTON_X:
event.cbutton.button = SDL_CONTROLLER_BUTTON_Y;
case SDL_GAMEPAD_BUTTON_WEST :
event.gbutton.button = SDL_GAMEPAD_BUTTON_NORTH;
break;
case SDL_CONTROLLER_BUTTON_Y:
event.cbutton.button = SDL_CONTROLLER_BUTTON_X;
case SDL_GAMEPAD_BUTTON_NORTH :
event.gbutton.button = SDL_GAMEPAD_BUTTON_WEST;
break;
}
}
switch (event.cbutton.button) {
case SDL_CONTROLLER_BUTTON_DPAD_UP:
switch (event.gbutton.button) {
case SDL_GAMEPAD_BUTTON_DPAD_UP :
if (m_UiNavMode) {
// Back-tab
sendKey(type, Qt::Key_Tab, Qt::ShiftModifier);
@@ -152,7 +152,7 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
sendKey(type, Qt::Key_Up);
}
break;
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
case SDL_GAMEPAD_BUTTON_DPAD_DOWN :
if (m_UiNavMode) {
sendKey(type, Qt::Key_Tab);
}
@@ -160,13 +160,13 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
sendKey(type, Qt::Key_Down);
}
break;
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
case SDL_GAMEPAD_BUTTON_DPAD_LEFT :
sendKey(type, Qt::Key_Left);
break;
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT :
sendKey(type, Qt::Key_Right);
break;
case SDL_CONTROLLER_BUTTON_A:
case SDL_GAMEPAD_BUTTON_SOUTH :
if (m_UiNavMode) {
sendKey(type, Qt::Key_Space);
}
@@ -174,14 +174,14 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
sendKey(type, Qt::Key_Return);
}
break;
case SDL_CONTROLLER_BUTTON_B:
case SDL_GAMEPAD_BUTTON_EAST :
sendKey(type, Qt::Key_Escape);
break;
case SDL_CONTROLLER_BUTTON_X:
case SDL_GAMEPAD_BUTTON_WEST :
sendKey(type, Qt::Key_Menu);
break;
case SDL_CONTROLLER_BUTTON_Y:
case SDL_CONTROLLER_BUTTON_START:
case SDL_GAMEPAD_BUTTON_NORTH :
case SDL_GAMEPAD_BUTTON_START :
// HACK: We use this keycode to inform main.qml
// to show the settings when Key_Menu is handled
// by the control in focus.
@@ -192,11 +192,18 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
}
break;
}
case SDL_CONTROLLERDEVICEADDED:
SDL_GameController* gc = SDL_GameControllerOpen(event.cdevice.which);
case SDL_EVENT_GAMEPAD_ADDED :
#if SDL_VERSION_ATLEAST(3, 0, 0)
SDL_Gamepad* gc = SDL_OpenGamepad(event.gdevice.which);
if (gc != nullptr) {
SDL_assert(!m_Gamepads.contains(gc));
m_Gamepads.append(gc);
}
#else
SDL_Gamepad* gc = SDL_GameControllerOpen(event.cdevice.which);
if (gc != nullptr) {
// SDL_CONTROLLERDEVICEADDED can be reported multiple times for the same
// gamepad in rare cases, because SDL doesn't fixup the device index in
// gamepad in rare cases, because SDL2 doesn't fixup the device index in
// the SDL_CONTROLLERDEVICEADDED event if an unopened gamepad disappears
// before we've processed the add event.
if (!m_Gamepads.contains(gc)) {
@@ -204,17 +211,18 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
}
else {
// We already have this game controller open
SDL_GameControllerClose(gc);
SDL_CloseGamepad(gc);
}
}
#endif
break;
}
}
// Handle analog sticks by polling
for (auto gc : m_Gamepads) {
short leftX = SDL_GameControllerGetAxis(gc, SDL_CONTROLLER_AXIS_LEFTX);
short leftY = SDL_GameControllerGetAxis(gc, SDL_CONTROLLER_AXIS_LEFTY);
short leftX = SDL_GetGamepadAxis(gc, SDL_GAMEPAD_AXIS_LEFTX);
short leftY = SDL_GetGamepadAxis(gc, SDL_GAMEPAD_AXIS_LEFTY);
if (SDL_GetTicks() - m_LastAxisNavigationEventTime < AXIS_NAVIGATION_REPEAT_DELAY) {
// Do nothing
}
@@ -290,12 +298,6 @@ int SdlGamepadKeyNavigation::getConnectedGamepads()
Q_ASSERT(m_Enabled);
int count = 0;
int numJoysticks = SDL_NumJoysticks();
for (int i = 0; i < numJoysticks; i++) {
if (SDL_IsGameController(i)) {
count++;
}
}
SDL_free(SDL_GetGamepads(&count));
return count;
}

View File

@@ -37,7 +37,7 @@ private slots:
private:
StreamingPreferences* m_Prefs;
QTimer* m_PollingTimer;
QList<SDL_GameController*> m_Gamepads;
QList<SDL_Gamepad*> m_Gamepads;
bool m_Enabled;
bool m_UiNavMode;
bool m_FirstPoll;