From cbb83be895a463cb9a20f2ec5b11f33bdf98e5dc Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 20 Mar 2025 15:10:24 -0700 Subject: [PATCH] Show the on-screen keyboard if we don't have active keyboard input Active keyboard input is based on the input the user has most recently sent. Fixes https://github.com/libsdl-org/SDL/issues/12595 --- src/events/SDL_keyboard.c | 17 +++++++++++++++++ src/events/SDL_keyboard_c.h | 6 ++++++ src/joystick/SDL_joystick.c | 19 +++++++++++++++++++ src/joystick/SDL_sysjoystick.h | 1 + src/video/SDL_video.c | 2 +- 5 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c index 066c6e6aaa..69fcc08091 100644 --- a/src/events/SDL_keyboard.c +++ b/src/events/SDL_keyboard.c @@ -70,6 +70,7 @@ typedef struct SDL_Keyboard static SDL_Keyboard SDL_keyboard; static int SDL_keyboard_count; static SDL_KeyboardInstance *SDL_keyboards; +static bool SDL_keyboard_active; static void SDLCALL SDL_KeycodeOptionsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) { @@ -214,6 +215,20 @@ const char *SDL_GetKeyboardNameForID(SDL_KeyboardID instance_id) return SDL_GetPersistentString(SDL_keyboards[keyboard_index].name); } +void SDL_SetKeyboardActive(bool active) +{ + SDL_keyboard_active = active; +} + +bool SDL_HasActiveKeyboard(void) +{ + if (!SDL_HasKeyboard()) { + // No keyboards to be active + return false; + } + return SDL_keyboard_active; +} + void SDL_ResetKeyboard(void) { SDL_Keyboard *keyboard = &SDL_keyboard; @@ -556,6 +571,8 @@ static bool SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, SDL_Keyb } if (source == KEYBOARD_HARDWARE) { + // Primary input appears to be a keyboard + SDL_SetKeyboardActive(true); keyboard->hardware_timestamp = SDL_GetTicks(); } else if (source == KEYBOARD_AUTORELEASE) { keyboard->autorelease_pending = true; diff --git a/src/events/SDL_keyboard_c.h b/src/events/SDL_keyboard_c.h index ddfb5c5747..45145cf211 100644 --- a/src/events/SDL_keyboard_c.h +++ b/src/events/SDL_keyboard_c.h @@ -43,6 +43,12 @@ extern void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name, bool se // A keyboard has been removed from the system extern void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID, bool send_event); +// Set whether keyboard input is active +extern void SDL_SetKeyboardActive(bool active); + +// Get whether keyboard input is active +extern bool SDL_HasActiveKeyboard(void); + // Set the mapping of scancode to key codes extern void SDL_SetKeymap(SDL_Keymap *keymap, bool send_event); diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 8f7947b825..bcc806a47f 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -427,6 +427,13 @@ static SDL_vidpid_list zero_centered_devices = { return result; \ } +#define CHECK_JOYSTICK_VIRTUAL(joystick, result) \ + if (!joystick->is_virtual) { \ + SDL_SetError("joystick isn't virtual"); \ + SDL_UnlockJoysticks(); \ + return result; \ + } + bool SDL_JoysticksInitialized(void) { return SDL_joysticks_initialized; @@ -1115,6 +1122,7 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id) joystick->attached = true; joystick->led_expiration = SDL_GetTicks(); joystick->battery_percent = -1; + joystick->is_virtual = (driver == &SDL_VIRTUAL_JoystickDriver); if (!driver->Open(joystick, device_index)) { SDL_SetObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK, false); @@ -1247,6 +1255,7 @@ bool SDL_SetJoystickVirtualAxis(SDL_Joystick *joystick, int axis, Sint16 value) SDL_LockJoysticks(); { CHECK_JOYSTICK_MAGIC(joystick, false); + CHECK_JOYSTICK_VIRTUAL(joystick, false); #ifdef SDL_JOYSTICK_VIRTUAL result = SDL_SetJoystickVirtualAxisInner(joystick, axis, value); @@ -1266,6 +1275,7 @@ bool SDL_SetJoystickVirtualBall(SDL_Joystick *joystick, int ball, Sint16 xrel, S SDL_LockJoysticks(); { CHECK_JOYSTICK_MAGIC(joystick, false); + CHECK_JOYSTICK_VIRTUAL(joystick, false); #ifdef SDL_JOYSTICK_VIRTUAL result = SDL_SetJoystickVirtualBallInner(joystick, ball, xrel, yrel); @@ -1285,6 +1295,7 @@ bool SDL_SetJoystickVirtualButton(SDL_Joystick *joystick, int button, bool down) SDL_LockJoysticks(); { CHECK_JOYSTICK_MAGIC(joystick, false); + CHECK_JOYSTICK_VIRTUAL(joystick, false); #ifdef SDL_JOYSTICK_VIRTUAL result = SDL_SetJoystickVirtualButtonInner(joystick, button, down); @@ -1304,6 +1315,7 @@ bool SDL_SetJoystickVirtualHat(SDL_Joystick *joystick, int hat, Uint8 value) SDL_LockJoysticks(); { CHECK_JOYSTICK_MAGIC(joystick, false); + CHECK_JOYSTICK_VIRTUAL(joystick, false); #ifdef SDL_JOYSTICK_VIRTUAL result = SDL_SetJoystickVirtualHatInner(joystick, hat, value); @@ -1323,6 +1335,7 @@ bool SDL_SetJoystickVirtualTouchpad(SDL_Joystick *joystick, int touchpad, int fi SDL_LockJoysticks(); { CHECK_JOYSTICK_MAGIC(joystick, false); + CHECK_JOYSTICK_VIRTUAL(joystick, false); #ifdef SDL_JOYSTICK_VIRTUAL result = SDL_SetJoystickVirtualTouchpadInner(joystick, touchpad, finger, down, x, y, pressure); @@ -1342,6 +1355,7 @@ bool SDL_SendJoystickVirtualSensorData(SDL_Joystick *joystick, SDL_SensorType ty SDL_LockJoysticks(); { CHECK_JOYSTICK_MAGIC(joystick, false); + CHECK_JOYSTICK_VIRTUAL(joystick, false); #ifdef SDL_JOYSTICK_VIRTUAL result = SDL_SendJoystickVirtualSensorDataInner(joystick, type, sensor_timestamp, data, num_values); @@ -2354,6 +2368,11 @@ void SDL_SendJoystickButton(Uint64 timestamp, SDL_Joystick *joystick, Uint8 butt return; } + if (!joystick->is_virtual) { + // Primary input appears to be a joystick + SDL_SetKeyboardActive(false); + } + /* We ignore events if we don't have keyboard focus, except for button * release. */ if (SDL_PrivateJoystickShouldIgnoreEvent()) { diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index 97f145de9a..f8f2d1af84 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -84,6 +84,7 @@ struct SDL_Joystick Uint16 firmware_version _guarded; // Firmware version, if available Uint64 steam_handle _guarded; // Steam controller API handle bool swap_face_buttons _guarded; // Whether we should swap face buttons + bool is_virtual _guarded; // Whether this is a virtual joystick int naxes _guarded; // Number of axis controls on the joystick SDL_JoystickAxisInfo *axes _guarded; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 1540e92b83..3d45b3b0ac 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -5416,7 +5416,7 @@ bool SDL_GetTextInputMultiline(SDL_PropertiesID props) static bool AutoShowingScreenKeyboard(void) { const char *hint = SDL_GetHint(SDL_HINT_ENABLE_SCREEN_KEYBOARD); - if (((!hint || SDL_strcasecmp(hint, "auto") == 0) && !SDL_HasKeyboard()) || + if (((!hint || SDL_strcasecmp(hint, "auto") == 0) && !SDL_HasActiveKeyboard()) || SDL_GetStringBoolean(hint, false)) { return true; } else {