From ce9e1bd32485ae8a024d8147e3aa3a36f0cb0a19 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
---
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 c0bde0d7e92c..453285793831 100644
--- a/src/core/linux/SDL_evdev.c
+++ b/src/core/linux/SDL_evdev.c
@@ -73,6 +73,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;
@@ -155,6 +156,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) {
@@ -208,6 +218,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;
@@ -231,13 +243,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);
@@ -276,6 +288,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];
@@ -864,6 +889,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);
@@ -900,6 +927,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++;
}
@@ -926,6 +955,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 ba58b91aa3a6..b0c6c7ef0e49 100644
--- a/src/core/linux/SDL_evdev.h
+++ b/src/core/linux/SDL_evdev.h
@@ -30,6 +30,7 @@ struct input_event;
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);
extern Uint64 SDL_EVDEV_GetEventTimestamp(struct input_event *event);
diff --git a/src/core/linux/SDL_evdev_kbd.c b/src/core/linux/SDL_evdev_kbd.c
index 2754e51e4d40..a58129dea1a0 100644
--- a/src/core/linux/SDL_evdev_kbd.c
+++ b/src/core/linux/SDL_evdev_kbd.c
@@ -84,6 +84,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.. */
@@ -332,20 +333,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;
}
@@ -355,12 +342,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;
}
@@ -378,6 +362,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 6d592ef28e42..e00ca0b1445a 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);