The names of keyboards and mice are valid after they've been removed

Fixes https://github.com/libsdl-org/SDL/issues/12816
This commit is contained in:
Sam Lantinga
2025-09-11 19:39:51 -07:00
parent 3ddc3f1146
commit 00812d13b0
3 changed files with 59 additions and 46 deletions

View File

@@ -44,12 +44,6 @@
#define KEYCODE_OPTION_LATIN_LETTERS 0x04
#define DEFAULT_KEYCODE_OPTIONS (KEYCODE_OPTION_FRENCH_NUMBERS | KEYCODE_OPTION_LATIN_LETTERS)
typedef struct SDL_KeyboardInstance
{
SDL_KeyboardID instance_id;
char *name;
} SDL_KeyboardInstance;
typedef struct SDL_Keyboard
{
// Data common to all keyboards
@@ -65,7 +59,8 @@ typedef struct SDL_Keyboard
static SDL_Keyboard SDL_keyboard;
static int SDL_keyboard_count;
static SDL_KeyboardInstance *SDL_keyboards;
static SDL_KeyboardID *SDL_keyboards;
static SDL_HashTable *SDL_keyboard_names;
static bool SDL_keyboard_quitting;
static void SDLCALL SDL_KeycodeOptionsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
@@ -95,6 +90,9 @@ bool SDL_InitKeyboard(void)
{
SDL_AddHintCallback(SDL_HINT_KEYCODE_OPTIONS,
SDL_KeycodeOptionsChanged, &SDL_keyboard);
SDL_keyboard_names = SDL_CreateHashTable(0, true, SDL_HashID, SDL_KeyMatchID, SDL_DestroyHashValue, NULL);
return true;
}
@@ -112,7 +110,7 @@ bool SDL_IsKeyboard(Uint16 vendor, Uint16 product, int num_keys)
static int SDL_GetKeyboardIndex(SDL_KeyboardID keyboardID)
{
for (int i = 0; i < SDL_keyboard_count; ++i) {
if (keyboardID == SDL_keyboards[i].instance_id) {
if (keyboardID == SDL_keyboards[i]) {
return i;
}
}
@@ -129,16 +127,19 @@ void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name)
SDL_assert(keyboardID != 0);
SDL_KeyboardInstance *keyboards = (SDL_KeyboardInstance *)SDL_realloc(SDL_keyboards, (SDL_keyboard_count + 1) * sizeof(*keyboards));
SDL_KeyboardID *keyboards = (SDL_KeyboardID *)SDL_realloc(SDL_keyboards, (SDL_keyboard_count + 1) * sizeof(*keyboards));
if (!keyboards) {
return;
}
SDL_KeyboardInstance *instance = &keyboards[SDL_keyboard_count];
instance->instance_id = keyboardID;
instance->name = SDL_strdup(name ? name : "");
keyboards[SDL_keyboard_count] = keyboardID;
SDL_keyboards = keyboards;
++SDL_keyboard_count;
if (!name) {
name = "Keyboard";
}
SDL_InsertIntoHashTable(SDL_keyboard_names, (const void *)(uintptr_t)keyboardID, SDL_strdup(name), true);
SDL_Event event;
SDL_zero(event);
event.type = SDL_EVENT_KEYBOARD_ADDED;
@@ -154,8 +155,6 @@ void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID)
return;
}
SDL_free(SDL_keyboards[keyboard_index].name);
if (keyboard_index != SDL_keyboard_count - 1) {
SDL_memmove(&SDL_keyboards[keyboard_index], &SDL_keyboards[keyboard_index + 1], (SDL_keyboard_count - keyboard_index - 1) * sizeof(SDL_keyboards[keyboard_index]));
}
@@ -187,7 +186,7 @@ SDL_KeyboardID *SDL_GetKeyboards(int *count)
}
for (i = 0; i < SDL_keyboard_count; ++i) {
keyboards[i] = SDL_keyboards[i].instance_id;
keyboards[i] = SDL_keyboards[i];
}
keyboards[i] = 0;
} else {
@@ -201,12 +200,17 @@ SDL_KeyboardID *SDL_GetKeyboards(int *count)
const char *SDL_GetKeyboardNameForID(SDL_KeyboardID instance_id)
{
int keyboard_index = SDL_GetKeyboardIndex(instance_id);
if (keyboard_index < 0) {
const char *name = NULL;
if (!SDL_FindInHashTable(SDL_keyboard_names, (const void *)(uintptr_t)instance_id, (const void **)&name)) {
SDL_SetError("Keyboard %" SDL_PRIu32 " not found", instance_id);
return NULL;
}
return SDL_GetPersistentString(SDL_keyboards[keyboard_index].name);
if (!name) {
// SDL_strdup() failed during insert
SDL_OutOfMemory();
return NULL;
}
return name;
}
void SDL_ResetKeyboard(void)
@@ -871,11 +875,14 @@ void SDL_QuitKeyboard(void)
SDL_keyboard_quitting = true;
for (int i = SDL_keyboard_count; i--;) {
SDL_RemoveKeyboard(SDL_keyboards[i].instance_id);
SDL_RemoveKeyboard(SDL_keyboards[i]);
}
SDL_free(SDL_keyboards);
SDL_keyboards = NULL;
SDL_DestroyHashTable(SDL_keyboard_names);
SDL_keyboard_names = NULL;
if (SDL_keyboard.keymap && SDL_keyboard.keymap->auto_release) {
SDL_DestroyKeymap(SDL_keyboard.keymap);
SDL_keyboard.keymap = NULL;

View File

@@ -34,16 +34,11 @@
#define WARP_EMULATION_THRESHOLD_NS SDL_MS_TO_NS(30)
typedef struct SDL_MouseInstance
{
SDL_MouseID instance_id;
char *name;
} SDL_MouseInstance;
// The mouse state
static SDL_Mouse SDL_mouse;
static int SDL_mouse_count;
static SDL_MouseInstance *SDL_mice;
static SDL_MouseID *SDL_mice;
static SDL_HashTable *SDL_mouse_names;
static bool SDL_mouse_quitting;
// for mapping mouse events to touch
@@ -311,6 +306,8 @@ bool SDL_PreInitMouse(void)
mouse->cursor_visible = true;
SDL_mouse_names = SDL_CreateHashTable(0, true, SDL_HashID, SDL_KeyMatchID, SDL_DestroyHashValue, NULL);
return true;
}
@@ -340,7 +337,7 @@ bool SDL_IsMouse(Uint16 vendor, Uint16 product)
static int SDL_GetMouseIndex(SDL_MouseID mouseID)
{
for (int i = 0; i < SDL_mouse_count; ++i) {
if (mouseID == SDL_mice[i].instance_id) {
if (mouseID == SDL_mice[i]) {
return i;
}
}
@@ -357,16 +354,19 @@ void SDL_AddMouse(SDL_MouseID mouseID, const char *name)
SDL_assert(mouseID != 0);
SDL_MouseInstance *mice = (SDL_MouseInstance *)SDL_realloc(SDL_mice, (SDL_mouse_count + 1) * sizeof(*mice));
SDL_MouseID *mice = (SDL_MouseID *)SDL_realloc(SDL_mice, (SDL_mouse_count + 1) * sizeof(*mice));
if (!mice) {
return;
}
SDL_MouseInstance *instance = &mice[SDL_mouse_count];
instance->instance_id = mouseID;
instance->name = SDL_strdup(name ? name : "");
mice[SDL_mouse_count] = mouseID;
SDL_mice = mice;
++SDL_mouse_count;
if (!name) {
name = "Mouse";
}
SDL_InsertIntoHashTable(SDL_mouse_names, (const void *)(uintptr_t)mouseID, SDL_strdup(name), true);
SDL_Event event;
SDL_zero(event);
event.type = SDL_EVENT_MOUSE_ADDED;
@@ -382,8 +382,6 @@ void SDL_RemoveMouse(SDL_MouseID mouseID)
return;
}
SDL_free(SDL_mice[mouse_index].name);
if (mouse_index != SDL_mouse_count - 1) {
SDL_memmove(&SDL_mice[mouse_index], &SDL_mice[mouse_index + 1], (SDL_mouse_count - mouse_index - 1) * sizeof(SDL_mice[mouse_index]));
}
@@ -429,7 +427,7 @@ SDL_MouseID *SDL_GetMice(int *count)
}
for (i = 0; i < SDL_mouse_count; ++i) {
mice[i] = SDL_mice[i].instance_id;
mice[i] = SDL_mice[i];
}
mice[i] = 0;
} else {
@@ -443,12 +441,17 @@ SDL_MouseID *SDL_GetMice(int *count)
const char *SDL_GetMouseNameForID(SDL_MouseID instance_id)
{
int mouse_index = SDL_GetMouseIndex(instance_id);
if (mouse_index < 0) {
const char *name = NULL;
if (!SDL_FindInHashTable(SDL_mouse_names, (const void *)(uintptr_t)instance_id, (const void **)&name)) {
SDL_SetError("Mouse %" SDL_PRIu32 " not found", instance_id);
return NULL;
}
return SDL_GetPersistentString(SDL_mice[mouse_index].name);
if (!name) {
// SDL_strdup() failed during insert
SDL_OutOfMemory();
return NULL;
}
return name;
}
void SDL_SetDefaultCursor(SDL_Cursor *cursor)
@@ -1165,11 +1168,14 @@ void SDL_QuitMouse(void)
SDL_MouseIntegerModeChanged, mouse);
for (int i = SDL_mouse_count; i--; ) {
SDL_RemoveMouse(SDL_mice[i].instance_id);
SDL_RemoveMouse(SDL_mice[i]);
}
SDL_free(SDL_mice);
SDL_mice = NULL;
SDL_DestroyHashTable(SDL_mouse_names);
SDL_mouse_names = NULL;
if (mouse->internal) {
SDL_free(mouse->internal);
mouse->internal = NULL;

View File

@@ -1733,12 +1733,12 @@ void SDLTest_PrintEvent(const SDL_Event *event)
SDL_Log("SDL EVENT: Window %" SDL_PRIu32 " HDR %s", event->window.windowID, event->window.data1 ? "enabled" : "disabled");
break;
case SDL_EVENT_KEYBOARD_ADDED:
SDL_Log("SDL EVENT: Keyboard %" SDL_PRIu32 " attached",
event->kdevice.which);
SDL_Log("SDL EVENT: Keyboard %" SDL_PRIu32 " (%s) attached",
event->kdevice.which, SDL_GetKeyboardNameForID(event->kdevice.which));
break;
case SDL_EVENT_KEYBOARD_REMOVED:
SDL_Log("SDL EVENT: Keyboard %" SDL_PRIu32 " removed",
event->kdevice.which);
SDL_Log("SDL EVENT: Keyboard %" SDL_PRIu32 " (%s) removed",
event->kdevice.which, SDL_GetKeyboardNameForID(event->kdevice.which));
break;
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP: {
@@ -1775,12 +1775,12 @@ void SDLTest_PrintEvent(const SDL_Event *event)
SDL_Log("SDL EVENT: Keymap changed");
break;
case SDL_EVENT_MOUSE_ADDED:
SDL_Log("SDL EVENT: Mouse %" SDL_PRIu32 " attached",
event->mdevice.which);
SDL_Log("SDL EVENT: Mouse %" SDL_PRIu32 " (%s) attached",
event->mdevice.which, SDL_GetMouseNameForID(event->mdevice.which));
break;
case SDL_EVENT_MOUSE_REMOVED:
SDL_Log("SDL EVENT: Mouse %" SDL_PRIu32 " removed",
event->mdevice.which);
SDL_Log("SDL EVENT: Mouse %" SDL_PRIu32 " (%s) removed",
event->mdevice.which, SDL_GetMouseNameForID(event->mdevice.which));
break;
case SDL_EVENT_MOUSE_MOTION:
SDL_Log("SDL EVENT: Mouse: moved to %g,%g (%g,%g) in window %" SDL_PRIu32,