From 4d1380decb91c22d86ed2af2cd13244fc68b162d Mon Sep 17 00:00:00 2001 From: "Herman S." <429230+has207@users.noreply.github.com> Date: Sat, 30 Aug 2025 17:12:45 +0900 Subject: [PATCH] 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. --- src/xenia/app/emulator_window.cc | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/xenia/app/emulator_window.cc b/src/xenia/app/emulator_window.cc index 1828ebe92..017cc4165 100644 --- a/src/xenia/app/emulator_window.cc +++ b/src/xenia/app/emulator_window.cc @@ -1896,19 +1896,26 @@ void EmulatorWindow::GamepadHotKeys() { if (input_sys) { while (true) { - auto input_lock = input_sys->lock(); + // Collect controller states while holding the lock + std::array, XUserMaxUserCount> + controller_states; + { + auto input_lock = input_sys->lock(); + for (uint32_t user_index = 0; user_index < XUserMaxUserCount; + ++user_index) { + X_RESULT result = input_sys->GetState( + 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 + // Process hotkeys without holding the lock for (uint32_t user_index = 0; user_index < XUserMaxUserCount; ++user_index) { - X_RESULT result = input_sys->GetState( - user_index, X_INPUT_FLAG::X_INPUT_FLAG_GAMEPAD, &state); - - // Release the lock before processing the hotkey - input_lock.mutex()->unlock(); - - // Check if the controller is connected - if (result == X_ERROR_SUCCESS) { - if (ProcessControllerHotkey(state.gamepad.buttons).rumble) { + if (controller_states[user_index].first) { + if (ProcessControllerHotkey( + controller_states[user_index].second.gamepad.buttons) + .rumble) { // Enable Vibration VibrateController(input_sys, user_index, true);