aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2024-11-24 18:25:58 +0100
committerdec05eba <dec05eba@protonmail.com>2024-11-24 18:33:57 +0100
commit734280f3042a1b2d08764599d1decdee2d4d3132 (patch)
tree4f72eb3aee2f8a98c05e4554f137f6e296fb2018 /src
parent56a7e558d290d168a906dba984f5051c1e327712 (diff)
Use linux /dev/input for global hotkeys instead of x11. This also works on wayland on any compositor
Diffstat (limited to 'src')
-rw-r--r--src/GlobalHotkeysLinux.cpp108
-rw-r--r--src/main.cpp49
2 files changed, 150 insertions, 7 deletions
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 <signal.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <string.h>
+
+#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 <unistd.h>
@@ -98,33 +99,67 @@ int main(void) {
auto overlay = std::make_unique<gsr::Overlay>(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();
});