make input system thread-safe

This commit is contained in:
Arisotura
2025-08-15 15:48:13 +02:00
parent 9120d19411
commit 8a6fa3a9ef
6 changed files with 86 additions and 28 deletions

View File

@ -155,6 +155,7 @@ public:
void setJoystick(int id);
int getJoystickID() { return joystickID; }
SDL_Joystick* getJoystick() { return joystick; }
std::shared_ptr<SDL_mutex> getJoyMutex() { return joyMutex; }
void touchScreen(int x, int y);
void releaseScreen();
@ -359,6 +360,9 @@ private:
bool hasRumble = false;
bool isRumbling = false;
static std::shared_ptr<SDL_mutex> joyMutexGlobal;
std::shared_ptr<SDL_mutex> joyMutex;
melonDS::u32 keyInputMask, joyInputMask;
melonDS::u32 keyHotkeyMask, joyHotkeyMask;
melonDS::u32 hotkeyMask, lastHotkeyMask;

View File

@ -69,9 +69,18 @@ const char* EmuInstance::hotkeyNames[HK_MAX] =
"HK_GuitarGripBlue"
};
std::shared_ptr<SDL_mutex> EmuInstance::joyMutexGlobal = nullptr;
void EmuInstance::inputInit()
{
if (!joyMutexGlobal)
{
SDL_mutex* mutex = SDL_CreateMutex();
joyMutexGlobal = std::shared_ptr<SDL_mutex>(mutex, SDL_DestroyMutex);
}
joyMutex = joyMutexGlobal;
keyInputMask = 0xFFF;
joyInputMask = 0xFFF;
inputMask = 0xFFF;
@ -91,16 +100,21 @@ void EmuInstance::inputInit()
hasAccelerometer = false;
hasGyroscope = false;
isRumbling = false;
inputLoadConfig();
}
void EmuInstance::inputDeInit()
{
SDL_LockMutex(joyMutex.get());
closeJoystick();
SDL_UnlockMutex(joyMutex.get());
}
void EmuInstance::inputLoadConfig()
{
SDL_LockMutex(joyMutex.get());
Config::Table keycfg = localCfg.GetTable("Keyboard");
Config::Table joycfg = localCfg.GetTable("Joystick");
@ -117,35 +131,47 @@ void EmuInstance::inputLoadConfig()
}
setJoystick(localCfg.GetInt("JoystickID"));
SDL_UnlockMutex(joyMutex.get());
}
void EmuInstance::inputRumbleStart(melonDS::u32 len_ms)
{
SDL_LockMutex(joyMutex.get());
if (controller && hasRumble && !isRumbling)
{
SDL_GameControllerRumble(controller, 0xFFFF, 0xFFFF, len_ms);
isRumbling = true;
}
SDL_UnlockMutex(joyMutex.get());
}
void EmuInstance::inputRumbleStop()
{
SDL_LockMutex(joyMutex.get());
if (controller && hasRumble && isRumbling)
{
SDL_GameControllerRumble(controller, 0, 0, 0);
isRumbling = false;
}
SDL_UnlockMutex(joyMutex.get());
}
float EmuInstance::inputMotionQuery(melonDS::Platform::MotionQueryType type)
{
float values[3];
SDL_LockMutex(joyMutex.get());
if (type <= melonDS::Platform::MotionAccelerationZ)
{
if (controller && hasAccelerometer)
{
if (SDL_GameControllerGetSensorData(controller, SDL_SENSOR_ACCEL, values, 3) == 0)
{
// Map values from DS console orientation to SDL controller orientation.
SDL_UnlockMutex(joyMutex.get());
switch (type)
{
case melonDS::Platform::MotionAccelerationX:
@ -157,12 +183,15 @@ float EmuInstance::inputMotionQuery(melonDS::Platform::MotionQueryType type)
}
}
}
}
else if (type <= melonDS::Platform::MotionRotationZ)
{
if (controller && hasGyroscope)
{
if (SDL_GameControllerGetSensorData(controller, SDL_SENSOR_GYRO, values, 3) == 0)
{
// Map values from DS console orientation to SDL controller orientation.
SDL_UnlockMutex(joyMutex.get());
switch (type)
{
case melonDS::Platform::MotionRotationX:
@ -174,6 +203,8 @@ float EmuInstance::inputMotionQuery(melonDS::Platform::MotionQueryType type)
}
}
}
}
SDL_UnlockMutex(joyMutex.get());
if (type == melonDS::Platform::MotionAccelerationZ)
return SDL_STANDARD_GRAVITY;
return 0.0f;
@ -182,8 +213,10 @@ float EmuInstance::inputMotionQuery(melonDS::Platform::MotionQueryType type)
void EmuInstance::setJoystick(int id)
{
SDL_LockMutex(joyMutex.get());
joystickID = id;
openJoystick();
SDL_UnlockMutex(joyMutex.get());
}
void EmuInstance::openJoystick()
@ -381,6 +414,7 @@ bool EmuInstance::joystickButtonDown(int val)
void EmuInstance::inputProcess()
{
SDL_LockMutex(joyMutex.get());
SDL_JoystickUpdate();
if (joystick)
@ -418,6 +452,7 @@ void EmuInstance::inputProcess()
hotkeyPress = hotkeyMask & ~lastHotkeyMask;
hotkeyRelease = lastHotkeyMask & ~hotkeyMask;
lastHotkeyMask = hotkeyMask;
SDL_UnlockMutex(joyMutex.get());
}
void EmuInstance::touchScreen(int x, int y)

View File

@ -153,7 +153,9 @@ void EmuThread::run()
while (emuStatus != emuStatus_Exit)
{
if (emuInstance->instanceID == 0)
MPInterface::Get().Process();
emuInstance->inputProcess();
if (emuInstance->hotkeyPressed(HK_FrameLimitToggle)) emit windowLimitFPSChange();

View File

@ -252,3 +252,8 @@ SDL_Joystick* InputConfigDialog::getJoystick()
{
return emuInstance->getJoystick();
}
std::shared_ptr<SDL_mutex> InputConfigDialog::getJoyMutex()
{
return emuInstance->getJoyMutex();
}

View File

@ -105,6 +105,7 @@ public:
~InputConfigDialog();
SDL_Joystick* getJoystick();
std::shared_ptr<SDL_mutex> getJoyMutex();
static InputConfigDialog* currentDlg;
static InputConfigDialog* openDlg(QWidget* parent)

View File

@ -220,7 +220,7 @@ protected:
QPushButton::focusOutEvent(event);
}
void timerEvent(QTimerEvent* event) override
void checkJoystick()
{
SDL_Joystick* joy = parentDialog->getJoystick();
if (!joy) { click(); return; }
@ -287,6 +287,14 @@ protected:
}
}
void timerEvent(QTimerEvent* event) override
{
auto mutex = parentDialog->getJoyMutex();
SDL_LockMutex(mutex.get());
checkJoystick();
SDL_UnlockMutex(mutex.get());
}
bool focusNextPrevChild(bool next) override { return false; }
private slots:
@ -299,6 +307,8 @@ private slots:
memset(axesRest, 0, sizeof(axesRest));
auto mutex = parentDialog->getJoyMutex();
SDL_LockMutex(mutex.get());
SDL_Joystick* joy = parentDialog->getJoystick();
if (joy && SDL_JoystickGetAttached(joy))
{
@ -309,6 +319,7 @@ private slots:
axesRest[a] = SDL_JoystickGetAxis(joy, a);
}
}
SDL_UnlockMutex(mutex.get());
}
else
{