summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Morph2020-10-21 08:42:11 -0400
committerGravatar Morph2020-10-21 09:41:30 -0400
commit2f852f182a807d828985e08d0b70f1129194fbad (patch)
tree1afa3cd5d81945d081607327cef059219511099c
parentMerge pull request #4811 from lioncash/warn-video (diff)
downloadyuzu-2f852f182a807d828985e08d0b70f1129194fbad.tar.gz
yuzu-2f852f182a807d828985e08d0b70f1129194fbad.tar.xz
yuzu-2f852f182a807d828985e08d0b70f1129194fbad.zip
sdl_impl: Fix controller reconnection issues
It turns out that after a controller is disconnected, there is a chance that events from the previous controller are sent/processed after it has been disconnected. This causes the previously disconnected controller to reappear as connected due to GetSDLJoystickBySDLID() emplacing this controller back to the map. Fix this by only returning an SDLJoystick if and only if it exists in the map.
Diffstat (limited to '')
-rw-r--r--src/input_common/sdl/sdl_impl.cpp169
1 files changed, 84 insertions, 85 deletions
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 9c3035920..10883e2d9 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -155,15 +155,15 @@ public:
155 return sdl_joystick.get(); 155 return sdl_joystick.get();
156 } 156 }
157 157
158 void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
159 sdl_controller.reset(controller);
160 sdl_joystick.reset(joystick);
161 }
162
163 SDL_GameController* GetSDLGameController() const { 158 SDL_GameController* GetSDLGameController() const {
164 return sdl_controller.get(); 159 return sdl_controller.get();
165 } 160 }
166 161
162 void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
163 sdl_joystick.reset(joystick);
164 sdl_controller.reset(controller);
165 }
166
167private: 167private:
168 struct State { 168 struct State {
169 std::unordered_map<int, bool> buttons; 169 std::unordered_map<int, bool> buttons;
@@ -186,69 +186,58 @@ private:
186std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { 186std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
187 std::lock_guard lock{joystick_map_mutex}; 187 std::lock_guard lock{joystick_map_mutex};
188 const auto it = joystick_map.find(guid); 188 const auto it = joystick_map.find(guid);
189
189 if (it != joystick_map.end()) { 190 if (it != joystick_map.end()) {
190 while (it->second.size() <= static_cast<std::size_t>(port)) { 191 while (it->second.size() <= static_cast<std::size_t>(port)) {
191 auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()), 192 auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
192 nullptr, nullptr); 193 nullptr, nullptr);
193 it->second.emplace_back(std::move(joystick)); 194 it->second.emplace_back(std::move(joystick));
194 } 195 }
196
195 return it->second[static_cast<std::size_t>(port)]; 197 return it->second[static_cast<std::size_t>(port)];
196 } 198 }
199
197 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr); 200 auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
201
198 return joystick_map[guid].emplace_back(std::move(joystick)); 202 return joystick_map[guid].emplace_back(std::move(joystick));
199} 203}
200 204
201std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { 205std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
202 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); 206 auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
203 auto sdl_controller = SDL_GameControllerFromInstanceID(sdl_id);
204 const std::string guid = GetGUID(sdl_joystick); 207 const std::string guid = GetGUID(sdl_joystick);
205 208
206 std::lock_guard lock{joystick_map_mutex}; 209 std::lock_guard lock{joystick_map_mutex};
207 const auto map_it = joystick_map.find(guid); 210 const auto map_it = joystick_map.find(guid);
208 if (map_it != joystick_map.end()) {
209 const auto vec_it =
210 std::find_if(map_it->second.begin(), map_it->second.end(),
211 [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
212 return sdl_joystick == joystick->GetSDLJoystick();
213 });
214 if (vec_it != map_it->second.end()) {
215 // This is the common case: There is already an existing SDL_Joystick mapped to a
216 // SDLJoystick. return the SDLJoystick
217 return *vec_it;
218 }
219 211
220 // Search for a SDLJoystick without a mapped SDL_Joystick... 212 if (map_it == joystick_map.end()) {
221 const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(), 213 return nullptr;
222 [](const std::shared_ptr<SDLJoystick>& joystick) { 214 }
223 return joystick->GetSDLJoystick() == nullptr;
224 });
225 if (nullptr_it != map_it->second.end()) {
226 // ... and map it
227 (*nullptr_it)->SetSDLJoystick(sdl_joystick, sdl_controller);
228 return *nullptr_it;
229 }
230 215
231 // There is no SDLJoystick without a mapped SDL_Joystick 216 const auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(),
232 // Create a new SDLJoystick 217 [&sdl_joystick](const auto& joystick) {
233 const int port = static_cast<int>(map_it->second.size()); 218 return joystick->GetSDLJoystick() == sdl_joystick;
234 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_controller); 219 });
235 return map_it->second.emplace_back(std::move(joystick)); 220
221 if (vec_it == map_it->second.end()) {
222 return nullptr;
236 } 223 }
237 224
238 auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_controller); 225 return *vec_it;
239 return joystick_map[guid].emplace_back(std::move(joystick));
240} 226}
241 227
242void SDLState::InitJoystick(int joystick_index) { 228void SDLState::InitJoystick(int joystick_index) {
243 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); 229 SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
244 SDL_GameController* sdl_gamecontroller = nullptr; 230 SDL_GameController* sdl_gamecontroller = nullptr;
231
245 if (SDL_IsGameController(joystick_index)) { 232 if (SDL_IsGameController(joystick_index)) {
246 sdl_gamecontroller = SDL_GameControllerOpen(joystick_index); 233 sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
247 } 234 }
235
248 if (!sdl_joystick) { 236 if (!sdl_joystick) {
249 LOG_ERROR(Input, "Failed to open joystick {}", joystick_index); 237 LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
250 return; 238 return;
251 } 239 }
240
252 const std::string guid = GetGUID(sdl_joystick); 241 const std::string guid = GetGUID(sdl_joystick);
253 242
254 std::lock_guard lock{joystick_map_mutex}; 243 std::lock_guard lock{joystick_map_mutex};
@@ -257,14 +246,17 @@ void SDLState::InitJoystick(int joystick_index) {
257 joystick_map[guid].emplace_back(std::move(joystick)); 246 joystick_map[guid].emplace_back(std::move(joystick));
258 return; 247 return;
259 } 248 }
249
260 auto& joystick_guid_list = joystick_map[guid]; 250 auto& joystick_guid_list = joystick_map[guid];
261 const auto it = std::find_if( 251 const auto joystick_it =
262 joystick_guid_list.begin(), joystick_guid_list.end(), 252 std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
263 [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); }); 253 [](const auto& joystick) { return !joystick->GetSDLJoystick(); });
264 if (it != joystick_guid_list.end()) { 254
265 (*it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller); 255 if (joystick_it != joystick_guid_list.end()) {
256 (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
266 return; 257 return;
267 } 258 }
259
268 const int port = static_cast<int>(joystick_guid_list.size()); 260 const int port = static_cast<int>(joystick_guid_list.size());
269 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller); 261 auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
270 joystick_guid_list.emplace_back(std::move(joystick)); 262 joystick_guid_list.emplace_back(std::move(joystick));
@@ -274,18 +266,14 @@ void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
274 const std::string guid = GetGUID(sdl_joystick); 266 const std::string guid = GetGUID(sdl_joystick);
275 267
276 std::lock_guard lock{joystick_map_mutex}; 268 std::lock_guard lock{joystick_map_mutex};
277 auto& joystick_guid_list = joystick_map[guid]; 269 // This call to guid is safe since the joystick is guaranteed to be in the map
278 auto joystick_it = std::find_if( 270 const auto& joystick_guid_list = joystick_map[guid];
279 joystick_guid_list.begin(), joystick_guid_list.end(), 271 const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
280 [&sdl_joystick](auto& joystick) { return joystick->GetSDLJoystick() == sdl_joystick; }); 272 [&sdl_joystick](const auto& joystick) {
281 273 return joystick->GetSDLJoystick() == sdl_joystick;
282 if (joystick_it != joystick_guid_list.end()) { 274 });
283 (*joystick_it)->SetSDLJoystick(nullptr, nullptr); 275
284 joystick_guid_list.erase(joystick_it); 276 (*joystick_it)->SetSDLJoystick(nullptr, nullptr);
285 if (joystick_guid_list.empty()) {
286 joystick_map.erase(guid);
287 }
288 }
289} 277}
290 278
291void SDLState::HandleGameControllerEvent(const SDL_Event& event) { 279void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
@@ -720,8 +708,7 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
720 std::vector<Common::ParamPackage> devices; 708 std::vector<Common::ParamPackage> devices;
721 for (const auto& [key, value] : joystick_map) { 709 for (const auto& [key, value] : joystick_map) {
722 for (const auto& joystick : value) { 710 for (const auto& joystick : value) {
723 auto* joy = joystick->GetSDLJoystick(); 711 if (auto* const controller = joystick->GetSDLGameController()) {
724 if (auto* controller = joystick->GetSDLGameController()) {
725 std::string name = 712 std::string name =
726 fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort()); 713 fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
727 devices.emplace_back(Common::ParamPackage{ 714 devices.emplace_back(Common::ParamPackage{
@@ -730,7 +717,7 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
730 {"guid", joystick->GetGUID()}, 717 {"guid", joystick->GetGUID()},
731 {"port", std::to_string(joystick->GetPort())}, 718 {"port", std::to_string(joystick->GetPort())},
732 }); 719 });
733 } else if (joy) { 720 } else if (auto* const joy = joystick->GetSDLJoystick()) {
734 std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort()); 721 std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort());
735 devices.emplace_back(Common::ParamPackage{ 722 devices.emplace_back(Common::ParamPackage{
736 {"class", "sdl"}, 723 {"class", "sdl"},
@@ -797,21 +784,27 @@ Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s
797Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { 784Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
798 switch (event.type) { 785 switch (event.type) {
799 case SDL_JOYAXISMOTION: { 786 case SDL_JOYAXISMOTION: {
800 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 787 if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
801 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 788 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
802 static_cast<s32>(event.jaxis.axis), 789 static_cast<s32>(event.jaxis.axis),
803 event.jaxis.value); 790 event.jaxis.value);
791 }
792 break;
804 } 793 }
805 case SDL_JOYBUTTONUP: { 794 case SDL_JOYBUTTONUP: {
806 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); 795 if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) {
807 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 796 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
808 static_cast<s32>(event.jbutton.button)); 797 static_cast<s32>(event.jbutton.button));
798 }
799 break;
809 } 800 }
810 case SDL_JOYHATMOTION: { 801 case SDL_JOYHATMOTION: {
811 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); 802 if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) {
812 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 803 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
813 static_cast<s32>(event.jhat.hat), 804 static_cast<s32>(event.jhat.hat),
814 static_cast<s32>(event.jhat.value)); 805 static_cast<s32>(event.jhat.value));
806 }
807 break;
815 } 808 }
816 } 809 }
817 return {}; 810 return {};
@@ -820,21 +813,27 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve
820Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) { 813Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) {
821 switch (event.type) { 814 switch (event.type) {
822 case SDL_JOYAXISMOTION: { 815 case SDL_JOYAXISMOTION: {
823 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 816 if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
824 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 817 return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
825 static_cast<s32>(event.jaxis.axis), 818 static_cast<s32>(event.jaxis.axis),
826 event.jaxis.value); 819 event.jaxis.value);
820 }
821 break;
827 } 822 }
828 case SDL_JOYBUTTONUP: { 823 case SDL_JOYBUTTONUP: {
829 const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which); 824 if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) {
830 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 825 return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
831 static_cast<s32>(event.jbutton.button)); 826 static_cast<s32>(event.jbutton.button));
827 }
828 break;
832 } 829 }
833 case SDL_JOYHATMOTION: { 830 case SDL_JOYHATMOTION: {
834 const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which); 831 if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) {
835 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), 832 return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
836 static_cast<s32>(event.jhat.hat), 833 static_cast<s32>(event.jhat.hat),
837 static_cast<s32>(event.jhat.value)); 834 static_cast<s32>(event.jhat.value));
835 }
836 break;
838 } 837 }
839 } 838 }
840 return {}; 839 return {};
@@ -1062,9 +1061,8 @@ public:
1062 // Simplify controller config by testing if game controller support is enabled. 1061 // Simplify controller config by testing if game controller support is enabled.
1063 if (event.type == SDL_JOYAXISMOTION) { 1062 if (event.type == SDL_JOYAXISMOTION) {
1064 const auto axis = event.jaxis.axis; 1063 const auto axis = event.jaxis.axis;
1065 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 1064 if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
1066 auto* const controller = joystick->GetSDLGameController(); 1065 auto* const controller = joystick->GetSDLGameController()) {
1067 if (controller) {
1068 const auto axis_left_x = 1066 const auto axis_left_x =
1069 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) 1067 SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
1070 .value.axis; 1068 .value.axis;
@@ -1098,12 +1096,13 @@ public:
1098 } 1096 }
1099 1097
1100 if (analog_x_axis != -1 && analog_y_axis != -1) { 1098 if (analog_x_axis != -1 && analog_y_axis != -1) {
1101 const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which); 1099 if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
1102 auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), 1100 auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
1103 analog_x_axis, analog_y_axis); 1101 analog_x_axis, analog_y_axis);
1104 analog_x_axis = -1; 1102 analog_x_axis = -1;
1105 analog_y_axis = -1; 1103 analog_y_axis = -1;
1106 return params; 1104 return params;
1105 }
1107 } 1106 }
1108 return {}; 1107 return {};
1109 } 1108 }