Fixed crash if a virtual joystick was disconnected

main
Sam Lantinga 2022-05-16 08:55:54 -07:00
parent 2317a96c8e
commit 3c3ccb1d48
3 changed files with 97 additions and 43 deletions

View File

@ -71,6 +71,10 @@ VIRTUAL_FreeHWData(joystick_hwdata *hwdata)
cur = cur->next; cur = cur->next;
} }
if (hwdata->joystick) {
hwdata->joystick->hwdata = NULL;
hwdata->joystick = NULL;
}
if (hwdata->name) { if (hwdata->name) {
SDL_free(hwdata->name); SDL_free(hwdata->name);
hwdata->name = NULL; hwdata->name = NULL;
@ -434,16 +438,12 @@ VIRTUAL_JoystickOpen(SDL_Joystick *joystick, int device_index)
if (!hwdata) { if (!hwdata) {
return SDL_SetError("No such device"); return SDL_SetError("No such device");
} }
if (hwdata->opened) {
/* This should never happen, it's handled by the higher joystick code */
return SDL_SetError("Joystick already opened");
}
joystick->instance_id = hwdata->instance_id; joystick->instance_id = hwdata->instance_id;
joystick->hwdata = hwdata; joystick->hwdata = hwdata;
joystick->naxes = hwdata->desc.naxes; joystick->naxes = hwdata->desc.naxes;
joystick->nbuttons = hwdata->desc.nbuttons; joystick->nbuttons = hwdata->desc.nbuttons;
joystick->nhats = hwdata->desc.nhats; joystick->nhats = hwdata->desc.nhats;
hwdata->opened = SDL_TRUE; hwdata->joystick = joystick;
return 0; return 0;
} }
@ -451,23 +451,39 @@ VIRTUAL_JoystickOpen(SDL_Joystick *joystick, int device_index)
static int static int
VIRTUAL_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) VIRTUAL_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{ {
joystick_hwdata *hwdata = joystick->hwdata; int result;
if (hwdata && hwdata->desc.Rumble) { if (joystick->hwdata) {
return hwdata->desc.Rumble(hwdata->desc.userdata, low_frequency_rumble, high_frequency_rumble); joystick_hwdata *hwdata = joystick->hwdata;
if (hwdata->desc.Rumble) {
result = hwdata->desc.Rumble(hwdata->desc.userdata, low_frequency_rumble, high_frequency_rumble);
} else {
result = SDL_Unsupported();
}
} else {
result = SDL_SetError("Rumble failed, device disconnected");
} }
return SDL_Unsupported();
return result;
} }
static int static int
VIRTUAL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) VIRTUAL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{ {
joystick_hwdata *hwdata = joystick->hwdata; int result;
if (hwdata && hwdata->desc.RumbleTriggers) { if (joystick->hwdata) {
return hwdata->desc.RumbleTriggers(hwdata->desc.userdata, left_rumble, right_rumble); joystick_hwdata *hwdata = joystick->hwdata;
if (hwdata->desc.RumbleTriggers) {
result = hwdata->desc.RumbleTriggers(hwdata->desc.userdata, left_rumble, right_rumble);
} else {
result = SDL_Unsupported();
}
} else {
result = SDL_SetError("Rumble failed, device disconnected");
} }
return SDL_Unsupported();
return result;
} }
@ -495,23 +511,39 @@ VIRTUAL_JoystickGetCapabilities(SDL_Joystick *joystick)
static int static int
VIRTUAL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) VIRTUAL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{ {
joystick_hwdata *hwdata = joystick->hwdata; int result;
if (hwdata && hwdata->desc.SetLED) { if (joystick->hwdata) {
return hwdata->desc.SetLED(hwdata->desc.userdata, red, green, blue); joystick_hwdata *hwdata = joystick->hwdata;
if (hwdata->desc.SetLED) {
result = hwdata->desc.SetLED(hwdata->desc.userdata, red, green, blue);
} else {
result = SDL_Unsupported();
}
} else {
result = SDL_SetError("SetLED failed, device disconnected");
} }
return SDL_Unsupported();
return result;
} }
static int static int
VIRTUAL_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) VIRTUAL_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{ {
joystick_hwdata *hwdata = joystick->hwdata; int result;
if (hwdata && hwdata->desc.SendEffect) { if (joystick->hwdata) {
return hwdata->desc.SendEffect(hwdata->desc.userdata, data, size); joystick_hwdata *hwdata = joystick->hwdata;
if (hwdata->desc.SendEffect) {
result = hwdata->desc.SendEffect(hwdata->desc.userdata, data, size);
} else {
result = SDL_Unsupported();
}
} else {
result = SDL_SetError("SendEffect failed, device disconnected");
} }
return SDL_Unsupported();
return result;
} }
static int static int
@ -555,17 +587,11 @@ VIRTUAL_JoystickUpdate(SDL_Joystick *joystick)
static void static void
VIRTUAL_JoystickClose(SDL_Joystick *joystick) VIRTUAL_JoystickClose(SDL_Joystick *joystick)
{ {
joystick_hwdata *hwdata; if (joystick->hwdata) {
joystick_hwdata *hwdata = joystick->hwdata;
if (!joystick) { hwdata->joystick = NULL;
return; joystick->hwdata = NULL;
} }
if (!joystick->hwdata) {
return;
}
hwdata = (joystick_hwdata *)joystick->hwdata;
hwdata->opened = SDL_FALSE;
} }

