From 1d9d4d6398e989d0628cb4dab0273293b79b4816 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 23 Jan 2025 21:23:19 +0100 Subject: Make hotkeys reconfigurable, faster hotkey startup time, fix some keyboard locale issues --- README.md | 13 +- TODO | 14 +- depends/mglpp | 2 +- include/Config.hpp | 19 +- include/GlobalHotkeys.hpp | 15 +- include/GlobalHotkeysLinux.hpp | 6 +- include/Overlay.hpp | 17 +- include/gui/GlobalSettingsPage.hpp | 46 +++- meson.build | 3 +- project.conf | 2 +- src/Config.cpp | 34 ++- src/GlobalHotkeysLinux.cpp | 140 ++++++++-- src/GlobalHotkeysX11.cpp | 39 ++- src/Overlay.cpp | 177 ++++++++++-- src/WindowUtils.cpp | 100 +++---- src/gui/GlobalSettingsPage.cpp | 434 ++++++++++++++++++++++++++++-- src/main.cpp | 96 +------ tools/gsr-global-hotkeys/keyboard_event.c | 406 ++++++++++++++++++---------- tools/gsr-global-hotkeys/keyboard_event.h | 76 +++--- tools/gsr-global-hotkeys/main.c | 115 +------- 20 files changed, 1187 insertions(+), 567 deletions(-) diff --git a/README.md b/README.md index 1b0651a..3d4a30c 100644 --- a/README.md +++ b/README.md @@ -56,18 +56,7 @@ If you want to donate you can donate via bitcoin or monero. # Known issues * When the UI is open the wallpaper is shown instead of the game on Hyprland. This is an issue with Hyprland. It cant be fixed until the UI is redesigned to not be a fullscreen overlay. * Opening the UI when a game is fullscreened can mess up the game window a bit on Hyprland. I believe this is an issue with Hyprland. -* Global hotkeys work incorrectly with different keyboard layouts in the flatpak version when using wayland (keys are not in their physical location). This seems to be a flatpak limitation. # FAQ ## I get an error when trying to start the gpu-screen-recorder-ui.service systemd service -If you have previously used the flatpak version of GPU Screen Recorder with the new UI then non-flatpak version of the systemd service will conflict with that. -Run these commands to first remove the flatpak version of the systemd service: -``` -systemctl stop --user gpu-screen-recorder-ui -rm ~/.local/share/systemd/user/gpu-screen-recorder-ui.service -systemctl --user daemon-reload -``` -and then start and enable the non-flatpak systemd service: -``` -systemctl enable --now --user gpu-screen-recorder-ui` -``` \ No newline at end of file +If you have previously used the flatpak version of GPU Screen Recorder with the new UI then non-flatpak version of the systemd service will conflict with that. Run `gsr-ui` to fix that. diff --git a/TODO b/TODO index 3020e6d..8b9cad0 100644 --- a/TODO +++ b/TODO @@ -16,8 +16,6 @@ Add support for window selection in capture. Add option to record the focused monitor. This works on wayland too when using kms capture since we can get cursor position without root and see which monitor (crtc) the cursor is on. Or use create_window_get_center_position. -Make hotkeys configurable. - Filechooser should have the option to select list view, search bar and common folders/mounted drives on the left side for quick navigation. Also a button to create a new directory. Restart replay on system start if monitor resolution changes. @@ -76,8 +74,6 @@ Run `systemctl status --user gpu-screen-recorder` when starting recording and gi Add option to select which gpu to record with, or list all monitors and automatically use the gpu associated with the monitor. Do the same in gtk application. -Test global hotkeys with azerty instead of qwerty. - Dont allow autostart of replay if capture option is window recording (when window recording is added). Use global shortcuts desktop portal protocol on wayland when available. @@ -102,11 +98,6 @@ Show warning if another instance of gpu screen recorder is already running when 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. -Implement hotkey changing in global settings by getting mgl key events. During this time gsr-global-hotkey would either need to be paused or add code in the callback handler for the existing hotkeys since they are grabbing hotkeys. - This can only be done after gsr-global-hotkeys properly handle different keyboard layouts to make sure mgl keys match gsr-global-hotkey keys. - -Re-enable hotkey disable option for flatpak. - 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. @@ -114,7 +105,6 @@ When enabling X11 global hotkey again only grab lalt, not ralt. When adding window capture only add it to recording and streaming and do the window selection when recording starts, to make it more ergonomic with hotkeys. If hotkey for recording/streaming start is pressed on the button for start is clicked then hide the ui if it's visible and show the window selection option (cursor). -Instead of using x11 in gsr-global-hotkeys do the keysym to keycode mapping in gsr-ui and send that to gsr-global-hotkeys. Also improve gsr-global-hotkeys setup performance - by only grabbing keys after the first button press. +Show an error that prime run will be disabled when using desktop portal capture option. This can cause issues as the user may have selected a video codec option that isn't available on their iGPU but is available on the prime-run dGPU. -Show an error that prime run will be disabled when using desktop portal capture option. This can cause issues as the user may have selected a video codec option that isn't available on their iGPU but is available on the prime-run dGPU. \ No newline at end of file +Is it possible to configure hotkey and the new hotkey to get triggered immediately? \ No newline at end of file diff --git a/depends/mglpp b/depends/mglpp index e776c85..cd258b5 160000 --- a/depends/mglpp +++ b/depends/mglpp @@ -1 +1 @@ -Subproject commit e776c85d1986ee9cd7629ec5f04e89f79230378c +Subproject commit cd258b5f2c6b3c9e41870703e1063a79e3a6abb4 diff --git a/include/Config.hpp b/include/Config.hpp index e7b629f..0d311b2 100644 --- a/include/Config.hpp +++ b/include/Config.hpp @@ -6,12 +6,14 @@ #include #include +#define GSR_CONFIG_FILE_VERSION 1 + namespace gsr { struct SupportedCaptureOptions; struct ConfigHotkey { - int64_t keysym = 0; - uint32_t modifiers = 0; + int64_t key = 0; // Mgl key + uint32_t modifiers = 0; // HotkeyModifier bool operator==(const ConfigHotkey &other) const; bool operator!=(const ConfigHotkey &other) const; @@ -41,11 +43,12 @@ namespace gsr { }; struct MainConfig { - int32_t config_file_version = 0; + int32_t config_file_version = GSR_CONFIG_FILE_VERSION; bool software_encoding_warning_shown = false; std::string hotkeys_enable_option = "enable_hotkeys"; std::string joystick_hotkeys_enable_option = "disable_hotkeys"; std::string tint_color; + ConfigHotkey show_hide_hotkey; }; struct YoutubeStreamConfig { @@ -69,7 +72,7 @@ namespace gsr { YoutubeStreamConfig youtube; TwitchStreamConfig twitch; CustomStreamConfig custom; - ConfigHotkey start_stop_recording_hotkey; + ConfigHotkey start_stop_hotkey; }; struct RecordConfig { @@ -79,8 +82,8 @@ namespace gsr { bool show_video_saved_notifications = true; std::string save_directory; std::string container = "mp4"; - ConfigHotkey start_stop_recording_hotkey; - ConfigHotkey pause_unpause_recording_hotkey; + ConfigHotkey start_stop_hotkey; + ConfigHotkey pause_unpause_hotkey; }; struct ReplayConfig { @@ -93,8 +96,8 @@ namespace gsr { std::string save_directory; std::string container = "mp4"; int32_t replay_time = 60; - ConfigHotkey start_stop_recording_hotkey; - ConfigHotkey save_recording_hotkey; + ConfigHotkey start_stop_hotkey; + ConfigHotkey save_hotkey; }; struct Config { diff --git a/include/GlobalHotkeys.hpp b/include/GlobalHotkeys.hpp index 27fca07..2927fa7 100644 --- a/include/GlobalHotkeys.hpp +++ b/include/GlobalHotkeys.hpp @@ -9,9 +9,20 @@ namespace mgl { } namespace gsr { + enum HotkeyModifier : uint32_t { + HOTKEY_MOD_LSHIFT = 1 << 0, + HOTKEY_MOD_RSHIFT = 1 << 1, + HOTKEY_MOD_LCTRL = 1 << 2, + HOTKEY_MOD_RCTRL = 1 << 3, + HOTKEY_MOD_LALT = 1 << 4, + HOTKEY_MOD_RALT = 1 << 5, + HOTKEY_MOD_LSUPER = 1 << 6, + HOTKEY_MOD_RSUPER = 1 << 7 + }; + struct Hotkey { - uint64_t key = 0; - uint32_t modifiers = 0; + uint32_t key = 0; // X11 keysym + uint32_t modifiers = 0; // HotkeyModifier }; using GlobalHotkeyCallback = std::function; diff --git a/include/GlobalHotkeysLinux.hpp b/include/GlobalHotkeysLinux.hpp index addb849..c9428de 100644 --- a/include/GlobalHotkeysLinux.hpp +++ b/include/GlobalHotkeysLinux.hpp @@ -18,11 +18,13 @@ namespace gsr { ~GlobalHotkeysLinux() override; bool start(); - bool bind_action(const std::string &id, GlobalHotkeyCallback callback) override; + bool bind_key_press(Hotkey hotkey, const std::string &id, GlobalHotkeyCallback callback) override; + void unbind_all_keys() override; void poll_events() override; private: pid_t process_id = 0; - int pipes[2]; + int read_pipes[2]; + int write_pipes[2]; FILE *read_file = nullptr; std::unordered_map bound_actions_by_id; GrabType grab_type; diff --git a/include/Overlay.hpp b/include/Overlay.hpp index 2ccfb02..a4e75dc 100644 --- a/include/Overlay.hpp +++ b/include/Overlay.hpp @@ -6,6 +6,8 @@ #include "Config.hpp" #include "window_texture.h" #include "WindowUtils.hpp" +#include "GlobalHotkeysLinux.hpp" +#include "GlobalHotkeysJoystick.hpp" #include #include @@ -42,8 +44,7 @@ namespace gsr { Overlay& operator=(const Overlay&) = delete; ~Overlay(); - void handle_events(gsr::GlobalHotkeys *global_hotkeys); - void on_event(mgl::Event &event); + void handle_events(); // Returns false if not visible bool draw(); @@ -62,9 +63,12 @@ namespace gsr { const Config& get_config() const; - std::function on_keyboard_hotkey_changed; - std::function on_joystick_hotkey_changed; + void unbind_all_keyboard_hotkeys(); + void rebind_all_keyboard_hotkeys(); private: + void handle_keyboard_mapping_event(); + void on_event(mgl::Event &event); + void xi_setup(); void handle_xi_events(); void process_key_bindings(mgl::Event &event); @@ -176,5 +180,10 @@ namespace gsr { mgl::Clock show_overlay_clock; double show_overlay_timeout_seconds = 0.0; + + std::unique_ptr global_hotkeys = nullptr; + std::unique_ptr global_hotkeys_js = nullptr; + Display *x11_mapping_display = nullptr; + XEvent x11_mapping_xev; }; } \ No newline at end of file diff --git a/include/gui/GlobalSettingsPage.hpp b/include/gui/GlobalSettingsPage.hpp index 1066bb5..92454c8 100644 --- a/include/gui/GlobalSettingsPage.hpp +++ b/include/gui/GlobalSettingsPage.hpp @@ -5,18 +5,32 @@ #include "../Config.hpp" #include +#include namespace gsr { + class Overlay; class GsrPage; class PageStack; class ScrollablePage; class Subsection; class RadioButton; class Button; + class List; + class CustomRendererWidget; + + enum ConfigureHotkeyType { + NONE, + REPLAY_START_STOP, + REPLAY_SAVE, + RECORD_START_STOP, + RECORD_PAUSE_UNPAUSE, + STREAM_START_STOP, + SHOW_HIDE + }; class GlobalSettingsPage : public StaticPage { public: - GlobalSettingsPage(const GsrInfo *gsr_info, Config &config, PageStack *page_stack); + GlobalSettingsPage(Overlay *overlay, const GsrInfo *gsr_info, Config &config, PageStack *page_stack); GlobalSettingsPage(const GlobalSettingsPage&) = delete; GlobalSettingsPage& operator=(const GlobalSettingsPage&) = delete; @@ -24,21 +38,39 @@ namespace gsr { void save(); void on_navigate_away_from_page() override; + bool on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) override; + std::function on_startup_changed; std::function on_click_exit_program_button; std::function on_keyboard_hotkey_changed; std::function on_joystick_hotkey_changed; private: + void load_hotkeys(); + std::unique_ptr create_appearance_subsection(ScrollablePage *parent_page); std::unique_ptr create_startup_subsection(ScrollablePage *parent_page); std::unique_ptr create_enable_keyboard_hotkeys_button(); std::unique_ptr create_enable_joystick_hotkeys_button(); + std::unique_ptr create_show_hide_hotkey_options(); + std::unique_ptr create_replay_hotkey_options(); + std::unique_ptr create_record_hotkey_options(); + std::unique_ptr create_stream_hotkey_options(); + std::unique_ptr create_hotkey_control_buttons(); std::unique_ptr create_hotkey_subsection(ScrollablePage *parent_page); std::unique_ptr