From 250675024332b6b08078a81bcef1e5355b916255 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 8 Nov 2025 13:24:40 +0100 Subject: [PATCH] Fix leds getting unset when closing the program --- TODO | 7 ++- meson.build | 4 +- project.conf | 2 +- tools/gsr-global-hotkeys/keyboard_event.c | 42 +++++++++++++++- tools/gsr-global-hotkeys/leds.c | 60 +++++++++++++++++++---- tools/gsr-global-hotkeys/leds.h | 8 +++ 6 files changed, 105 insertions(+), 18 deletions(-) diff --git a/TODO b/TODO index e6b1d2a..4f31974 100644 --- a/TODO +++ b/TODO @@ -84,9 +84,6 @@ Dont put widget position to int position when scrolling. This makes the UI jitte Show warning if another instance of gpu screen recorder is already running when starting recording? -Keyboard leds get turned off when stopping gsr-global-hotkeys (for example numlock). The numlock key has to be pressed twice again to make it look correct to match its state. - Fix this by writing 0 or 1 to /sys/class/leds/input2::numlock/brightness. - Make gsr-ui flatpak systemd work nicely with non-flatpak gsr-ui. Maybe change ExecStart to do flatpak run ... || gsr-ui, but make it run as a shell command first with /bin/sh -c "". When enabling X11 global hotkey again only grab lalt, not ralt. @@ -245,4 +242,6 @@ Show the currently recorded capture in the ui, to preview if everything looks ok Show a question mark beside options. When hovering the question mark show a tooltip that explains the options. -Remove all mgl::Clock usage in Overlay. We only need to get the time once per update in Overlay::handle_events. Also get time in other places outside handle_events. \ No newline at end of file +Remove all mgl::Clock usage in Overlay. We only need to get the time once per update in Overlay::handle_events. Also get time in other places outside handle_events. + +Handle stopping replay/stream when recording is running (show notification that the video is saved and move the video to folder with game name). diff --git a/meson.build b/meson.build index ba74e5e..a33468f 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('gsr-ui', ['c', 'cpp'], version : '1.7.9', default_options : ['warning_level=2', 'cpp_std=c++17'], subproject_dir : 'depends') +project('gsr-ui', ['c', 'cpp'], version : '1.8.0', default_options : ['warning_level=2', 'cpp_std=c++17'], subproject_dir : 'depends') add_project_arguments('-D_FILE_OFFSET_BITS=64', language : ['c', 'cpp']) @@ -66,7 +66,7 @@ datadir = get_option('datadir') gsr_ui_resources_path = join_paths(prefix, datadir, 'gsr-ui') add_project_arguments('-DGSR_UI_VERSION="' + meson.project_version() + '"', language: ['c', 'cpp']) -add_project_arguments('-DGSR_FLATPAK_VERSION="5.8.4"', language: ['c', 'cpp']) +add_project_arguments('-DGSR_FLATPAK_VERSION="5.8.5"', language: ['c', 'cpp']) executable( meson.project_name(), diff --git a/project.conf b/project.conf index ae8d781..6d9685b 100644 --- a/project.conf +++ b/project.conf @@ -1,7 +1,7 @@ [package] name = "gsr-ui" type = "executable" -version = "1.7.9" +version = "1.8.0" platforms = ["posix"] [lang.cpp] diff --git a/tools/gsr-global-hotkeys/keyboard_event.c b/tools/gsr-global-hotkeys/keyboard_event.c index ac85a68..f36d101 100644 --- a/tools/gsr-global-hotkeys/keyboard_event.c +++ b/tools/gsr-global-hotkeys/keyboard_event.c @@ -1,5 +1,6 @@ #include "keyboard_event.h" #include "keys.h" +#include "leds.h" /* C stdlib */ #include @@ -716,6 +717,41 @@ bool keyboard_event_init(keyboard_event *self, bool exclusive_grab, keyboard_gra return true; } +static void write_led_data_to_device(int fd, uint16_t led, int value) { + struct input_event led_data = { + .type = EV_LED, + .code = led, + .value = value + }; + write(fd, &led_data, sizeof(led_data)); + + struct input_event syn_data = { + .type = EV_SYN, + .code = 0, + .value = 0 + }; + write(fd, &syn_data, sizeof(syn_data)); +} + +/* When the device is ungrabbed the leds are unset for some reason. Set them back to their previous brightness */ +static void keyboard_event_device_deinit(int fd, event_extra_data *extra_data) { + ggh_leds leds; + const bool got_leds = get_leds(extra_data->dev_input_id, &leds); + + ioctl(fd, EVIOCGRAB, 0); + if(got_leds) { + if(leds.scroll_lock_brightness >= 0) + write_led_data_to_device(fd, LED_SCROLLL, leds.scroll_lock_brightness); + + if(leds.num_lock_brightness >= 0) + write_led_data_to_device(fd, LED_NUML, leds.num_lock_brightness); + + if(leds.caps_lock_brightness >= 0) + write_led_data_to_device(fd, LED_CAPSL, leds.caps_lock_brightness); + } + close(fd); +} + void keyboard_event_deinit(keyboard_event *self) { self->running = false; @@ -732,8 +768,10 @@ void keyboard_event_deinit(keyboard_event *self) { for(int i = 0; i < self->num_event_polls; ++i) { if(self->event_polls[i].fd > 0) { - ioctl(self->event_polls[i].fd, EVIOCGRAB, 0); - close(self->event_polls[i].fd); + if(self->event_extra_data[i].dev_input_id > 0 && !self->event_extra_data[i].gsr_ui_virtual_keyboard) + keyboard_event_device_deinit(self->event_polls[i].fd, &self->event_extra_data[i]); + else + close(self->event_polls[i].fd); } free(self->event_extra_data[i].key_states); free(self->event_extra_data[i].key_presses_grabbed); diff --git a/tools/gsr-global-hotkeys/leds.c b/tools/gsr-global-hotkeys/leds.c index cc3550a..4f5c238 100644 --- a/tools/gsr-global-hotkeys/leds.c +++ b/tools/gsr-global-hotkeys/leds.c @@ -15,27 +15,37 @@ /* LINUX */ #include -static int get_max_brightness(const char *sys_class_path, const char *filename) { - char path[PATH_MAX]; - snprintf(path, sizeof(path), "%s/%s/max_brightness", sys_class_path, filename); - - const int fd = open(path, O_RDONLY); +/* Returns -1 on error */ +static int read_int_from_file(const char *filepath) { + const int fd = open(filepath, O_RDONLY); if(fd == -1) { fprintf(stderr, "Warning: get_max_brightness open error: %s\n", strerror(errno)); - return false; + return -1; } bool success = false; - int max_brightness = 0; + int value = 0; char buffer[32]; const ssize_t num_bytes_read = read(fd, buffer, sizeof(buffer)); if(num_bytes_read > 0) { buffer[num_bytes_read] = '\0'; - success = sscanf(buffer, "%d", &max_brightness) == 1; + success = sscanf(buffer, "%d", &value) == 1; } close(fd); - return success; + return success ? value : -1; +} + +static int get_max_brightness(const char *sys_class_path, const char *filename) { + char path[PATH_MAX]; + snprintf(path, sizeof(path), "%s/%s/max_brightness", sys_class_path, filename); + return read_int_from_file(path); +} + +static int get_brightness(const char *sys_class_path, const char *filename) { + char path[PATH_MAX]; + snprintf(path, sizeof(path), "%s/%s/brightness", sys_class_path, filename); + return read_int_from_file(path); } static bool string_starts_with(const char *str, const char *sub) { @@ -137,3 +147,35 @@ bool set_leds(const char *led_name, bool enabled) { return false; } } + +bool get_leds(int event_number, ggh_leds *leds) { + leds->scroll_lock_brightness = -1; + leds->num_lock_brightness = -1; + leds->caps_lock_brightness = -1; + + char path[PATH_MAX]; + snprintf(path, sizeof(path), "/sys/class/input/event%d/device", event_number); + + DIR *dir = opendir(path); + if(!dir) + return false; + + struct dirent *entry; + while((entry = readdir(dir)) != NULL) { + if(entry->d_name[0] == '.') + continue; + + if(!string_starts_with(entry->d_name, "input")) + continue; + + if(string_ends_with(entry->d_name, "::scrolllock")) + leds->scroll_lock_brightness = get_brightness(path, entry->d_name); + else if(string_ends_with(entry->d_name, "::numlock")) + leds->num_lock_brightness = get_brightness(path, entry->d_name); + else if(string_ends_with(entry->d_name, "::capslock")) + leds->caps_lock_brightness = get_brightness(path, entry->d_name); + } + + closedir(dir); + return true; +} diff --git a/tools/gsr-global-hotkeys/leds.h b/tools/gsr-global-hotkeys/leds.h index 7373e55..18d711a 100644 --- a/tools/gsr-global-hotkeys/leds.h +++ b/tools/gsr-global-hotkeys/leds.h @@ -4,6 +4,14 @@ /* C stdlib */ #include +typedef struct { + /* These are set to -1 if not supported */ + int scroll_lock_brightness; + int num_lock_brightness; + int caps_lock_brightness; +} ggh_leds; + bool set_leds(const char *led_name, bool enabled); +bool get_leds(int event_number, ggh_leds *leds); #endif /* LEDS_H */