From ad94cff59e9b1a73f30c2a1fc46633c346d52108 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 20 Jul 2025 01:55:02 +0200 Subject: [PATCH] Add lshift + printscreen hotkey to take a screenshot of a window (or desktop portal on wayland) --- TODO | 2 + include/Config.hpp | 1 + include/Overlay.hpp | 9 ++++- include/gui/GlobalSettingsPage.hpp | 3 ++ src/Config.cpp | 4 +- src/Overlay.cpp | 62 ++++++++++++++++++++++-------- src/gui/GlobalSettingsPage.cpp | 36 +++++++++++++++++ src/main.cpp | 5 +++ tools/gsr-ui-cli/main.c | 3 ++ 9 files changed, 107 insertions(+), 18 deletions(-) diff --git a/TODO b/TODO index 59950f9..17abf96 100644 --- a/TODO +++ b/TODO @@ -205,3 +205,5 @@ Disable hotkeys if virtual keyboard is found (either at startup or after running Maybe this can be fixed automatically by grabbing gsr-ui virtual keyboard and releasing it just before we write to it and then release it again. But wont keyboard remapping software grab the keyboard first if they detect it quickly? If we fail to grab it because some other software did then dont grab any keyboards nor gsr-ui virtual keyboards, just listen to them. + +Support localization. \ No newline at end of file diff --git a/include/Config.hpp b/include/Config.hpp index 7c2aeda..ec24572 100644 --- a/include/Config.hpp +++ b/include/Config.hpp @@ -145,6 +145,7 @@ namespace gsr { std::string save_directory; ConfigHotkey take_screenshot_hotkey; ConfigHotkey take_screenshot_region_hotkey; + ConfigHotkey take_screenshot_window_hotkey; // Or desktop portal, on wayland }; struct Config { diff --git a/include/Overlay.hpp b/include/Overlay.hpp index 30ec21d..72e03f8 100644 --- a/include/Overlay.hpp +++ b/include/Overlay.hpp @@ -41,6 +41,12 @@ namespace gsr { SCREENSHOT }; + enum class ScreenshotForceType { + NONE, + REGION, + WINDOW + }; + class Overlay { public: Overlay(std::string resources_path, GsrInfo gsr_info, SupportedCaptureOptions capture_options, egl_functions egl_funcs); @@ -64,6 +70,7 @@ namespace gsr { void save_replay_10_min(); void take_screenshot(); void take_screenshot_region(); + void take_screenshot_window(); void show_notification(const char *str, double timeout_seconds, mgl::Color icon_color, mgl::Color bg_color, NotificationType notification_type, const char *capture_target = nullptr); bool is_open() const; bool should_exit(std::string &reason) const; @@ -121,7 +128,7 @@ namespace gsr { bool on_press_start_replay(bool disable_notification, bool finished_selection); void on_press_start_record(bool finished_selection); void on_press_start_stream(bool finished_selection); - void on_press_take_screenshot(bool finished_selection, bool force_region_capture); + void on_press_take_screenshot(bool finished_selection, ScreenshotForceType force_type); bool update_compositor_texture(const Monitor &monitor); std::string get_capture_target(const std::string &capture_target, const SupportedCaptureOptions &capture_options); diff --git a/include/gui/GlobalSettingsPage.hpp b/include/gui/GlobalSettingsPage.hpp index d96397d..e120d69 100644 --- a/include/gui/GlobalSettingsPage.hpp +++ b/include/gui/GlobalSettingsPage.hpp @@ -29,6 +29,7 @@ namespace gsr { STREAM_START_STOP, TAKE_SCREENSHOT, TAKE_SCREENSHOT_REGION, + TAKE_SCREENSHOT_WINDOW, SHOW_HIDE }; @@ -63,6 +64,7 @@ namespace gsr { std::unique_ptr create_stream_hotkey_options(); std::unique_ptr create_screenshot_hotkey_options(); std::unique_ptr create_screenshot_region_hotkey_options(); + std::unique_ptr create_screenshot_window_hotkey_options(); std::unique_ptr create_hotkey_control_buttons(); std::unique_ptr create_keyboard_hotkey_subsection(ScrollablePage *parent_page); std::unique_ptr create_controller_hotkey_subsection(ScrollablePage *parent_page); @@ -99,6 +101,7 @@ namespace gsr { Button *start_stop_streaming_button_ptr = nullptr; Button *take_screenshot_button_ptr = nullptr; Button *take_screenshot_region_button_ptr = nullptr; + Button *take_screenshot_window_button_ptr = nullptr; Button *show_hide_button_ptr = nullptr; ConfigHotkey configure_config_hotkey; diff --git a/src/Config.cpp b/src/Config.cpp index 313cd38..28c9e68 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -153,6 +153,7 @@ namespace gsr { screenshot_config.take_screenshot_hotkey = {mgl::Keyboard::Printscreen, 0}; screenshot_config.take_screenshot_region_hotkey = {mgl::Keyboard::Printscreen, HOTKEY_MOD_LCTRL}; + screenshot_config.take_screenshot_window_hotkey = {mgl::Keyboard::Printscreen, HOTKEY_MOD_LSHIFT}; main_config.show_hide_hotkey = {mgl::Keyboard::Z, HOTKEY_MOD_LALT}; } @@ -284,7 +285,8 @@ namespace gsr { {"screenshot.show_screenshot_saved_notifications", &config.screenshot_config.show_screenshot_saved_notifications}, {"screenshot.save_directory", &config.screenshot_config.save_directory}, {"screenshot.take_screenshot_hotkey", &config.screenshot_config.take_screenshot_hotkey}, - {"screenshot.take_screenshot_region_hotkey", &config.screenshot_config.take_screenshot_region_hotkey} + {"screenshot.take_screenshot_region_hotkey", &config.screenshot_config.take_screenshot_region_hotkey}, + {"screenshot.take_screenshot_window_hotkey", &config.screenshot_config.take_screenshot_window_hotkey} }; } diff --git a/src/Overlay.cpp b/src/Overlay.cpp index c698cff..036d5dd 100644 --- a/src/Overlay.cpp +++ b/src/Overlay.cpp @@ -378,6 +378,13 @@ namespace gsr { overlay->take_screenshot_region(); }); + global_hotkeys->bind_key_press( + config_hotkey_to_hotkey(overlay->get_config().screenshot_config.take_screenshot_window_hotkey), + "take_screenshot_window", [overlay](const std::string &id) { + fprintf(stderr, "pressed %s\n", id.c_str()); + overlay->take_screenshot_window(); + }); + global_hotkeys->bind_key_press( config_hotkey_to_hotkey(ConfigHotkey{ mgl::Keyboard::Key::Escape, HOTKEY_MOD_LCTRL | HOTKEY_MOD_LSHIFT | HOTKEY_MOD_LALT }), "exit", [overlay](const std::string &id) { @@ -1481,11 +1488,15 @@ namespace gsr { } void Overlay::take_screenshot() { - on_press_take_screenshot(false, false); + on_press_take_screenshot(false, ScreenshotForceType::NONE); } void Overlay::take_screenshot_region() { - on_press_take_screenshot(false, true); + on_press_take_screenshot(false, ScreenshotForceType::REGION); + } + + void Overlay::take_screenshot_window() { + on_press_take_screenshot(false, ScreenshotForceType::WINDOW); } static const char* notification_type_to_string(NotificationType notification_type) { @@ -2940,7 +2951,7 @@ namespace gsr { hide_ui = true; } - void Overlay::on_press_take_screenshot(bool finished_selection, bool force_region_capture) { + void Overlay::on_press_take_screenshot(bool finished_selection, ScreenshotForceType force_type) { if(region_selector.is_started() || window_selector.is_started()) return; @@ -2949,8 +2960,21 @@ namespace gsr { return; } - const bool region_capture = config.screenshot_config.record_area_option == "region" || force_region_capture; - const char *record_area_option = region_capture ? "region" : config.screenshot_config.record_area_option.c_str(); + bool hotkey_window_capture = false; + std::string record_area_option; + switch(force_type) { + case ScreenshotForceType::NONE: + record_area_option = config.screenshot_config.record_area_option; + break; + case ScreenshotForceType::REGION: + record_area_option = "region"; + break; + case ScreenshotForceType::WINDOW: + record_area_option = gsr_info.system_info.display_server == DisplayServer::X11 ? "window" : "portal"; + hotkey_window_capture = true; + break; + } + const SupportedCaptureOptions capture_options = get_supported_capture_options(gsr_info); screenshot_capture_target = get_capture_target(record_area_option, capture_options); if(!validate_capture_target(record_area_option, capture_options)) { @@ -2960,19 +2984,19 @@ namespace gsr { return; } - if(region_capture && !finished_selection) { + if(record_area_option == "region" && !finished_selection) { start_region_capture = true; - on_region_selected = [this, force_region_capture]() { + on_region_selected = [this, force_type]() { usleep(200 * 1000); // Hack: wait 0.2 seconds before taking a screenshot to allow user to move cursor away. TODO: Remove this - on_press_take_screenshot(true, force_region_capture); + on_press_take_screenshot(true, force_type); }; return; } - if(config.screenshot_config.record_area_option == "window" && !finished_selection) { + if(record_area_option == "window" && !finished_selection) { start_window_capture = true; - on_window_selected = [this, force_region_capture]() { - on_press_take_screenshot(true, force_region_capture); + on_window_selected = [this, force_type]() { + on_press_take_screenshot(true, force_type); }; return; } @@ -2996,13 +3020,22 @@ namespace gsr { args.push_back(size); } - if(config.screenshot_config.restore_portal_session) { + if(config.screenshot_config.restore_portal_session && !hotkey_window_capture) { args.push_back("-restore-portal-session"); args.push_back("yes"); } + const std::string hotkey_window_capture_portal_session_token_filepath = get_config_dir() + "/gpu-screen-recorder/gsr-ui-window-capture-token"; + if(record_area_option == "portal") { + hide_ui = true; + if(hotkey_window_capture) { + args.push_back("-portal-session-token-filepath"); + args.push_back(hotkey_window_capture_portal_session_token_filepath.c_str()); + } + } + char region_str[128]; - if(region_capture) + if(record_area_option == "region") add_region_command(args, region_str, sizeof(region_str), region_selector); args.push_back(nullptr); @@ -3012,9 +3045,6 @@ namespace gsr { if(gpu_screen_recorder_screenshot_process == -1) { show_notification("Failed to launch gpu-screen-recorder to take a screenshot", notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::SCREENSHOT); } - - if(config.screenshot_config.record_area_option == "portal") - hide_ui = true; } bool Overlay::update_compositor_texture(const Monitor &monitor) { diff --git a/src/gui/GlobalSettingsPage.cpp b/src/gui/GlobalSettingsPage.cpp index 6650c69..1f27cfc 100644 --- a/src/gui/GlobalSettingsPage.cpp +++ b/src/gui/GlobalSettingsPage.cpp @@ -348,6 +348,27 @@ namespace gsr { return list; } + std::unique_ptr GlobalSettingsPage::create_screenshot_window_hotkey_options() { + auto list = std::make_unique(List::Orientation::HORIZONTAL, List::Alignment::CENTER); + + char str[128]; + if(gsr_info->system_info.display_server == DisplayServer::X11) + snprintf(str, sizeof(str), "Take a screenshot of a window:"); + else + snprintf(str, sizeof(str), "Take a screenshot with desktop portal:"); + + list->add_widget(std::make_unique