From 734280f3042a1b2d08764599d1decdee2d4d3132 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 24 Nov 2024 18:25:58 +0100 Subject: Use linux /dev/input for global hotkeys instead of x11. This also works on wayland on any compositor --- src/GlobalHotkeysLinux.cpp | 108 +++++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 49 +++++++++++++++++--- 2 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 src/GlobalHotkeysLinux.cpp (limited to 'src') diff --git a/src/GlobalHotkeysLinux.cpp b/src/GlobalHotkeysLinux.cpp new file mode 100644 index 0000000..975e585 --- /dev/null +++ b/src/GlobalHotkeysLinux.cpp @@ -0,0 +1,108 @@ +#include "../include/GlobalHotkeysLinux.hpp" +#include +#include +#include +#include + +#define PIPE_READ 0 +#define PIPE_WRITE 1 + +namespace gsr { + GlobalHotkeysLinux::GlobalHotkeysLinux() { + for(int i = 0; i < 2; ++i) { + pipes[i] = -1; + } + } + + GlobalHotkeysLinux::~GlobalHotkeysLinux() { + for(int i = 0; i < 2; ++i) { + if(pipes[i] > 0) + close(pipes[i]); + } + + if(read_file) + fclose(read_file); + + if(process_id > 0) { + kill(process_id, SIGKILL); + int status; + waitpid(process_id, &status, 0); + } + } + + bool GlobalHotkeysLinux::start() { + if(process_id > 0) + return false; + + if(pipe(pipes) == -1) + return false; + + const pid_t pid = vfork(); + if(pid == -1) { + perror("Failed to vfork"); + for(int i = 0; i < 2; ++i) { + close(pipes[i]); + pipes[i] = -1; + } + return false; + } else if(pid == 0) { /* child */ + dup2(pipes[PIPE_WRITE], STDOUT_FILENO); + for(int i = 0; i < 2; ++i) { + close(pipes[i]); + } + + const char *args[] = { "gsr-global-hotkeys", NULL }; + execvp(args[0], (char* const*)args); + perror("execvp"); + _exit(127); + } else { /* parent */ + process_id = pid; + close(pipes[PIPE_WRITE]); + pipes[PIPE_WRITE] = -1; + + const int fdl = fcntl(pipes[PIPE_READ], F_GETFL); + fcntl(pipes[PIPE_READ], F_SETFL, fdl | O_NONBLOCK); + + read_file = fdopen(pipes[PIPE_READ], "r"); + if(read_file) + pipes[PIPE_READ] = -1; + else + fprintf(stderr, "fdopen failed, error: %s\n", strerror(errno)); + } + + return true; + } + + bool GlobalHotkeysLinux::bind_action(const std::string &id, GlobalHotkeyCallback callback) { + return bound_actions_by_id.insert(std::make_pair(id, callback)).second; + } + + void GlobalHotkeysLinux::poll_events() { + if(process_id <= 0) { + fprintf(stderr, "error: GlobalHotkeysLinux::poll_events failed, process has not been started yet. Use GlobalHotkeysLinux::start to start the process first\n"); + return; + } + + if(!read_file) { + fprintf(stderr, "error: GlobalHotkeysLinux::poll_events failed, read file hasn't opened\n"); + return; + } + + char buffer[256]; + char *line = fgets(buffer, sizeof(buffer), read_file); + if(!line) + return; + + const int line_len = strlen(line); + if(line_len == 0) + return; + + if(line[line_len - 1] == '\n') + line[line_len - 1] = '\0'; + + const std::string action = line; + auto it = bound_actions_by_id.find(action); + if(it != bound_actions_by_id.end()) + it->second(action); + } +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index c2b7ab0..be2e50d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #include "../include/window_texture.h" #include "../include/Overlay.hpp" #include "../include/GlobalHotkeysX11.hpp" +#include "../include/GlobalHotkeysLinux.hpp" #include "../include/gui/Utils.hpp" #include @@ -98,33 +99,67 @@ int main(void) { auto overlay = std::make_unique(resources_path, gsr_info, egl_funcs); //overlay.show(); - gsr::GlobalHotkeysX11 global_hotkeys; - const bool show_hotkey_registered = global_hotkeys.bind_key_press({ XK_z, Mod1Mask }, "show/hide", [&](const std::string &id) { + // gsr::GlobalHotkeysX11 global_hotkeys; + // const bool show_hotkey_registered = global_hotkeys.bind_key_press({ XK_z, Mod1Mask }, "show_hide", [&](const std::string &id) { + // fprintf(stderr, "pressed %s\n", id.c_str()); + // overlay->toggle_show(); + // }); + + // const bool record_hotkey_registered = global_hotkeys.bind_key_press({ XK_F9, Mod1Mask }, "record", [&](const std::string &id) { + // fprintf(stderr, "pressed %s\n", id.c_str()); + // overlay->toggle_record(); + // }); + + // const bool pause_hotkey_registered = global_hotkeys.bind_key_press({ XK_F7, Mod1Mask }, "pause", [&](const std::string &id) { + // fprintf(stderr, "pressed %s\n", id.c_str()); + // overlay->toggle_pause(); + // }); + + // const bool stream_hotkey_registered = global_hotkeys.bind_key_press({ XK_F8, Mod1Mask }, "stream", [&](const std::string &id) { + // fprintf(stderr, "pressed %s\n", id.c_str()); + // overlay->toggle_stream(); + // }); + + // const bool replay_hotkey_registered = global_hotkeys.bind_key_press({ XK_F10, ShiftMask | Mod1Mask }, "replay start", [&](const std::string &id) { + // fprintf(stderr, "pressed %s\n", id.c_str()); + // overlay->toggle_replay(); + // }); + + // const bool replay_save_hotkey_registered = global_hotkeys.bind_key_press({ XK_F10, Mod1Mask }, "replay save", [&](const std::string &id) { + // fprintf(stderr, "pressed %s\n", id.c_str()); + // overlay->save_replay(); + // }); + + gsr::GlobalHotkeysLinux global_hotkeys; + if(!global_hotkeys.start()) + fprintf(stderr, "error: failed to start global hotkeys\n"); + + const bool show_hotkey_registered = global_hotkeys.bind_action("show_hide", [&](const std::string &id) { fprintf(stderr, "pressed %s\n", id.c_str()); overlay->toggle_show(); }); - const bool record_hotkey_registered = global_hotkeys.bind_key_press({ XK_F9, Mod1Mask }, "record", [&](const std::string &id) { + const bool record_hotkey_registered = global_hotkeys.bind_action("record", [&](const std::string &id) { fprintf(stderr, "pressed %s\n", id.c_str()); overlay->toggle_record(); }); - const bool pause_hotkey_registered = global_hotkeys.bind_key_press({ XK_F7, Mod1Mask }, "pause", [&](const std::string &id) { + const bool pause_hotkey_registered = global_hotkeys.bind_action("pause", [&](const std::string &id) { fprintf(stderr, "pressed %s\n", id.c_str()); overlay->toggle_pause(); }); - const bool stream_hotkey_registered = global_hotkeys.bind_key_press({ XK_F8, Mod1Mask }, "stream", [&](const std::string &id) { + const bool stream_hotkey_registered = global_hotkeys.bind_action("stream", [&](const std::string &id) { fprintf(stderr, "pressed %s\n", id.c_str()); overlay->toggle_stream(); }); - const bool replay_hotkey_registered = global_hotkeys.bind_key_press({ XK_F10, ShiftMask | Mod1Mask }, "replay start", [&](const std::string &id) { + const bool replay_hotkey_registered = global_hotkeys.bind_action("replay_start", [&](const std::string &id) { fprintf(stderr, "pressed %s\n", id.c_str()); overlay->toggle_replay(); }); - const bool replay_save_hotkey_registered = global_hotkeys.bind_key_press({ XK_F10, Mod1Mask }, "replay save", [&](const std::string &id) { + const bool replay_save_hotkey_registered = global_hotkeys.bind_action("replay_save", [&](const std::string &id) { fprintf(stderr, "pressed %s\n", id.c_str()); overlay->save_replay(); }); -- cgit v1.2.3