Use separate class for SDL event signals so that i can work with the SDL window event loop

This commit is contained in:
rainmakerv3 2025-06-24 17:55:56 +08:00
parent 5430ca00fe
commit b74eb796fe
7 changed files with 231 additions and 142 deletions

View File

@ -1068,6 +1068,8 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/gui_settings.h src/qt_gui/gui_settings.h
src/qt_gui/settings.cpp src/qt_gui/settings.cpp
src/qt_gui/settings.h src/qt_gui/settings.h
src/qt_gui/sdl_event_wrapper.cpp
src/qt_gui/sdl_event_wrapper.h
${EMULATOR} ${EMULATOR}
${RESOURCE_FILES} ${RESOURCE_FILES}
${TRANSLATIONS} ${TRANSLATIONS}

View File

@ -10,17 +10,21 @@
#include "control_settings.h" #include "control_settings.h"
#include "ui_control_settings.h" #include "ui_control_settings.h"
ControlSettings::ControlSettings(std::shared_ptr<GameInfoClass> game_info_get, QWidget* parent) ControlSettings::ControlSettings(std::shared_ptr<GameInfoClass> game_info_get, bool isGameRunning,
: QDialog(parent), m_game_info(game_info_get), ui(new Ui::ControlSettings) { QWidget* parent)
: QDialog(parent), m_game_info(game_info_get), GameRunning(isGameRunning),
ui(new Ui::ControlSettings) {
ui->setupUi(this); ui->setupUi(this);
if (!GameRunning) {
SDL_InitSubSystem(SDL_INIT_GAMEPAD); SDL_InitSubSystem(SDL_INIT_GAMEPAD);
SDL_InitSubSystem(SDL_INIT_EVENTS); SDL_InitSubSystem(SDL_INIT_EVENTS);
} else {
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
}
CheckGamePad(); CheckGamePad();
QFuture<void> future = QtConcurrent::run(&ControlSettings::pollSDLEvents, this);
AddBoxItems(); AddBoxItems();
SetUIValuestoMappings(); SetUIValuestoMappings();
UpdateLightbarColor(); UpdateLightbarColor();
@ -113,6 +117,14 @@ ControlSettings::ControlSettings(std::shared_ptr<GameInfoClass> game_info_get, Q
[this]() { CheckMapping(MappingButton); }); [this]() { CheckMapping(MappingButton); });
connect(this, &ControlSettings::AxisChanged, this, connect(this, &ControlSettings::AxisChanged, this,
[this]() { ConnectAxisInputs(MappingButton); }); [this]() { ConnectAxisInputs(MappingButton); });
RemapWrapper = SdlEventWrapper::Wrapper::GetInstance();
SdlEventWrapper::Wrapper::wrapperActive = true;
QObject::connect(RemapWrapper, &SdlEventWrapper::Wrapper::SDLEvent, this,
&ControlSettings::processSDLEvents);
if (!GameRunning)
QFuture<void> future = QtConcurrent::run(&ControlSettings::pollSDLEvents, this);
} }
void ControlSettings::SaveControllerConfig(bool CloseOnSave) { void ControlSettings::SaveControllerConfig(bool CloseOnSave) {
@ -621,9 +633,12 @@ void ControlSettings::UpdateLightbarColor() {
} }
void ControlSettings::CheckGamePad() { void ControlSettings::CheckGamePad() {
if (m_gamepad) { if (GameRunning)
SDL_CloseGamepad(m_gamepad); return;
m_gamepad = nullptr;
if (gamepad) {
SDL_CloseGamepad(gamepad);
gamepad = nullptr;
} }
int gamepad_count; int gamepad_count;
@ -641,9 +656,9 @@ void ControlSettings::CheckGamePad() {
} }
LOG_INFO(Input, "Got {} gamepads. Opening the first one.", gamepad_count); LOG_INFO(Input, "Got {} gamepads. Opening the first one.", gamepad_count);
m_gamepad = SDL_OpenGamepad(gamepads[0]); gamepad = SDL_OpenGamepad(gamepads[0]);
if (!m_gamepad) { if (!gamepad) {
LOG_ERROR(Input, "Failed to open gamepad 0: {}", SDL_GetError()); LOG_ERROR(Input, "Failed to open gamepad 0: {}", SDL_GetError());
SDL_free(gamepads); SDL_free(gamepads);
return; return;
@ -697,7 +712,6 @@ void ControlSettings::StartTimer(QPushButton*& button, bool isButton) {
MappingTimer = 3; MappingTimer = 3;
isButton ? EnableButtonMapping = true : EnableAxisMapping = true; isButton ? EnableButtonMapping = true : EnableAxisMapping = true;
MappingCompleted = false; MappingCompleted = false;
triggerWasPressed = false;
mapping = button->text(); mapping = button->text();
DisableMappingButtons(); DisableMappingButtons();
@ -743,8 +757,8 @@ void ControlSettings::SetMapping(QString input) {
mapping = input; mapping = input;
MappingCompleted = true; MappingCompleted = true;
if (EnableAxisMapping) { if (EnableAxisMapping) {
emit AxisChanged();
emit PushGamepadEvent(); emit PushGamepadEvent();
emit AxisChanged();
} }
} }
@ -760,27 +774,28 @@ bool ControlSettings::eventFilter(QObject* obj, QEvent* event) {
return QDialog::eventFilter(obj, event); return QDialog::eventFilter(obj, event);
} }
void ControlSettings::pollSDLEvents() { void ControlSettings::processSDLEvents(int Type, int Input, int Value) {
SDL_Event event; if (Type == SDL_EVENT_QUIT) {
SdlEventWrapper::Wrapper::wrapperActive = false;
while (isRunning) { if (gamepad)
if (!SDL_WaitEvent(&event)) { SDL_CloseGamepad(gamepad);
return; if (!GameRunning) {
}
if (event.type == SDL_EVENT_QUIT) {
isRunning = false;
SDL_QuitSubSystem(SDL_INIT_GAMEPAD); SDL_QuitSubSystem(SDL_INIT_GAMEPAD);
SDL_QuitSubSystem(SDL_INIT_EVENTS); SDL_QuitSubSystem(SDL_INIT_EVENTS);
SDL_Quit(); SDL_Quit();
} else {
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "0");
}
} }
if (event.type == SDL_EVENT_GAMEPAD_ADDED) if (Type == SDL_EVENT_GAMEPAD_ADDED) {
if (!GameRunning)
CheckGamePad(); CheckGamePad();
}
if (EnableButtonMapping) { if (EnableButtonMapping) {
if (event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) { if (Type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) {
switch (event.gbutton.button) { switch (Input) {
case SDL_GAMEPAD_BUTTON_SOUTH: case SDL_GAMEPAD_BUTTON_SOUTH:
pressedButtons.insert("cross"); pressedButtons.insert("cross");
break; break;
@ -840,42 +855,28 @@ void ControlSettings::pollSDLEvents() {
} }
} }
if (event.type == SDL_EVENT_GAMEPAD_BUTTON_UP) { if (Type == SDL_EVENT_GAMEPAD_AXIS_MOTION) {
emit PushGamepadEvent();
}
if (event.type == SDL_EVENT_GAMEPAD_AXIS_MOTION) {
// SDL trigger axis values range from 0 to 32000, set mapping on half movement // SDL trigger axis values range from 0 to 32000, set mapping on half movement
// Set zone for trigger release signal arbitrarily at 5000 // Set zone for trigger release signal arbitrarily at 5000
switch (event.gaxis.axis) { if (Value > 16000) {
switch (Input) {
case SDL_GAMEPAD_AXIS_LEFT_TRIGGER: case SDL_GAMEPAD_AXIS_LEFT_TRIGGER:
if (event.gaxis.value > 16000) {
pressedButtons.insert("l2"); pressedButtons.insert("l2");
triggerWasPressed = true;
} else if (event.gaxis.value < 5000) {
if (triggerWasPressed)
emit PushGamepadEvent();
}
break; break;
case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER: case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER:
if (event.gaxis.value > 16000) {
pressedButtons.insert("r2"); pressedButtons.insert("r2");
triggerWasPressed = true;
} else if (event.gaxis.value < 5000) {
if (triggerWasPressed)
emit PushGamepadEvent();
}
break; break;
default: default:
break; break;
} }
} }
}
} else if (EnableAxisMapping) { } else if (EnableAxisMapping) {
if (event.type == SDL_EVENT_GAMEPAD_AXIS_MOTION) { if (Type == SDL_EVENT_GAMEPAD_AXIS_MOTION) {
// SDL stick axis values range from -32000 to 32000, set mapping on half movement // SDL stick axis values range from -32000 to 32000, set mapping on half movement
if (event.gaxis.value > 16000 || event.gaxis.value < -16000) { if (Value > 16000 || Value < -16000) {
switch (event.gaxis.axis) { switch (Input) {
case SDL_GAMEPAD_AXIS_LEFTX: case SDL_GAMEPAD_AXIS_LEFTX:
SetMapping("axis_left_x"); SetMapping("axis_left_x");
break; break;
@ -895,6 +896,16 @@ void ControlSettings::pollSDLEvents() {
} }
} }
} }
void ControlSettings::pollSDLEvents() {
SDL_Event event;
while (SdlEventWrapper::Wrapper::wrapperActive) {
if (!SDL_WaitEvent(&event)) {
return;
}
SdlEventWrapper::Wrapper::GetInstance()->Wrapper::ProcessEvent(&event);
}
} }
ControlSettings::~ControlSettings() {} ControlSettings::~ControlSettings() {}

View File

@ -1,11 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <QComboBox>
#include <QDialog> #include <QDialog>
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <SDL3/SDL_gamepad.h> #include <SDL3/SDL_gamepad.h>
#include "game_info.h" #include "game_info.h"
#include "sdl_event_wrapper.h"
namespace Ui { namespace Ui {
class ControlSettings; class ControlSettings;
@ -14,7 +14,7 @@ class ControlSettings;
class ControlSettings : public QDialog { class ControlSettings : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
explicit ControlSettings(std::shared_ptr<GameInfoClass> game_info_get, explicit ControlSettings(std::shared_ptr<GameInfoClass> game_info_get, bool GameRunning,
QWidget* parent = nullptr); QWidget* parent = nullptr);
~ControlSettings(); ~ControlSettings();
@ -39,6 +39,7 @@ private:
void SetUIValuestoMappings(); void SetUIValuestoMappings();
void GetGameTitle(); void GetGameTitle();
void CheckGamePad(); void CheckGamePad();
void processSDLEvents(int Type, int Input, int Value);
void pollSDLEvents(); void pollSDLEvents();
void SetMapping(QString input); void SetMapping(QString input);
void DisableMappingButtons(); void DisableMappingButtons();
@ -48,8 +49,7 @@ private:
QList<QPushButton*> AxisList; QList<QPushButton*> AxisList;
QSet<QString> pressedButtons; QSet<QString> pressedButtons;
bool isRunning = true; bool GameRunning;
bool triggerWasPressed = false;
bool EnableButtonMapping = false; bool EnableButtonMapping = false;
bool EnableAxisMapping = false; bool EnableAxisMapping = false;
bool MappingCompleted = false; bool MappingCompleted = false;
@ -57,7 +57,8 @@ private:
int MappingTimer; int MappingTimer;
QTimer* timer; QTimer* timer;
QPushButton* MappingButton; QPushButton* MappingButton;
SDL_Gamepad* m_gamepad = nullptr; SDL_Gamepad* gamepad = nullptr;
SdlEventWrapper::Wrapper* RemapWrapper;
const std::vector<std::string> ControllerInputs = { const std::vector<std::string> ControllerInputs = {
"cross", "circle", "square", "triangle", "l1", "cross", "circle", "square", "triangle", "l1",

View File

@ -473,13 +473,8 @@ void MainWindow::CreateConnects() {
}); });
connect(ui->controllerButton, &QPushButton::clicked, this, [this]() { connect(ui->controllerButton, &QPushButton::clicked, this, [this]() {
if (!isGameRunning) { ControlSettings* remapWindow = new ControlSettings(m_game_info, isGameRunning, this);
auto configWindow = new ControlSettings(m_game_info, this); remapWindow->exec();
configWindow->exec();
} else {
QMessageBox::information(this, tr("Remapping not available"),
tr("Cannot remap controller while game is running"));
}
}); });
connect(ui->keyboardButton, &QPushButton::clicked, this, [this]() { connect(ui->keyboardButton, &QPushButton::clicked, this, [this]() {

View File

@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "sdl_event_wrapper.h"
using namespace SdlEventWrapper;
Wrapper* Wrapper::WrapperInstance = nullptr;
bool Wrapper::wrapperActive = false;
Wrapper::Wrapper(QObject* parent) : QObject(parent) {}
Wrapper* Wrapper::GetInstance() {
if (WrapperInstance == nullptr) {
WrapperInstance = new Wrapper();
}
return WrapperInstance;
}
bool Wrapper::ProcessEvent(SDL_Event* event) {
if (!wrapperActive)
return false;
switch (event->type) {
case SDL_EVENT_QUIT:
emit SDLEvent(SDL_EVENT_QUIT, 0, 0);
return true;
case SDL_EVENT_GAMEPAD_ADDED:
emit SDLEvent(SDL_EVENT_GAMEPAD_ADDED, 0, 0);
return true;
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
emit SDLEvent(SDL_EVENT_GAMEPAD_BUTTON_DOWN, event->gbutton.button, 0);
return true;
case SDL_EVENT_GAMEPAD_BUTTON_UP:
emit SDLEvent(SDL_EVENT_GAMEPAD_BUTTON_UP, event->gbutton.button, 0);
return true;
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
emit SDLEvent(SDL_EVENT_GAMEPAD_AXIS_MOTION, event->gaxis.axis, event->gaxis.value);
return true;
default:
return false;
}
}
Wrapper::~Wrapper() {}

View File

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QObject>
#include <SDL3/SDL_events.h>
namespace SdlEventWrapper {
class Wrapper : public QObject {
Q_OBJECT
public:
explicit Wrapper(QObject* parent = nullptr);
~Wrapper();
bool ProcessEvent(SDL_Event* event);
static Wrapper* GetInstance();
static bool wrapperActive;
static Wrapper* WrapperInstance;
signals:
void SDLEvent(int Type, int Input, int Value);
};
} // namespace SdlEventWrapper

View File

@ -20,6 +20,10 @@
#include "sdl_window.h" #include "sdl_window.h"
#include "video_core/renderdoc.h" #include "video_core/renderdoc.h"
#ifdef ENABLE_QT_GUI
#include "qt_gui/sdl_event_wrapper.h"
#endif
#ifdef __APPLE__ #ifdef __APPLE__
#include "SDL3/SDL_metal.h" #include "SDL3/SDL_metal.h"
#endif #endif
@ -340,6 +344,13 @@ void WindowSDL::WaitEvent() {
return; return;
} }
#ifdef ENABLE_QT_GUI
if (SdlEventWrapper::Wrapper::wrapperActive) {
if (SdlEventWrapper::Wrapper::GetInstance()->ProcessEvent(&event))
return;
}
#endif
if (ImGui::Core::ProcessEvent(&event)) { if (ImGui::Core::ProcessEvent(&event)) {
return; return;
} }