From 87bb0f5bcbdb30aba1da276f2fa4e7beb8a3e3df Mon Sep 17 00:00:00 2001 From: Sam Lantinga 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 f5e713a57..22b686051 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 2681768bc..7f9ac3620 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 632bbd248..83b5490d8 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 8105ab8be..cb4b6da10 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);