View File

@ -41,7 +41,8 @@ typedef struct joystick_hwdata
Uint8 *buttons; Uint8 *buttons;
Uint8 *hats; Uint8 *hats;
SDL_JoystickID instance_id; SDL_JoystickID instance_id;
SDL_bool opened; SDL_Joystick *joystick;
struct joystick_hwdata *next; struct joystick_hwdata *next;
} joystick_hwdata; } joystick_hwdata;

View File

@ -335,9 +335,10 @@ static int VirtualControllerSetLED(void *userdata, Uint8 red, Uint8 green, Uint8
return 0; return 0;
} }
static int OpenVirtualController() static void OpenVirtualController()
{ {
SDL_VirtualJoystickDesc desc; SDL_VirtualJoystickDesc desc;
int virtual_index;
SDL_zero(desc); SDL_zero(desc);
desc.version = SDL_VIRTUAL_JOYSTICK_DESC_VERSION; desc.version = SDL_VIRTUAL_JOYSTICK_DESC_VERSION;
@ -348,7 +349,32 @@ static int OpenVirtualController()
desc.Rumble = VirtualControllerRumble; desc.Rumble = VirtualControllerRumble;
desc.RumbleTriggers = VirtualControllerRumbleTriggers; desc.RumbleTriggers = VirtualControllerRumbleTriggers;
desc.SetLED = VirtualControllerSetLED; desc.SetLED = VirtualControllerSetLED;
return SDL_JoystickAttachVirtualEx(&desc);
virtual_index = SDL_JoystickAttachVirtualEx(&desc);
if (virtual_index < 0) {
SDL_Log("Couldn't open virtual device: %s\n", SDL_GetError());
} else {
virtual_joystick = SDL_JoystickOpen(virtual_index);
if (!virtual_joystick) {
SDL_Log("Couldn't open virtual device: %s\n", SDL_GetError());
}
}
}
static void CloseVirtualController()
{
int i;
for (i = 0; i < SDL_NumJoysticks(); ++i) {
if (SDL_JoystickIsVirtual(i)) {
SDL_JoystickDetachVirtual(i);
}
}
if (virtual_joystick) {
SDL_JoystickClose(virtual_joystick);
virtual_joystick = NULL;
}
} }
static SDL_GameControllerButton FindButtonAtPosition(int x, int y) static SDL_GameControllerButton FindButtonAtPosition(int x, int y)
@ -580,6 +606,14 @@ loop(void *arg)
} }
break; break;
} }
if (event.key.keysym.sym == SDLK_a) {
OpenVirtualController();
break;
}
if (event.key.keysym.sym == SDLK_d) {
CloseVirtualController();
break;
}
if (event.key.keysym.sym != SDLK_ESCAPE) { if (event.key.keysym.sym != SDLK_ESCAPE) {
break; break;
} }
@ -836,15 +870,7 @@ main(int argc, char *argv[])
for (i = 1; i < argc; ++i) { for (i = 1; i < argc; ++i) {
if (SDL_strcmp(argv[i], "--virtual") == 0) { if (SDL_strcmp(argv[i], "--virtual") == 0) {
int virtual_index = OpenVirtualController(); OpenVirtualController();
if (virtual_index < 0) {
SDL_Log("Couldn't open virtual device: %s\n", SDL_GetError());
} else {
virtual_joystick = SDL_JoystickOpen(virtual_index);
if (!virtual_joystick) {
SDL_Log("Couldn't open virtual device: %s\n", SDL_GetError());
}
}
} }
if (argv[i] && *argv[i] != '-') { if (argv[i] && *argv[i] != '-') {
controller_index = SDL_atoi(argv[i]); controller_index = SDL_atoi(argv[i]);
@ -873,6 +899,7 @@ main(int argc, char *argv[])
CyclePS5TriggerEffect(); CyclePS5TriggerEffect();
} }
CloseVirtualController();
SDL_DestroyRenderer(screen); SDL_DestroyRenderer(screen);
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);