From 87bb0f5bcbdb30aba1da276f2fa4e7beb8a3e3df Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 8 Nov 2023 03:25:22 -0800
Subject: [PATCH] Don't mute the console input if we can't read the keyboard
This makes sure you can hit Ctrl-C if you don't have permission to access the raw keyboard device.
Fixes https://github.com/libsdl-org/SDL/issues/4812
(cherry picked from commit ce9e1bd32485ae8a024d8147e3aa3a36f0cb0a19)
---
src/core/linux/SDL_evdev.c | 34 ++++++++++++++++++++--
src/core/linux/SDL_evdev.h | 1 +
src/core/linux/SDL_evdev_kbd.c | 53 ++++++++++++++++++++++------------
src/core/linux/SDL_evdev_kbd.h | 1 +
4 files changed, 69 insertions(+), 20 deletions(-)
diff --git a/src/core/linux/SDL_evdev.c b/src/core/linux/SDL_evdev.c
index f5e713a5734f..22b686051c27 100644
--- a/src/core/linux/SDL_evdev.c
+++ b/src/core/linux/SDL_evdev.c
@@ -66,6 +66,7 @@ typedef struct SDL_evdevlist_item
{
char *path;
int fd;
+ int udev_class;
/* TODO: use this for every device, not just touchscreen */
SDL_bool out_of_sync;
@@ -150,6 +151,15 @@ static int SDL_EVDEV_SetRelativeMouseMode(SDL_bool enabled)
return 0;
}
+static void SDL_EVDEV_UpdateKeyboardMute(void)
+{
+ if (SDL_EVDEV_GetDeviceCount(SDL_UDEV_DEVICE_KEYBOARD) > 0) {
+ SDL_EVDEV_kbd_set_muted(_this->kbd, SDL_TRUE);
+ } else {
+ SDL_EVDEV_kbd_set_muted(_this->kbd, SDL_FALSE);
+ }
+}
+
int SDL_EVDEV_Init(void)
{
if (_this == NULL) {
@@ -203,6 +213,8 @@ int SDL_EVDEV_Init(void)
#endif /* SDL_USE_LIBUDEV */
_this->kbd = SDL_EVDEV_kbd_init();
+
+ SDL_EVDEV_UpdateKeyboardMute();
}
SDL_GetMouse()->SetRelativeMouseMode = SDL_EVDEV_SetRelativeMouseMode;
@@ -226,13 +238,13 @@ void SDL_EVDEV_Quit(void)
SDL_UDEV_Quit();
#endif /* SDL_USE_LIBUDEV */
- SDL_EVDEV_kbd_quit(_this->kbd);
-
/* Remove existing devices */
while (_this->first != NULL) {
SDL_EVDEV_device_removed(_this->first->path);
}
+ SDL_EVDEV_kbd_quit(_this->kbd);
+
SDL_assert(_this->first == NULL);
SDL_assert(_this->last == NULL);
SDL_assert(_this->num_devices == 0);
@@ -271,6 +283,19 @@ static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_cl
}
#endif /* SDL_USE_LIBUDEV */
+int SDL_EVDEV_GetDeviceCount(int device_class)
+{
+ SDL_evdevlist_item *item;
+ int count = 0;
+
+ for (item = _this->first; item != NULL; item = item->next) {
+ if ((item->udev_class & device_class) == device_class) {
+ ++count;
+ }
+ }
+ return count;
+}
+
void SDL_EVDEV_Poll(void)
{
struct input_event events[32];
@@ -847,6 +872,8 @@ static int SDL_EVDEV_device_added(const char *dev_path, int udev_class)
return SDL_OutOfMemory();
}
+ item->udev_class = udev_class;
+
if (ioctl(item->fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0) {
item->relative_mouse = test_bit(REL_X, relbit) && test_bit(REL_Y, relbit);
item->high_res_wheel = test_bit(REL_WHEEL_HI_RES, relbit);
@@ -882,6 +909,8 @@ static int SDL_EVDEV_device_added(const char *dev_path, int udev_class)
SDL_EVDEV_sync_device(item);
+ SDL_EVDEV_UpdateKeyboardMute();
+
return _this->num_devices++;
}
@@ -908,6 +937,7 @@ static int SDL_EVDEV_device_removed(const char *dev_path)
close(item->fd);
SDL_free(item->path);
SDL_free(item);
+ SDL_EVDEV_UpdateKeyboardMute();
_this->num_devices--;
return 0;
}
diff --git a/src/core/linux/SDL_evdev.h b/src/core/linux/SDL_evdev.h
index 2681768bc52c..7f9ac3620b9d 100644
--- a/src/core/linux/SDL_evdev.h
+++ b/src/core/linux/SDL_evdev.h
@@ -30,6 +30,7 @@
extern int SDL_EVDEV_Init(void);
extern void SDL_EVDEV_Quit(void);
+extern int SDL_EVDEV_GetDeviceCount(int device_class);
extern void SDL_EVDEV_Poll(void);
#endif /* SDL_INPUT_LINUXEV */
diff --git a/src/core/linux/SDL_evdev_kbd.c b/src/core/linux/SDL_evdev_kbd.c
index 632bbd248f24..83b5490d8dbc 100644
--- a/src/core/linux/SDL_evdev_kbd.c
+++ b/src/core/linux/SDL_evdev_kbd.c
@@ -85,6 +85,7 @@ static fn_handler_fn *fn_handler[] = {
struct SDL_EVDEV_keyboard_state
{
int console_fd;
+ SDL_bool muted;
int old_kbd_mode;
unsigned short **key_maps;
unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
@@ -333,20 +334,6 @@ SDL_EVDEV_keyboard_state *SDL_EVDEV_kbd_init(void)
ioctl(kbd->console_fd, KDSKBMODE, K_UNICODE);
}
- /* Allow inhibiting keyboard mute with env. variable for debugging etc. */
- if (SDL_getenv("SDL_INPUT_LINUX_KEEP_KBD") == NULL) {
- /* Mute the keyboard so keystrokes only generate evdev events
- * and do not leak through to the console
- */
- ioctl(kbd->console_fd, KDSKBMODE, K_OFF);
-
- /* Make sure to restore keyboard if application fails to call
- * SDL_Quit before exit or fatal signal is raised.
- */
- if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, SDL_FALSE)) {
- kbd_register_emerg_cleanup(kbd);
- }
- }
return kbd;
}
@@ -356,12 +343,9 @@ void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state)
return;
}
- kbd_unregister_emerg_cleanup();
+ SDL_EVDEV_kbd_set_muted(state, SDL_FALSE);
if (state->console_fd >= 0) {
- /* Restore the original keyboard mode */
- ioctl(state->console_fd, KDSKBMODE, state->old_kbd_mode);
-
close(state->console_fd);
state->console_fd = -1;
}
@@ -379,6 +363,39 @@ void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state)
SDL_free(state);
}
+void SDL_EVDEV_kbd_set_muted(SDL_EVDEV_keyboard_state *state, SDL_bool muted)
+{
+ if (state == NULL) {
+ return;
+ }
+
+ if (muted == state->muted) {
+ return;
+ }
+
+ if (muted) {
+ /* Allow inhibiting keyboard mute with env. variable for debugging etc. */
+ if (SDL_getenv("SDL_INPUT_LINUX_KEEP_KBD") == NULL) {
+ /* Mute the keyboard so keystrokes only generate evdev events
+ * and do not leak through to the console
+ */
+ ioctl(state->console_fd, KDSKBMODE, K_OFF);
+
+ /* Make sure to restore keyboard if application fails to call
+ * SDL_Quit before exit or fatal signal is raised.
+ */
+ if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, SDL_FALSE)) {
+ kbd_register_emerg_cleanup(state);
+ }
+ }
+ } else {
+ kbd_unregister_emerg_cleanup();
+
+ /* Restore the original keyboard mode */
+ ioctl(state->console_fd, KDSKBMODE, state->old_kbd_mode);
+ }
+}
+
/*
* Helper Functions.
*/
diff --git a/src/core/linux/SDL_evdev_kbd.h b/src/core/linux/SDL_evdev_kbd.h
index 8105ab8be190..cb4b6da10ddf 100644
--- a/src/core/linux/SDL_evdev_kbd.h
+++ b/src/core/linux/SDL_evdev_kbd.h
@@ -26,6 +26,7 @@ struct SDL_EVDEV_keyboard_state;
typedef struct SDL_EVDEV_keyboard_state SDL_EVDEV_keyboard_state;
extern SDL_EVDEV_keyboard_state *SDL_EVDEV_kbd_init(void);
+extern void SDL_EVDEV_kbd_set_muted(SDL_EVDEV_keyboard_state *state, SDL_bool muted);
extern void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down);
extern void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state);