mirror of
https://repo.dec05eba.com/gpu-screen-recorder-ui
synced 2026-03-31 09:17:04 +09:00
Support keyboard led indicator on wayland as well
This commit is contained in:
2
TODO
2
TODO
@@ -245,4 +245,4 @@ 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.
|
Show a question mark beside options. When hovering the question mark show a tooltip that explains the options.
|
||||||
|
|
||||||
Make led indicator work on wayland (set led with /sys/... blabla with root access). Maybe add a command in gsr-global-hotkeys for that, set_led true/false <led name>. That should loop all input devices and set their led status for the led name.
|
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.
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <sys/types.h>
|
||||||
#include <mglpp/system/Clock.hpp>
|
#include <mglpp/system/Clock.hpp>
|
||||||
|
|
||||||
namespace gsr {
|
namespace gsr {
|
||||||
class LedIndicator {
|
class LedIndicator {
|
||||||
public:
|
public:
|
||||||
LedIndicator(Display *dpy);
|
LedIndicator();
|
||||||
LedIndicator(const LedIndicator&) = delete;
|
LedIndicator(const LedIndicator&) = delete;
|
||||||
LedIndicator& operator=(const LedIndicator&) = delete;
|
LedIndicator& operator=(const LedIndicator&) = delete;
|
||||||
~LedIndicator();
|
~LedIndicator();
|
||||||
@@ -15,10 +15,10 @@ namespace gsr {
|
|||||||
void blink();
|
void blink();
|
||||||
void update();
|
void update();
|
||||||
private:
|
private:
|
||||||
|
bool run_gsr_global_hotkeys_set_leds(bool enabled);
|
||||||
void update_led(bool new_state);
|
void update_led(bool new_state);
|
||||||
private:
|
private:
|
||||||
Display *dpy = nullptr;
|
pid_t gsr_global_hotkeys_pid = -1;
|
||||||
Atom scroll_lock_atom = None;
|
|
||||||
bool led_indicator_on = false;
|
bool led_indicator_on = false;
|
||||||
bool led_enabled = false;
|
bool led_enabled = false;
|
||||||
bool perform_blink = false;
|
bool perform_blink = false;
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ executable(
|
|||||||
'tools/gsr-global-hotkeys/hotplug.c',
|
'tools/gsr-global-hotkeys/hotplug.c',
|
||||||
'tools/gsr-global-hotkeys/keyboard_event.c',
|
'tools/gsr-global-hotkeys/keyboard_event.c',
|
||||||
'tools/gsr-global-hotkeys/keys.c',
|
'tools/gsr-global-hotkeys/keys.c',
|
||||||
|
'tools/gsr-global-hotkeys/leds.c',
|
||||||
'tools/gsr-global-hotkeys/main.c'
|
'tools/gsr-global-hotkeys/main.c'
|
||||||
],
|
],
|
||||||
c_args : '-fstack-protector-all',
|
c_args : '-fstack-protector-all',
|
||||||
|
|||||||
@@ -231,8 +231,8 @@ namespace gsr {
|
|||||||
{"record.record_options.overclock", &config.record_config.record_options.overclock},
|
{"record.record_options.overclock", &config.record_config.record_options.overclock},
|
||||||
{"record.record_options.record_cursor", &config.record_config.record_options.record_cursor},
|
{"record.record_options.record_cursor", &config.record_config.record_options.record_cursor},
|
||||||
{"record.record_options.restore_portal_session", &config.record_config.record_options.restore_portal_session},
|
{"record.record_options.restore_portal_session", &config.record_config.record_options.restore_portal_session},
|
||||||
{"record.record_options.show_notifications", &config.replay_config.record_options.show_notifications},
|
{"record.record_options.show_notifications", &config.record_config.record_options.show_notifications},
|
||||||
{"record.record_options.use_led_indicator", &config.replay_config.record_options.use_led_indicator},
|
{"record.record_options.use_led_indicator", &config.record_config.record_options.use_led_indicator},
|
||||||
{"record.save_video_in_game_folder", &config.record_config.save_video_in_game_folder},
|
{"record.save_video_in_game_folder", &config.record_config.save_video_in_game_folder},
|
||||||
{"record.save_directory", &config.record_config.save_directory},
|
{"record.save_directory", &config.record_config.save_directory},
|
||||||
{"record.container", &config.record_config.container},
|
{"record.container", &config.record_config.container},
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
#include "../include/LedIndicator.hpp"
|
#include "../include/LedIndicator.hpp"
|
||||||
|
|
||||||
#include <X11/XKBlib.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
namespace gsr {
|
namespace gsr {
|
||||||
LedIndicator::LedIndicator(Display *dpy) : dpy(dpy) {
|
LedIndicator::LedIndicator() {
|
||||||
scroll_lock_atom = XInternAtom(dpy, "Scroll Lock", False);
|
run_gsr_global_hotkeys_set_leds(false);
|
||||||
XkbSetNamedIndicator(dpy, scroll_lock_atom, True, False, False, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LedIndicator::~LedIndicator() {
|
LedIndicator::~LedIndicator() {
|
||||||
XkbSetNamedIndicator(dpy, scroll_lock_atom, True, False, False, NULL);
|
run_gsr_global_hotkeys_set_leds(false);
|
||||||
|
if(gsr_global_hotkeys_pid > 0) {
|
||||||
|
int status;
|
||||||
|
waitpid(gsr_global_hotkeys_pid, &status, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LedIndicator::set_led(bool enabled) {
|
void LedIndicator::set_led(bool enabled) {
|
||||||
@@ -22,12 +28,48 @@ namespace gsr {
|
|||||||
blink_timer.restart();
|
blink_timer.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LedIndicator::run_gsr_global_hotkeys_set_leds(bool enabled) {
|
||||||
|
if(gsr_global_hotkeys_pid > 0) {
|
||||||
|
int status;
|
||||||
|
if(waitpid(gsr_global_hotkeys_pid, &status, WNOHANG) == 0) {
|
||||||
|
// Still running
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
gsr_global_hotkeys_pid = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool inside_flatpak = getenv("FLATPAK_ID") != NULL;
|
||||||
|
const char *user_homepath = getenv("HOME");
|
||||||
|
if(!user_homepath)
|
||||||
|
user_homepath = "/tmp";
|
||||||
|
|
||||||
|
gsr_global_hotkeys_pid = vfork();
|
||||||
|
if(gsr_global_hotkeys_pid == -1) {
|
||||||
|
fprintf(stderr, "Error: LedIndicator::run_gsr_global_hotkeys_set_leds: failed to fork\n");
|
||||||
|
return false;
|
||||||
|
} else if(gsr_global_hotkeys_pid == 0) { // Child
|
||||||
|
if(inside_flatpak) {
|
||||||
|
const char *args[] = { "flatpak-spawn", "--host", "/var/lib/flatpak/app/com.dec05eba.gpu_screen_recorder/current/active/files/bin/kms-server-proxy", "launch-gsr-global-hotkeys", user_homepath, "--set-led", "Scroll Lock", enabled ? "on" : "off", nullptr };
|
||||||
|
execvp(args[0], (char* const*)args);
|
||||||
|
} else {
|
||||||
|
const char *args[] = { "gsr-global-hotkeys", "--set-led", "Scroll Lock", enabled ? "on" : "off", nullptr };
|
||||||
|
execvp(args[0], (char* const*)args);
|
||||||
|
}
|
||||||
|
|
||||||
|
perror("gsr-global-hotkeys");
|
||||||
|
_exit(127);
|
||||||
|
return true;
|
||||||
|
} else { // Parent
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LedIndicator::update_led(bool new_state) {
|
void LedIndicator::update_led(bool new_state) {
|
||||||
if(new_state == led_indicator_on)
|
if(new_state == led_indicator_on)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
led_indicator_on = new_state;
|
if(run_gsr_global_hotkeys_set_leds(new_state))
|
||||||
XkbSetNamedIndicator(dpy, scroll_lock_atom, True, new_state, False, NULL);
|
led_indicator_on = new_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LedIndicator::update() {
|
void LedIndicator::update() {
|
||||||
|
|||||||
@@ -522,8 +522,8 @@ namespace gsr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(x11_dpy)
|
// TODO: Only do this if led indicator is enabled (at startup or when changing recording/screenshot settings to enabled it)
|
||||||
led_indicator = std::make_unique<LedIndicator>(x11_dpy);
|
led_indicator = std::make_unique<LedIndicator>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Overlay::~Overlay() {
|
Overlay::~Overlay() {
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ namespace gsr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Widget> ScreenshotSettingsPage::create_led_indicator() {
|
std::unique_ptr<Widget> ScreenshotSettingsPage::create_led_indicator() {
|
||||||
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, gsr_info->system_info.display_server == DisplayServer::X11 ? "Blink scroll lock led when taking a screenshot" : "Blink scroll lock led when taking a screenshot (not supported by Wayland)");
|
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Blink scroll lock led when taking a screenshot");
|
||||||
checkbox->set_checked(true);
|
checkbox->set_checked(true);
|
||||||
led_indicator_checkbox_ptr = checkbox.get();
|
led_indicator_checkbox_ptr = checkbox.get();
|
||||||
return checkbox;
|
return checkbox;
|
||||||
|
|||||||
@@ -832,10 +832,7 @@ namespace gsr {
|
|||||||
|
|
||||||
std::unique_ptr<CheckBox> SettingsPage::create_led_indicator(const char *type) {
|
std::unique_ptr<CheckBox> SettingsPage::create_led_indicator(const char *type) {
|
||||||
char label_str[256];
|
char label_str[256];
|
||||||
if(gsr_info->system_info.display_server == DisplayServer::X11)
|
snprintf(label_str, sizeof(label_str), "Show %s status with scroll lock led", type);
|
||||||
snprintf(label_str, sizeof(label_str), "Show %s status with scroll lock led", type);
|
|
||||||
else
|
|
||||||
snprintf(label_str, sizeof(label_str), "Show %s status with scroll lock led (not supported by Wayland)", type);
|
|
||||||
|
|
||||||
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, label_str);
|
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, label_str);
|
||||||
checkbox->set_checked(false);
|
checkbox->set_checked(false);
|
||||||
|
|||||||
@@ -237,6 +237,17 @@ static void keyboard_event_process_input_event_data(keyboard_event *self, event_
|
|||||||
fprintf(stderr, "Error: failed to write event data to virtual keyboard for exclusively grabbed device\n");
|
fprintf(stderr, "Error: failed to write event data to virtual keyboard for exclusively grabbed device\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(event.type == EV_LED) {
|
||||||
|
write(fd, &event, sizeof(event));
|
||||||
|
|
||||||
|
const struct input_event syn_event = {
|
||||||
|
.type = EV_SYN,
|
||||||
|
.code = 0,
|
||||||
|
.value = 0
|
||||||
|
};
|
||||||
|
write(fd, &syn_event, sizeof(syn_event));
|
||||||
|
}
|
||||||
|
|
||||||
if(!extra_data->is_possibly_non_keyboard_device)
|
if(!extra_data->is_possibly_non_keyboard_device)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -389,7 +400,7 @@ static bool keyboard_event_try_add_device_if_keyboard(keyboard_event *self, cons
|
|||||||
if(keyboard_event_has_event_with_dev_input_fd(self, dev_input_id))
|
if(keyboard_event_has_event_with_dev_input_fd(self, dev_input_id))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const int fd = open(dev_input_filepath, O_RDONLY);
|
const int fd = open(dev_input_filepath, O_RDWR);
|
||||||
if(fd == -1)
|
if(fd == -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -553,10 +564,12 @@ static int setup_virtual_keyboard_input(const char *name) {
|
|||||||
if(is_keyboard_key(i) || is_mouse_button(i))
|
if(is_keyboard_key(i) || is_mouse_button(i))
|
||||||
success &= (ioctl(fd, UI_SET_KEYBIT, i) != -1);
|
success &= (ioctl(fd, UI_SET_KEYBIT, i) != -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < REL_MAX; ++i) {
|
for(int i = 0; i < REL_MAX; ++i) {
|
||||||
success &= (ioctl(fd, UI_SET_RELBIT, i) != -1);
|
success &= (ioctl(fd, UI_SET_RELBIT, i) != -1);
|
||||||
}
|
}
|
||||||
// for(int i = 0; i < LED_MAX; ++i) {
|
|
||||||
|
// for(int i = 0; i <= LED_CHARGING; ++i) {
|
||||||
// success &= (ioctl(fd, UI_SET_LEDBIT, i) != -1);
|
// success &= (ioctl(fd, UI_SET_LEDBIT, i) != -1);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@@ -635,6 +648,22 @@ bool keyboard_event_init(keyboard_event *self, bool exclusive_grab, keyboard_gra
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self->event_polls[self->num_event_polls] = (struct pollfd) {
|
||||||
|
.fd = self->timer_fd,
|
||||||
|
.events = POLLIN,
|
||||||
|
.revents = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
self->event_extra_data[self->num_event_polls] = (event_extra_data) {
|
||||||
|
.dev_input_id = -1,
|
||||||
|
.grabbed = false,
|
||||||
|
.key_states = NULL,
|
||||||
|
.key_presses_grabbed = NULL,
|
||||||
|
.num_keys_pressed = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
++self->num_event_polls;
|
||||||
|
|
||||||
/* 0.5 seconds */
|
/* 0.5 seconds */
|
||||||
const struct itimerspec timer_value = {
|
const struct itimerspec timer_value = {
|
||||||
.it_value = (struct timespec) {
|
.it_value = (struct timespec) {
|
||||||
@@ -653,22 +682,6 @@ bool keyboard_event_init(keyboard_event *self, bool exclusive_grab, keyboard_gra
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->event_polls[self->num_event_polls] = (struct pollfd) {
|
|
||||||
.fd = self->timer_fd,
|
|
||||||
.events = POLLIN,
|
|
||||||
.revents = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
self->event_extra_data[self->num_event_polls] = (event_extra_data) {
|
|
||||||
.dev_input_id = -1,
|
|
||||||
.grabbed = false,
|
|
||||||
.key_states = NULL,
|
|
||||||
.key_presses_grabbed = NULL,
|
|
||||||
.num_keys_pressed = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
++self->num_event_polls;
|
|
||||||
|
|
||||||
self->uinput_written_time_seconds = clock_get_monotonic_seconds();
|
self->uinput_written_time_seconds = clock_get_monotonic_seconds();
|
||||||
|
|
||||||
if(hotplug_event_init(&self->hotplug_ev)) {
|
if(hotplug_event_init(&self->hotplug_ev)) {
|
||||||
@@ -717,11 +730,6 @@ void keyboard_event_deinit(keyboard_event *self) {
|
|||||||
self->uinput_fd = -1;
|
self->uinput_fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(self->timer_fd > 0) {
|
|
||||||
close(self->timer_fd);
|
|
||||||
self->timer_fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < self->num_event_polls; ++i) {
|
for(int i = 0; i < self->num_event_polls; ++i) {
|
||||||
if(self->event_polls[i].fd > 0) {
|
if(self->event_polls[i].fd > 0) {
|
||||||
ioctl(self->event_polls[i].fd, EVIOCGRAB, 0);
|
ioctl(self->event_polls[i].fd, EVIOCGRAB, 0);
|
||||||
|
|||||||
139
tools/gsr-global-hotkeys/leds.c
Normal file
139
tools/gsr-global-hotkeys/leds.c
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
#include "leds.h"
|
||||||
|
|
||||||
|
/* C stdlib */
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* POSIX */
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/* LINUX */
|
||||||
|
#include <linux/input.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
if(fd == -1) {
|
||||||
|
fprintf(stderr, "Warning: get_max_brightness open error: %s\n", strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
int max_brightness = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool string_starts_with(const char *str, const char *sub) {
|
||||||
|
const int str_len = strlen(str);
|
||||||
|
const int sub_len = strlen(sub);
|
||||||
|
return str_len >= sub_len && memcmp(str, sub, sub_len) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool string_ends_with(const char *str, const char *sub) {
|
||||||
|
const int str_len = strlen(str);
|
||||||
|
const int sub_len = strlen(sub);
|
||||||
|
return str_len >= sub_len && memcmp(str + str_len - sub_len, sub, sub_len) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sys_class_led_path_get_event_number(const char *sys_class_path, const char *filename) {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
snprintf(path, sizeof(path), "%s/%s/device", sys_class_path, filename);
|
||||||
|
|
||||||
|
DIR *dir = opendir(path);
|
||||||
|
if(!dir)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int event_number = -1;
|
||||||
|
struct dirent *entry;
|
||||||
|
while((entry = readdir(dir)) != NULL) {
|
||||||
|
int v = -1;
|
||||||
|
if(sscanf(entry->d_name, "event%d", &v) == 1 && v >= 0) {
|
||||||
|
event_number = v;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
return event_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
We have to do this retardation instead of setting /sys/class/leds brightness since it doesn't work with /dev/uinput
|
||||||
|
and we cant loop all /dev/input devices and open and write to them either since closing a /dev/input is very slow on linux.
|
||||||
|
So we instead check which devices have the led before opening it.
|
||||||
|
*/
|
||||||
|
static bool set_device_leds(const char *led_name_path, bool enabled) {
|
||||||
|
DIR *dir = opendir("/sys/class/leds");
|
||||||
|
if(!dir)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char dev_input_filepath[1024];
|
||||||
|
struct dirent *entry;
|
||||||
|
while((entry = readdir(dir)) != NULL) {
|
||||||
|
if(entry->d_name[0] == '.')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!string_starts_with(entry->d_name, "input") || !string_ends_with(entry->d_name, led_name_path))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const int event_number = sys_class_led_path_get_event_number("/sys/class/leds", entry->d_name);
|
||||||
|
if(event_number == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(dev_input_filepath, sizeof(dev_input_filepath), "/dev/input/event%d", event_number);
|
||||||
|
|
||||||
|
const int device_fd = open(dev_input_filepath, O_WRONLY);
|
||||||
|
if(device_fd == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int brightness = 0;
|
||||||
|
if(enabled) {
|
||||||
|
brightness = get_max_brightness("/sys/class/leds", entry->d_name);
|
||||||
|
if(brightness < 0)
|
||||||
|
brightness = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct input_event led_data = {
|
||||||
|
.type = EV_LED,
|
||||||
|
.code = LED_SCROLLL,
|
||||||
|
.value = brightness
|
||||||
|
};
|
||||||
|
write(device_fd, &led_data, sizeof(led_data));
|
||||||
|
|
||||||
|
struct input_event syn_data = {
|
||||||
|
.type = EV_SYN,
|
||||||
|
.code = 0,
|
||||||
|
.value = 0
|
||||||
|
};
|
||||||
|
write(device_fd, &syn_data, sizeof(syn_data));
|
||||||
|
|
||||||
|
close(device_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_leds(const char *led_name, bool enabled) {
|
||||||
|
if(strcmp(led_name, "Scroll Lock") == 0) {
|
||||||
|
return set_device_leds("::scrolllock", enabled);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error: invalid led: \"%s\", expected \"Scroll Lock\"\n", led_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
tools/gsr-global-hotkeys/leds.h
Normal file
9
tools/gsr-global-hotkeys/leds.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef LEDS_H
|
||||||
|
#define LEDS_H
|
||||||
|
|
||||||
|
/* C stdlib */
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
bool set_leds(const char *led_name, bool enabled);
|
||||||
|
|
||||||
|
#endif /* LEDS_H */
|
||||||
@@ -1,19 +1,26 @@
|
|||||||
#include "keyboard_event.h"
|
#include "keyboard_event.h"
|
||||||
|
#include "leds.h"
|
||||||
|
|
||||||
/* C stdlib */
|
/* C stdlib */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/* POSIX */
|
/* POSIX */
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
static void usage(void) {
|
static void usage(void) {
|
||||||
fprintf(stderr, "usage: gsr-global-hotkeys [--all|--virtual]\n");
|
fprintf(stderr, "usage: gsr-global-hotkeys [--all|--virtual|--no-grab|--set-led] [Scroll Lock] [on|off]\n");
|
||||||
fprintf(stderr, "OPTIONS:\n");
|
fprintf(stderr, "OPTIONS:\n");
|
||||||
fprintf(stderr, " --all Grab all devices.\n");
|
fprintf(stderr, " --all Grab all devices.\n");
|
||||||
fprintf(stderr, " --virtual Grab all virtual devices only.\n");
|
fprintf(stderr, " --virtual Grab all virtual devices only.\n");
|
||||||
fprintf(stderr, " --no-grab Don't grab devices, only listen to them.\n");
|
fprintf(stderr, " --no-grab Don't grab devices, only listen to them.\n");
|
||||||
|
fprintf(stderr, " --set-led Turn device led on/off.\n");
|
||||||
|
fprintf(stderr, "EXAMPLES:\n");
|
||||||
|
fprintf(stderr, " gsr-global-hotkeys --all\n");
|
||||||
|
fprintf(stderr, " gsr-global-hotkeys --set-led \"Scroll Lock\" on\n");
|
||||||
|
fprintf(stderr, " gsr-global-hotkeys --set-led \"Scroll Lock\" off\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_gsr_global_hotkeys_already_running(void) {
|
static bool is_gsr_global_hotkeys_already_running(void) {
|
||||||
@@ -38,6 +45,8 @@ int main(int argc, char **argv) {
|
|||||||
setlocale(LC_ALL, "C"); /* Sigh... stupid C */
|
setlocale(LC_ALL, "C"); /* Sigh... stupid C */
|
||||||
|
|
||||||
keyboard_grab_type grab_type = KEYBOARD_GRAB_TYPE_ALL;
|
keyboard_grab_type grab_type = KEYBOARD_GRAB_TYPE_ALL;
|
||||||
|
const uid_t user_id = getuid();
|
||||||
|
|
||||||
if(argc == 2) {
|
if(argc == 2) {
|
||||||
const char *grab_type_arg = argv[1];
|
const char *grab_type_arg = argv[1];
|
||||||
if(strcmp(grab_type_arg, "--all") == 0) {
|
if(strcmp(grab_type_arg, "--all") == 0) {
|
||||||
@@ -46,11 +55,42 @@ int main(int argc, char **argv) {
|
|||||||
grab_type = KEYBOARD_GRAB_TYPE_VIRTUAL;
|
grab_type = KEYBOARD_GRAB_TYPE_VIRTUAL;
|
||||||
} else if(strcmp(grab_type_arg, "--no-grab") == 0) {
|
} else if(strcmp(grab_type_arg, "--no-grab") == 0) {
|
||||||
grab_type = KEYBOARD_GRAB_TYPE_NO_GRAB;
|
grab_type = KEYBOARD_GRAB_TYPE_NO_GRAB;
|
||||||
|
} else if(strcmp(grab_type_arg, "--set-led") == 0) {
|
||||||
|
fprintf(stderr, "Error: missing led name and on/off argument to --set-led\n");
|
||||||
|
usage();
|
||||||
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "gsr-global-hotkeys error: expected --all, --virtual or --no-grab, got %s\n", grab_type_arg);
|
fprintf(stderr, "gsr-global-hotkeys error: expected --all, --virtual, --no-grab or --set-led, got %s\n", grab_type_arg);
|
||||||
usage();
|
usage();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
} else if(argc == 4) {
|
||||||
|
/* It's not ideal to use gsr-global-hotkeys for leds, but we do that for now because it's a mess to create another binary for flatpak and distros */
|
||||||
|
const char *led_name = argv[2];
|
||||||
|
const char *led_enabled_str = argv[3];
|
||||||
|
bool led_enabled = false;
|
||||||
|
|
||||||
|
if(strcmp(led_enabled_str, "on") == 0) {
|
||||||
|
led_enabled = true;
|
||||||
|
} else if(strcmp(led_enabled_str, "off") == 0) {
|
||||||
|
led_enabled = false;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error: expected \"on\" or \"off\" for --set-led option, got: \"%s\"", led_enabled_str);
|
||||||
|
usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(geteuid() != 0) {
|
||||||
|
if(setuid(0) == -1) {
|
||||||
|
fprintf(stderr, "gsr-global-hotkeys error: failed to change user to root, global hotkeys will not work. Make sure to set the correct capability on gsr-global-hotkeys\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool success = set_leds(led_name, led_enabled);
|
||||||
|
setuid(user_id);
|
||||||
|
|
||||||
|
return success ? 0 : 1;
|
||||||
} else if(argc != 1) {
|
} else if(argc != 1) {
|
||||||
fprintf(stderr, "gsr-global-hotkeys error: expected 0 or 1 arguments, got %d argument(s)\n", argc);
|
fprintf(stderr, "gsr-global-hotkeys error: expected 0 or 1 arguments, got %d argument(s)\n", argc);
|
||||||
usage();
|
usage();
|
||||||
@@ -62,7 +102,6 @@ int main(int argc, char **argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uid_t user_id = getuid();
|
|
||||||
if(geteuid() != 0) {
|
if(geteuid() != 0) {
|
||||||
if(setuid(0) == -1) {
|
if(setuid(0) == -1) {
|
||||||
fprintf(stderr, "gsr-global-hotkeys error: failed to change user to root, global hotkeys will not work. Make sure to set the correct capability on gsr-global-hotkeys\n");
|
fprintf(stderr, "gsr-global-hotkeys error: failed to change user to root, global hotkeys will not work. Make sure to set the correct capability on gsr-global-hotkeys\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user