From 7b3f5845d28fdf245967b930452d392458fd8535 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Thu, 3 Sep 2020 11:07:57 -0400 Subject: sdl_impl: Erase the SDLJoystick entry after removing a controller Previously, disconnecting a controller still leaves a null SDLJoystick entry within the vector of SDLJoysticks mapped by GUID. When a DirectInput device of the same GUID is reconnected, it adds that device to a new port causing non-detectable input. Furthermore, opening the "Configure" menu would cause yuzu to crash since it first tries to resolve the name of a null SDLJoystick entry that was not removed. Resolve this by properly erasing the SDLJoystick entry from the vector. --- src/input_common/sdl/sdl_impl.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index 8c2cef35d..9c3035920 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp @@ -273,21 +273,19 @@ void SDLState::InitJoystick(int joystick_index) { void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) { const std::string guid = GetGUID(sdl_joystick); - std::shared_ptr found_joystick; - { - std::lock_guard lock{joystick_map_mutex}; - // This call to guid is safe since the joystick is guaranteed to be in the map - const auto& joystick_guid_list = joystick_map[guid]; - const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), - [&sdl_joystick](const auto& joystick) { - return joystick->GetSDLJoystick() == sdl_joystick; - }); - found_joystick = *joystick_it; - } - - // Destruct SDL_Joystick outside the lock guard because SDL can internally call the - // event callback which locks the mutex again. - found_joystick->SetSDLJoystick(nullptr, nullptr); + std::lock_guard lock{joystick_map_mutex}; + auto& joystick_guid_list = joystick_map[guid]; + auto joystick_it = std::find_if( + joystick_guid_list.begin(), joystick_guid_list.end(), + [&sdl_joystick](auto& joystick) { return joystick->GetSDLJoystick() == sdl_joystick; }); + + if (joystick_it != joystick_guid_list.end()) { + (*joystick_it)->SetSDLJoystick(nullptr, nullptr); + joystick_guid_list.erase(joystick_it); + if (joystick_guid_list.empty()) { + joystick_map.erase(guid); + } + } } void SDLState::HandleGameControllerEvent(const SDL_Event& event) { -- cgit v1.2.3