Fix hotkey processing locking issue.

Rather than manually release the lock inside the loop, which breaks RAII
and introduces undefined behavior, we separate the controller state gathering
operation from the rumble hotkey processing loop. The lock lifecycle
is now automatically managed by scope.

On a side note, with multiple controllers connected this would probably
have become clear that it's broken sooner but I guess that's not a very
common use case.
This commit is contained in:
Herman S.
2025-08-30 17:12:45 +09:00
committed by Radosław Gliński
parent 765073021a
commit 4d1380decb

View File

@@ -1896,19 +1896,26 @@ void EmulatorWindow::GamepadHotKeys() {
if (input_sys) { if (input_sys) {
while (true) { while (true) {
// Collect controller states while holding the lock
std::array<std::pair<bool, X_INPUT_STATE>, XUserMaxUserCount>
controller_states;
{
auto input_lock = input_sys->lock(); auto input_lock = input_sys->lock();
for (uint32_t user_index = 0; user_index < XUserMaxUserCount; for (uint32_t user_index = 0; user_index < XUserMaxUserCount;
++user_index) { ++user_index) {
X_RESULT result = input_sys->GetState( X_RESULT result = input_sys->GetState(
user_index, X_INPUT_FLAG::X_INPUT_FLAG_GAMEPAD, &state); user_index, X_INPUT_FLAG::X_INPUT_FLAG_GAMEPAD, &state);
controller_states[user_index] = {result == X_ERROR_SUCCESS, state};
}
} // Lock is released here when input_lock goes out of scope
// Release the lock before processing the hotkey // Process hotkeys without holding the lock
input_lock.mutex()->unlock(); for (uint32_t user_index = 0; user_index < XUserMaxUserCount;
++user_index) {
// Check if the controller is connected if (controller_states[user_index].first) {
if (result == X_ERROR_SUCCESS) { if (ProcessControllerHotkey(
if (ProcessControllerHotkey(state.gamepad.buttons).rumble) { controller_states[user_index].second.gamepad.buttons)
.rumble) {
// Enable Vibration // Enable Vibration
VibrateController(input_sys, user_index, true); VibrateController(input_sys, user_index, true);