Merge pull request #4816 from Morph1984/controller-disconnect-fix
sdl_impl: Fix controller reconnection issues
This commit is contained in:
commit
6f6d83befa
|
@ -155,15 +155,15 @@ public:
|
||||||
return sdl_joystick.get();
|
return sdl_joystick.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
|
|
||||||
sdl_controller.reset(controller);
|
|
||||||
sdl_joystick.reset(joystick);
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_GameController* GetSDLGameController() const {
|
SDL_GameController* GetSDLGameController() const {
|
||||||
return sdl_controller.get();
|
return sdl_controller.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
|
||||||
|
sdl_joystick.reset(joystick);
|
||||||
|
sdl_controller.reset(controller);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct State {
|
struct State {
|
||||||
std::unordered_map<int, bool> buttons;
|
std::unordered_map<int, bool> buttons;
|
||||||
|
@ -186,69 +186,58 @@ private:
|
||||||
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
|
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
|
||||||
std::lock_guard lock{joystick_map_mutex};
|
std::lock_guard lock{joystick_map_mutex};
|
||||||
const auto it = joystick_map.find(guid);
|
const auto it = joystick_map.find(guid);
|
||||||
|
|
||||||
if (it != joystick_map.end()) {
|
if (it != joystick_map.end()) {
|
||||||
while (it->second.size() <= static_cast<std::size_t>(port)) {
|
while (it->second.size() <= static_cast<std::size_t>(port)) {
|
||||||
auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
|
auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
|
||||||
nullptr, nullptr);
|
nullptr, nullptr);
|
||||||
it->second.emplace_back(std::move(joystick));
|
it->second.emplace_back(std::move(joystick));
|
||||||
}
|
}
|
||||||
|
|
||||||
return it->second[static_cast<std::size_t>(port)];
|
return it->second[static_cast<std::size_t>(port)];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
|
auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
|
||||||
|
|
||||||
return joystick_map[guid].emplace_back(std::move(joystick));
|
return joystick_map[guid].emplace_back(std::move(joystick));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
|
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
|
||||||
auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
|
auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
|
||||||
auto sdl_controller = SDL_GameControllerFromInstanceID(sdl_id);
|
|
||||||
const std::string guid = GetGUID(sdl_joystick);
|
const std::string guid = GetGUID(sdl_joystick);
|
||||||
|
|
||||||
std::lock_guard lock{joystick_map_mutex};
|
std::lock_guard lock{joystick_map_mutex};
|
||||||
const auto map_it = joystick_map.find(guid);
|
const auto map_it = joystick_map.find(guid);
|
||||||
if (map_it != joystick_map.end()) {
|
|
||||||
const auto vec_it =
|
|
||||||
std::find_if(map_it->second.begin(), map_it->second.end(),
|
|
||||||
[&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
|
|
||||||
return sdl_joystick == joystick->GetSDLJoystick();
|
|
||||||
});
|
|
||||||
if (vec_it != map_it->second.end()) {
|
|
||||||
// This is the common case: There is already an existing SDL_Joystick mapped to a
|
|
||||||
// SDLJoystick. return the SDLJoystick
|
|
||||||
return *vec_it;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search for a SDLJoystick without a mapped SDL_Joystick...
|
if (map_it == joystick_map.end()) {
|
||||||
const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(),
|
return nullptr;
|
||||||
[](const std::shared_ptr<SDLJoystick>& joystick) {
|
|
||||||
return joystick->GetSDLJoystick() == nullptr;
|
|
||||||
});
|
|
||||||
if (nullptr_it != map_it->second.end()) {
|
|
||||||
// ... and map it
|
|
||||||
(*nullptr_it)->SetSDLJoystick(sdl_joystick, sdl_controller);
|
|
||||||
return *nullptr_it;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There is no SDLJoystick without a mapped SDL_Joystick
|
|
||||||
// Create a new SDLJoystick
|
|
||||||
const int port = static_cast<int>(map_it->second.size());
|
|
||||||
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_controller);
|
|
||||||
return map_it->second.emplace_back(std::move(joystick));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_controller);
|
const auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(),
|
||||||
return joystick_map[guid].emplace_back(std::move(joystick));
|
[&sdl_joystick](const auto& joystick) {
|
||||||
|
return joystick->GetSDLJoystick() == sdl_joystick;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (vec_it == map_it->second.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *vec_it;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLState::InitJoystick(int joystick_index) {
|
void SDLState::InitJoystick(int joystick_index) {
|
||||||
SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
|
SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
|
||||||
SDL_GameController* sdl_gamecontroller = nullptr;
|
SDL_GameController* sdl_gamecontroller = nullptr;
|
||||||
|
|
||||||
if (SDL_IsGameController(joystick_index)) {
|
if (SDL_IsGameController(joystick_index)) {
|
||||||
sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
|
sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sdl_joystick) {
|
if (!sdl_joystick) {
|
||||||
LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
|
LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string guid = GetGUID(sdl_joystick);
|
const std::string guid = GetGUID(sdl_joystick);
|
||||||
|
|
||||||
std::lock_guard lock{joystick_map_mutex};
|
std::lock_guard lock{joystick_map_mutex};
|
||||||
|
@ -257,14 +246,17 @@ void SDLState::InitJoystick(int joystick_index) {
|
||||||
joystick_map[guid].emplace_back(std::move(joystick));
|
joystick_map[guid].emplace_back(std::move(joystick));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& joystick_guid_list = joystick_map[guid];
|
auto& joystick_guid_list = joystick_map[guid];
|
||||||
const auto it = std::find_if(
|
const auto joystick_it =
|
||||||
joystick_guid_list.begin(), joystick_guid_list.end(),
|
std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
|
||||||
[](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); });
|
[](const auto& joystick) { return !joystick->GetSDLJoystick(); });
|
||||||
if (it != joystick_guid_list.end()) {
|
|
||||||
(*it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
|
if (joystick_it != joystick_guid_list.end()) {
|
||||||
|
(*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int port = static_cast<int>(joystick_guid_list.size());
|
const int port = static_cast<int>(joystick_guid_list.size());
|
||||||
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
|
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
|
||||||
joystick_guid_list.emplace_back(std::move(joystick));
|
joystick_guid_list.emplace_back(std::move(joystick));
|
||||||
|
@ -274,18 +266,14 @@ void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
|
||||||
const std::string guid = GetGUID(sdl_joystick);
|
const std::string guid = GetGUID(sdl_joystick);
|
||||||
|
|
||||||
std::lock_guard lock{joystick_map_mutex};
|
std::lock_guard lock{joystick_map_mutex};
|
||||||
auto& joystick_guid_list = joystick_map[guid];
|
// This call to guid is safe since the joystick is guaranteed to be in the map
|
||||||
auto joystick_it = std::find_if(
|
const auto& joystick_guid_list = joystick_map[guid];
|
||||||
joystick_guid_list.begin(), joystick_guid_list.end(),
|
const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
|
||||||
[&sdl_joystick](auto& joystick) { return joystick->GetSDLJoystick() == sdl_joystick; });
|
[&sdl_joystick](const auto& joystick) {
|
||||||
|
return joystick->GetSDLJoystick() == sdl_joystick;
|
||||||
|
});
|
||||||
|
|
||||||
if (joystick_it != joystick_guid_list.end()) {
|
(*joystick_it)->SetSDLJoystick(nullptr, nullptr);
|
||||||
(*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) {
|
void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
|
||||||
|
@ -720,8 +708,7 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
|
||||||
std::vector<Common::ParamPackage> devices;
|
std::vector<Common::ParamPackage> devices;
|
||||||
for (const auto& [key, value] : joystick_map) {
|
for (const auto& [key, value] : joystick_map) {
|
||||||
for (const auto& joystick : value) {
|
for (const auto& joystick : value) {
|
||||||
auto* joy = joystick->GetSDLJoystick();
|
if (auto* const controller = joystick->GetSDLGameController()) {
|
||||||
if (auto* controller = joystick->GetSDLGameController()) {
|
|
||||||
std::string name =
|
std::string name =
|
||||||
fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
|
fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
|
||||||
devices.emplace_back(Common::ParamPackage{
|
devices.emplace_back(Common::ParamPackage{
|
||||||
|
@ -730,7 +717,7 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
|
||||||
{"guid", joystick->GetGUID()},
|
{"guid", joystick->GetGUID()},
|
||||||
{"port", std::to_string(joystick->GetPort())},
|
{"port", std::to_string(joystick->GetPort())},
|
||||||
});
|
});
|
||||||
} else if (joy) {
|
} else if (auto* const joy = joystick->GetSDLJoystick()) {
|
||||||
std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort());
|
std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort());
|
||||||
devices.emplace_back(Common::ParamPackage{
|
devices.emplace_back(Common::ParamPackage{
|
||||||
{"class", "sdl"},
|
{"class", "sdl"},
|
||||||
|
@ -797,21 +784,27 @@ Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s
|
||||||
Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
|
Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_JOYAXISMOTION: {
|
case SDL_JOYAXISMOTION: {
|
||||||
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
|
if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
|
||||||
return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
||||||
static_cast<s32>(event.jaxis.axis),
|
static_cast<s32>(event.jaxis.axis),
|
||||||
event.jaxis.value);
|
event.jaxis.value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case SDL_JOYBUTTONUP: {
|
case SDL_JOYBUTTONUP: {
|
||||||
const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
|
if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) {
|
||||||
return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
||||||
static_cast<s32>(event.jbutton.button));
|
static_cast<s32>(event.jbutton.button));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case SDL_JOYHATMOTION: {
|
case SDL_JOYHATMOTION: {
|
||||||
const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
|
if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) {
|
||||||
return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
||||||
static_cast<s32>(event.jhat.hat),
|
static_cast<s32>(event.jhat.hat),
|
||||||
static_cast<s32>(event.jhat.value));
|
static_cast<s32>(event.jhat.value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
@ -820,21 +813,27 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve
|
||||||
Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) {
|
Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_JOYAXISMOTION: {
|
case SDL_JOYAXISMOTION: {
|
||||||
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
|
if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
|
||||||
return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
||||||
static_cast<s32>(event.jaxis.axis),
|
static_cast<s32>(event.jaxis.axis),
|
||||||
event.jaxis.value);
|
event.jaxis.value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case SDL_JOYBUTTONUP: {
|
case SDL_JOYBUTTONUP: {
|
||||||
const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
|
if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) {
|
||||||
return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
||||||
static_cast<s32>(event.jbutton.button));
|
static_cast<s32>(event.jbutton.button));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case SDL_JOYHATMOTION: {
|
case SDL_JOYHATMOTION: {
|
||||||
const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
|
if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) {
|
||||||
return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
|
||||||
static_cast<s32>(event.jhat.hat),
|
static_cast<s32>(event.jhat.hat),
|
||||||
static_cast<s32>(event.jhat.value));
|
static_cast<s32>(event.jhat.value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
@ -1062,9 +1061,8 @@ public:
|
||||||
// Simplify controller config by testing if game controller support is enabled.
|
// Simplify controller config by testing if game controller support is enabled.
|
||||||
if (event.type == SDL_JOYAXISMOTION) {
|
if (event.type == SDL_JOYAXISMOTION) {
|
||||||
const auto axis = event.jaxis.axis;
|
const auto axis = event.jaxis.axis;
|
||||||
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
|
if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
|
||||||
auto* const controller = joystick->GetSDLGameController();
|
auto* const controller = joystick->GetSDLGameController()) {
|
||||||
if (controller) {
|
|
||||||
const auto axis_left_x =
|
const auto axis_left_x =
|
||||||
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
|
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
|
||||||
.value.axis;
|
.value.axis;
|
||||||
|
@ -1098,12 +1096,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (analog_x_axis != -1 && analog_y_axis != -1) {
|
if (analog_x_axis != -1 && analog_y_axis != -1) {
|
||||||
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
|
if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) {
|
||||||
auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
|
auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
|
||||||
analog_x_axis, analog_y_axis);
|
analog_x_axis, analog_y_axis);
|
||||||
analog_x_axis = -1;
|
analog_x_axis = -1;
|
||||||
analog_y_axis = -1;
|
analog_y_axis = -1;
|
||||||
return params;
|
return params;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue