diff options
Diffstat (limited to 'src/input_common/sdl/sdl_impl.cpp')
| -rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 169 |
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 | |||
| 167 | private: | 167 | private: |
| 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: | |||
| 186 | std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { | 186 | std::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 | ||
| 201 | std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { | 205 | std::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 | ||
| 242 | void SDLState::InitJoystick(int joystick_index) { | 228 | void 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 | ||
| 291 | void SDLState::HandleGameControllerEvent(const SDL_Event& event) { | 279 | void 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 | |||
| 797 | Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { | 784 | Common::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 | |||
| 820 | Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) { | 813 | Common::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 | } |