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/settings.cpp
src/qt_gui/settings.h
src/qt_gui/sdl_event_wrapper.cpp
src/qt_gui/sdl_event_wrapper.h
${EMULATOR}
${RESOURCE_FILES}
${TRANSLATIONS}

View File

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

View File

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

View File

@ -473,13 +473,8 @@ void MainWindow::CreateConnects() {
});
connect(ui->controllerButton, &QPushButton::clicked, this, [this]() {
if (!isGameRunning) {
auto configWindow = new ControlSettings(m_game_info, this);
configWindow->exec();
} else {
QMessageBox::information(this, tr("Remapping not available"),
tr("Cannot remap controller while game is running"));
}
ControlSettings* remapWindow = new ControlSettings(m_game_info, isGameRunning, this);
remapWindow->exec();
});
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 "video_core/renderdoc.h"
#ifdef ENABLE_QT_GUI
#include "qt_gui/sdl_event_wrapper.h"
#endif
#ifdef __APPLE__
#include "SDL3/SDL_metal.h"
#endif
@ -340,6 +344,13 @@ void WindowSDL::WaitEvent() {
return;
}
#ifdef ENABLE_QT_GUI
if (SdlEventWrapper::Wrapper::wrapperActive) {
if (SdlEventWrapper::Wrapper::GetInstance()->ProcessEvent(&event))
return;
}
#endif
if (ImGui::Core::ProcessEvent(&event)) {
return;
}