Fix lost KEY_UP events with multiple keyboards using shared scancode state (#14446)
Build (All) / Create test plan (push) Has been cancelled
Build (All) / level1 (push) Has been cancelled
Build (All) / level2 (push) Has been cancelled

This commit is contained in:
Chris Burrows
2025-11-12 18:36:08 +11:00
committed by GitHub
parent 65989d269e
commit 3dab15d3b4
+24 -4
View File
@@ -51,6 +51,7 @@ typedef struct SDL_Keyboard
SDL_Keymod modstate; SDL_Keymod modstate;
Uint8 keysource[SDL_SCANCODE_COUNT]; Uint8 keysource[SDL_SCANCODE_COUNT];
bool keystate[SDL_SCANCODE_COUNT]; bool keystate[SDL_SCANCODE_COUNT];
Uint8 keyrefcount[SDL_SCANCODE_COUNT]; // how many devices hold this key
SDL_Keymap *keymap; SDL_Keymap *keymap;
Uint32 keycode_options; Uint32 keycode_options;
bool autorelease_pending; bool autorelease_pending;
@@ -88,6 +89,10 @@ static void SDLCALL SDL_KeycodeOptionsChanged(void *userdata, const char *name,
// Public functions // Public functions
bool SDL_InitKeyboard(void) bool SDL_InitKeyboard(void)
{ {
// Init key reference counts to 0
SDL_Keyboard *keyboard = &SDL_keyboard;
SDL_zeroa(keyboard->keyrefcount);
SDL_AddHintCallback(SDL_HINT_KEYCODE_OPTIONS, SDL_AddHintCallback(SDL_HINT_KEYCODE_OPTIONS,
SDL_KeycodeOptionsChanged, &SDL_keyboard); SDL_KeycodeOptionsChanged, &SDL_keyboard);
@@ -225,6 +230,7 @@ void SDL_ResetKeyboard(void)
if (keyboard->keystate[scancode]) { if (keyboard->keystate[scancode]) {
SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, 0, (SDL_Scancode)scancode, false); SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, 0, (SDL_Scancode)scancode, false);
} }
keyboard->keyrefcount[scancode] = 0; // Reset reference count
} }
} }
@@ -522,6 +528,7 @@ static bool SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, SDL_Keyb
SDL_Keycode keycode = SDLK_UNKNOWN; SDL_Keycode keycode = SDLK_UNKNOWN;
Uint32 type; Uint32 type;
bool repeat = false; bool repeat = false;
bool last_release = false;
const Uint8 source = flags & KEYBOARD_SOURCE_MASK; const Uint8 source = flags & KEYBOARD_SOURCE_MASK;
#ifdef DEBUG_KEYBOARD #ifdef DEBUG_KEYBOARD
@@ -538,6 +545,9 @@ static bool SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, SDL_Keyb
if (scancode > SDL_SCANCODE_UNKNOWN && scancode < SDL_SCANCODE_COUNT) { if (scancode > SDL_SCANCODE_UNKNOWN && scancode < SDL_SCANCODE_COUNT) {
// Drop events that don't change state // Drop events that don't change state
if (down) { if (down) {
if (keyboard->keyrefcount[scancode] < 255) {
keyboard->keyrefcount[scancode]++;
}
if (keyboard->keystate[scancode]) { if (keyboard->keystate[scancode]) {
if (!(keyboard->keysource[scancode] & source)) { if (!(keyboard->keysource[scancode] & source)) {
keyboard->keysource[scancode] |= source; keyboard->keysource[scancode] |= source;
@@ -547,14 +557,22 @@ static bool SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, SDL_Keyb
} }
keyboard->keysource[scancode] |= source; keyboard->keysource[scancode] |= source;
} else { } else {
if (!keyboard->keystate[scancode]) { if (keyboard->keyrefcount[scancode] == 0) {
return false; return false;
} }
keyboard->keysource[scancode] = 0; --keyboard->keyrefcount[scancode];
if (keyboard->keyrefcount[scancode] == 0) {
keyboard->keysource[scancode] = 0;
last_release = true;
}
} }
// Update internal keyboard state // Update internal keyboard state
keyboard->keystate[scancode] = down; if (down) {
keyboard->keystate[scancode] = true;
} else if (last_release) {
keyboard->keystate[scancode] = false;
}
keycode = SDL_GetKeyFromScancode(scancode, keyboard->modstate, true); keycode = SDL_GetKeyFromScancode(scancode, keyboard->modstate, true);
@@ -621,7 +639,9 @@ static bool SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, SDL_Keyb
break; break;
} }
} else { } else {
keyboard->modstate &= ~modifier; if (last_release) {
keyboard->modstate &= ~modifier;
}
} }
} }