sdl: handle joystick and gamepad api errors to avoid crashes

Fixes MINIDUMP-7K
This commit is contained in:
Flyinghead 2023-02-06 15:20:21 +01:00
parent 98531e07ea
commit a045c52146
1 changed files with 77 additions and 59 deletions

View File

@ -166,7 +166,16 @@ public:
SDLGamepad(int maple_port, int joystick_idx, SDL_Joystick* sdl_joystick) SDLGamepad(int maple_port, int joystick_idx, SDL_Joystick* sdl_joystick)
: GamepadDevice(maple_port, "SDL"), sdl_joystick(sdl_joystick) : GamepadDevice(maple_port, "SDL"), sdl_joystick(sdl_joystick)
{ {
_name = SDL_JoystickName(sdl_joystick); const char *joyName = SDL_JoystickName(sdl_joystick);
if (joyName == nullptr)
{
WARN_LOG(INPUT, "Can't get joystick %d name: %s", joystick_idx, SDL_GetError());
_name = "Joystick " + std::to_string(joystick_idx);
}
else
{
_name = joyName;
}
sdl_joystick_instance = SDL_JoystickInstanceID(sdl_joystick); sdl_joystick_instance = SDL_JoystickInstanceID(sdl_joystick);
_unique_id = "sdl_joystick_" + std::to_string(sdl_joystick_instance); _unique_id = "sdl_joystick_" + std::to_string(sdl_joystick_instance);
INFO_LOG(INPUT, "SDL: Opened joystick %d on port %d: '%s' unique_id=%s", sdl_joystick_instance, maple_port, _name.c_str(), _unique_id.c_str()); INFO_LOG(INPUT, "SDL: Opened joystick %d on port %d: '%s' unique_id=%s", sdl_joystick_instance, maple_port, _name.c_str(), _unique_id.c_str());
@ -174,12 +183,19 @@ public:
if (SDL_IsGameController(joystick_idx)) if (SDL_IsGameController(joystick_idx))
{ {
sdl_controller = SDL_GameControllerOpen(joystick_idx); sdl_controller = SDL_GameControllerOpen(joystick_idx);
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(sdl_controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT); if (sdl_controller == nullptr)
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) {
leftTrigger = bind.value.axis; WARN_LOG(INPUT, "Can't open game controller %d: %s", joystick_idx, SDL_GetError());
bind = SDL_GameControllerGetBindForAxis(sdl_controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT); }
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) else
rightTrigger = bind.value.axis; {
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(sdl_controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS)
leftTrigger = bind.value.axis;
bind = SDL_GameControllerGetBindForAxis(sdl_controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS)
rightTrigger = bind.value.axis;
}
} }
if (!find_mapping()) if (!find_mapping())
@ -273,50 +289,51 @@ public:
{ "paddle4", "Paddle 4" }, { "paddle4", "Paddle 4" },
{ "touchpad", "Touchpad" }, { "touchpad", "Touchpad" },
}; };
for (SDL_GameControllerButton button = SDL_CONTROLLER_BUTTON_A; button < SDL_CONTROLLER_BUTTON_MAX; button = (SDL_GameControllerButton)(button + 1)) if (sdl_controller != nullptr)
{ for (SDL_GameControllerButton button = SDL_CONTROLLER_BUTTON_A; button < SDL_CONTROLLER_BUTTON_MAX; button = (SDL_GameControllerButton)(button + 1))
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(sdl_controller, button);
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON && bind.value.button == (int)code)
{ {
const char *sdlButton = SDL_GameControllerGetStringForButton(button); SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(sdl_controller, button);
if (sdlButton == nullptr) if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON && bind.value.button == (int)code)
return nullptr;
for (const auto& button : buttonsTable)
if (!strcmp(button.sdlButton, sdlButton))
return button.label;
return sdlButton;
}
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT && (code >> 8) - 1 == (u32)bind.value.hat.hat)
{
int hat;
const char *name;
switch (code & 0xff)
{ {
case 0: const char *sdlButton = SDL_GameControllerGetStringForButton(button);
hat = SDL_HAT_UP; if (sdlButton == nullptr)
name = "DPad Up"; return nullptr;
break; for (const auto& button : buttonsTable)
case 1: if (!strcmp(button.sdlButton, sdlButton))
hat = SDL_HAT_DOWN; return button.label;
name = "DPad Down"; return sdlButton;
break; }
case 2: if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT && (code >> 8) - 1 == (u32)bind.value.hat.hat)
hat = SDL_HAT_LEFT; {
name = "DPad Left"; int hat;
break; const char *name;
case 3: switch (code & 0xff)
hat = SDL_HAT_RIGHT; {
name = "DPad Right"; case 0:
break; hat = SDL_HAT_UP;
default: name = "DPad Up";
hat = 0; break;
name = nullptr; case 1:
break; hat = SDL_HAT_DOWN;
name = "DPad Down";
break;
case 2:
hat = SDL_HAT_LEFT;
name = "DPad Left";
break;
case 3:
hat = SDL_HAT_RIGHT;
name = "DPad Right";
break;
default:
hat = 0;
name = nullptr;
break;
}
if (hat == bind.value.hat.hat_mask)
return name;
} }
if (hat == bind.value.hat.hat_mask)
return name;
} }
}
return nullptr; return nullptr;
} }
@ -336,20 +353,21 @@ public:
{ "righttrigger", "R2" }, { "righttrigger", "R2" },
}; };
for (SDL_GameControllerAxis axis = SDL_CONTROLLER_AXIS_LEFTX; axis < SDL_CONTROLLER_AXIS_MAX; axis = (SDL_GameControllerAxis)(axis + 1)) if (sdl_controller != nullptr)
{ for (SDL_GameControllerAxis axis = SDL_CONTROLLER_AXIS_LEFTX; axis < SDL_CONTROLLER_AXIS_MAX; axis = (SDL_GameControllerAxis)(axis + 1))
SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(sdl_controller, axis);
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS && bind.value.axis == (int)code)
{ {
const char *sdlAxis = SDL_GameControllerGetStringForAxis(axis); SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(sdl_controller, axis);
if (sdlAxis == nullptr) if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS && bind.value.axis == (int)code)
return nullptr; {
for (const auto& axis : axesTable) const char *sdlAxis = SDL_GameControllerGetStringForAxis(axis);
if (!strcmp(axis.sdlAxis, sdlAxis)) if (sdlAxis == nullptr)
return axis.label; return nullptr;
return sdlAxis; for (const auto& axis : axesTable)
if (!strcmp(axis.sdlAxis, sdlAxis))
return axis.label;
return sdlAxis;
}
} }
}
return nullptr; return nullptr;
} }