aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--TODO8
-rw-r--r--images/ps4_options.pngbin0 -> 801 bytes
-rw-r--r--include/Config.hpp1
-rw-r--r--include/GlobalHotkeysJoystick.hpp2
-rw-r--r--include/Overlay.hpp3
-rw-r--r--include/Theme.hpp1
-rw-r--r--include/gui/Button.hpp2
-rw-r--r--include/gui/GlobalSettingsPage.hpp3
-rw-r--r--src/Config.cpp6
-rw-r--r--src/GlobalHotkeysJoystick.cpp11
-rw-r--r--src/GlobalHotkeysLinux.cpp14
-rw-r--r--src/Overlay.cpp39
-rw-r--r--src/Theme.cpp3
-rw-r--r--src/gui/Button.cpp8
-rw-r--r--src/gui/GlobalSettingsPage.cpp47
-rw-r--r--src/gui/SettingsPage.cpp2
-rw-r--r--src/main.cpp5
-rw-r--r--tools/gsr-global-hotkeys/keyboard_event.c13
-rw-r--r--tools/gsr-ui-cli/main.c24
20 files changed, 153 insertions, 41 deletions
diff --git a/README.md b/README.md
index 63da57c..f61b49d 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ This might cause issues for you if you use input remapping software. To workarou
# License
This software is licensed under GPL3.0-only. Files under `fonts/` directory belong to the Noto Sans Google fonts project and they are licensed under `SIL Open Font License`.\
`images/default.cur` it part of the [Adwaita icon theme](https://gitlab.gnome.org/GNOME/adwaita-icon-theme/-/tree/master) which is licensed under `CC BY-SA 3.0`.\
-The D-Pad images under `images/` were created by [Julio Cacko](https://juliocacko.itch.io/free-input-prompts) and they are licensed under `CC0 1.0 Universal`.\
+The controller buttons under `images/` were created by [Julio Cacko](https://juliocacko.itch.io/free-input-prompts) and they are licensed under `CC0 1.0 Universal`.\
The PlayStation logo under `images/` was created by [ArksDigital](https://arks.itch.io/ps4-buttons) and it's are licensed under `CC BY 4.0`.
# Reporting bugs, contributing patches, questions or donation
diff --git a/TODO b/TODO
index 8eced48..65addf3 100644
--- a/TODO
+++ b/TODO
@@ -105,13 +105,9 @@ When adding window capture only add it to recording and streaming and do the win
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.
-Is it possible to configure hotkey and the new hotkey to get triggered immediately?
-
For keyboards that report supporting mice the keyboard grab will be delayed until any key has been pressed (and then released), see: https://github.com/dec05eba/gpu-screen-recorder-issues/issues/97
See if there is any way around this.
-Instead of installing gsr-global-hotkeys in flatpak use kms-server-proxy to launch gsr-global-hotkeys inside the flatpak with root, just like gsr-kms-server. This removes the need to update gsr-global-hotkeys everytime there is an update.
-
Check if "modprobe uinput" is needed on some systems (old fedora?).
Add recording timer to see duration of recording/streaming.
@@ -137,11 +133,9 @@ Make input work with cjk input systems (such as fcitx).
System startup option should also support runit and some other init systems, not only soystemd.
-Allow using a hotkey such as printscreen or any other non-alphanumeric key without a modifier. Allow that in gsr-ui and gsr-global-hotkeys. Update the ui to match that.
-
Use x11 shm instead of XGetImage (https://stackoverflow.com/questions/43442675/how-to-use-xshmgetimage-and-xshmputimage).
-Add a hotkey to record/stream/replay/screenshot region.
+Add a hotkey to record/stream/replay region.
Do xi grab for keys as well. Otherwise the ui cant be used for keyboard input if a program has grabbed the keyboard, and there could possibly be a game that grabs the keyboard as well.
diff --git a/images/ps4_options.png b/images/ps4_options.png
new file mode 100644
index 0000000..99787fa
--- /dev/null
+++ b/images/ps4_options.png
Binary files differ
diff --git a/include/Config.hpp b/include/Config.hpp
index 1e2e9cb..0e8e4eb 100644
--- a/include/Config.hpp
+++ b/include/Config.hpp
@@ -126,6 +126,7 @@ namespace gsr {
bool show_screenshot_saved_notifications = true;
std::string save_directory;
ConfigHotkey take_screenshot_hotkey;
+ ConfigHotkey take_screenshot_region_hotkey;
};
struct Config {
diff --git a/include/GlobalHotkeysJoystick.hpp b/include/GlobalHotkeysJoystick.hpp
index 1effe3c..30a7689 100644
--- a/include/GlobalHotkeysJoystick.hpp
+++ b/include/GlobalHotkeysJoystick.hpp
@@ -24,6 +24,7 @@ namespace gsr {
// take_screenshot
// toggle_record
// toggle_replay
+ // toggle_show
bool bind_action(const std::string &id, GlobalHotkeyCallback callback) override;
void poll_events() override;
private:
@@ -58,6 +59,7 @@ namespace gsr {
bool take_screenshot = false;
bool toggle_record = false;
bool toggle_replay = false;
+ bool toggle_show = false;
int hotplug_poll_index = -1;
Hotplug hotplug;
};
diff --git a/include/Overlay.hpp b/include/Overlay.hpp
index 5ed7f51..d7b8af1 100644
--- a/include/Overlay.hpp
+++ b/include/Overlay.hpp
@@ -59,6 +59,7 @@ namespace gsr {
void toggle_replay();
void save_replay();
void take_screenshot();
+ void take_screenshot_region();
void show_notification(const char *str, double timeout_seconds, mgl::Color icon_color, mgl::Color bg_color, NotificationType notification_type);
bool is_open() const;
bool should_exit(std::string &reason) const;
@@ -111,7 +112,7 @@ namespace gsr {
bool on_press_start_replay(bool disable_notification, bool finished_region_selection);
void on_press_start_record(bool finished_region_selection);
void on_press_start_stream(bool finished_region_selection);
- void on_press_take_screenshot(bool finished_region_selection);
+ void on_press_take_screenshot(bool finished_region_selection, bool force_region_capture);
bool update_compositor_texture(const Monitor &monitor);
void force_window_on_top();
diff --git a/include/Theme.hpp b/include/Theme.hpp
index bda8dd4..4305072 100644
--- a/include/Theme.hpp
+++ b/include/Theme.hpp
@@ -44,6 +44,7 @@ namespace gsr {
mgl::Texture screenshot_texture;
mgl::Texture ps4_home_texture;
+ mgl::Texture ps4_options_texture;
mgl::Texture ps4_dpad_up_texture;
mgl::Texture ps4_dpad_down_texture;
mgl::Texture ps4_dpad_left_texture;
diff --git a/include/gui/Button.hpp b/include/gui/Button.hpp
index 7070457..f412521 100644
--- a/include/gui/Button.hpp
+++ b/include/gui/Button.hpp
@@ -21,6 +21,7 @@ namespace gsr {
mgl::vec2f get_size() override;
void set_border_scale(float scale);
+ void set_icon_padding_scale(float scale);
void set_bg_hover_color(mgl::Color color);
void set_icon(mgl::Texture *texture);
@@ -38,5 +39,6 @@ namespace gsr {
mgl::Text text;
mgl::Sprite sprite;
float border_scale = 0.0015f;
+ float icon_padding_scale = 1.0f;
};
} \ No newline at end of file
diff --git a/include/gui/GlobalSettingsPage.hpp b/include/gui/GlobalSettingsPage.hpp
index c261ab6..5df5b9c 100644
--- a/include/gui/GlobalSettingsPage.hpp
+++ b/include/gui/GlobalSettingsPage.hpp
@@ -26,6 +26,7 @@ namespace gsr {
RECORD_PAUSE_UNPAUSE,
STREAM_START_STOP,
TAKE_SCREENSHOT,
+ TAKE_SCREENSHOT_REGION,
SHOW_HIDE
};
@@ -58,6 +59,7 @@ namespace gsr {
std::unique_ptr<List> create_record_hotkey_options();
std::unique_ptr<List> create_stream_hotkey_options();
std::unique_ptr<List> create_screenshot_hotkey_options();
+ std::unique_ptr<List> create_screenshot_region_hotkey_options();
std::unique_ptr<List> create_hotkey_control_buttons();
std::unique_ptr<Subsection> create_keyboard_hotkey_subsection(ScrollablePage *parent_page);
std::unique_ptr<Subsection> create_controller_hotkey_subsection(ScrollablePage *parent_page);
@@ -91,6 +93,7 @@ namespace gsr {
Button *pause_unpause_recording_button_ptr = nullptr;
Button *start_stop_streaming_button_ptr = nullptr;
Button *take_screenshot_button_ptr = nullptr;
+ Button *take_screenshot_region_button_ptr = nullptr;
Button *show_hide_button_ptr = nullptr;
ConfigHotkey configure_config_hotkey;
diff --git a/src/Config.cpp b/src/Config.cpp
index 734f827..fdb5e4a 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -139,7 +139,8 @@ namespace gsr {
replay_config.start_stop_hotkey = {mgl::Keyboard::F10, HOTKEY_MOD_LALT | HOTKEY_MOD_LSHIFT};
replay_config.save_hotkey = {mgl::Keyboard::F10, HOTKEY_MOD_LALT};
- screenshot_config.take_screenshot_hotkey = {mgl::Keyboard::F1, HOTKEY_MOD_LALT};
+ screenshot_config.take_screenshot_hotkey = {mgl::Keyboard::Printscreen, 0};
+ screenshot_config.take_screenshot_region_hotkey = {mgl::Keyboard::Printscreen, HOTKEY_MOD_LCTRL};
main_config.show_hide_hotkey = {mgl::Keyboard::Z, HOTKEY_MOD_LALT};
}
@@ -262,7 +263,8 @@ namespace gsr {
{"screenshot.save_screenshot_in_game_folder", &config.screenshot_config.save_screenshot_in_game_folder},
{"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_hotkey", &config.screenshot_config.take_screenshot_hotkey},
+ {"screenshot.take_screenshot_region_hotkey", &config.screenshot_config.take_screenshot_region_hotkey}
};
}
diff --git a/src/GlobalHotkeysJoystick.cpp b/src/GlobalHotkeysJoystick.cpp
index 066c8c9..d005aa9 100644
--- a/src/GlobalHotkeysJoystick.cpp
+++ b/src/GlobalHotkeysJoystick.cpp
@@ -7,6 +7,7 @@
namespace gsr {
static constexpr int button_pressed = 1;
+ static constexpr int options_button = 9;
static constexpr int playstation_button = 10;
static constexpr int axis_up_down = 7;
static constexpr int axis_left_right = 6;
@@ -123,6 +124,13 @@ namespace gsr {
if(it != bound_actions_by_id.end())
it->second("toggle_replay");
}
+
+ if(toggle_show) {
+ toggle_show = false;
+ auto it = bound_actions_by_id.find("toggle_show");
+ if(it != bound_actions_by_id.end())
+ it->second("toggle_show");
+ }
}
void GlobalHotkeysJoystick::read_events() {
@@ -180,12 +188,15 @@ namespace gsr {
if((event.type & JS_EVENT_BUTTON) == JS_EVENT_BUTTON) {
if(event.number == playstation_button)
playstation_button_pressed = event.value == button_pressed;
+ else if(playstation_button_pressed && event.number == options_button && event.value == button_pressed)
+ toggle_show = true;
} else if((event.type & JS_EVENT_AXIS) == JS_EVENT_AXIS && playstation_button_pressed) {
const int trigger_threshold = 16383;
const bool prev_up_pressed = up_pressed;
const bool prev_down_pressed = down_pressed;
const bool prev_left_pressed = left_pressed;
const bool prev_right_pressed = right_pressed;
+
if(event.number == axis_up_down) {
up_pressed = event.value <= -trigger_threshold;
down_pressed = event.value >= trigger_threshold;
diff --git a/src/GlobalHotkeysLinux.cpp b/src/GlobalHotkeysLinux.cpp
index 4df6390..fbba0ea 100644
--- a/src/GlobalHotkeysLinux.cpp
+++ b/src/GlobalHotkeysLinux.cpp
@@ -9,6 +9,7 @@ extern "C" {
#include <mgl/mgl.h>
}
#include <X11/Xlib.h>
+#include <X11/keysym.h>
#include <linux/input-event-codes.h>
#define PIPE_READ 0
@@ -58,6 +59,10 @@ namespace gsr {
return result;
}
+ static bool x11_key_is_alpha_numerical(KeySym keysym) {
+ return (keysym >= XK_A && keysym <= XK_Z) || (keysym >= XK_a && keysym <= XK_z) || (keysym >= XK_0 && keysym <= XK_9);
+ }
+
GlobalHotkeysLinux::GlobalHotkeysLinux(GrabType grab_type) : grab_type(grab_type) {
for(int i = 0; i < 2; ++i) {
read_pipes[i] = -1;
@@ -173,7 +178,7 @@ namespace gsr {
return false;
}
- if(hotkey.modifiers == 0) {
+ if(hotkey.modifiers == 0 && x11_key_is_alpha_numerical(hotkey.key)) {
//fprintf(stderr, "Error: GlobalHotkeysLinux::bind_key_press: hotkey requires a modifier\n");
return false;
}
@@ -185,7 +190,12 @@ namespace gsr {
const std::string modifiers_command = linux_keys_to_command_string(modifiers.data(), modifiers.size());
char command[256];
- const int command_size = snprintf(command, sizeof(command), "bind %s %d+%s\n", id.c_str(), (int)keycode, modifiers_command.c_str());
+ int command_size = 0;
+ if(modifiers_command.empty())
+ command_size = snprintf(command, sizeof(command), "bind %s %d\n", id.c_str(), (int)keycode);
+ else
+ command_size = snprintf(command, sizeof(command), "bind %s %d+%s\n", id.c_str(), (int)keycode, modifiers_command.c_str());
+
if(write(write_pipes[PIPE_WRITE], command, command_size) != command_size) {
fprintf(stderr, "Error: GlobalHotkeysLinux::bind_key_press: failed to write command to gsr-global-hotkeys, error: %s\n", strerror(errno));
return false;
diff --git a/src/Overlay.cpp b/src/Overlay.cpp
index 63f9822..4eb8844 100644
--- a/src/Overlay.cpp
+++ b/src/Overlay.cpp
@@ -272,7 +272,7 @@ namespace gsr {
static void bind_linux_hotkeys(GlobalHotkeysLinux *global_hotkeys, Overlay *overlay) {
global_hotkeys->bind_key_press(
config_hotkey_to_hotkey(overlay->get_config().main_config.show_hide_hotkey),
- "show_hide", [overlay](const std::string &id) {
+ "toggle_show", [overlay](const std::string &id) {
fprintf(stderr, "pressed %s\n", id.c_str());
overlay->toggle_show();
});
@@ -318,6 +318,13 @@ namespace gsr {
fprintf(stderr, "pressed %s\n", id.c_str());
overlay->take_screenshot();
});
+
+ global_hotkeys->bind_key_press(
+ config_hotkey_to_hotkey(overlay->get_config().screenshot_config.take_screenshot_region_hotkey),
+ "take_screenshot_region", [overlay](const std::string &id) {
+ fprintf(stderr, "pressed %s\n", id.c_str());
+ overlay->take_screenshot_region();
+ });
}
static std::unique_ptr<GlobalHotkeysLinux> register_linux_hotkeys(Overlay *overlay, GlobalHotkeysLinux::GrabType grab_type) {
@@ -334,6 +341,11 @@ namespace gsr {
if(!global_hotkeys_js->start())
fprintf(stderr, "Warning: failed to start joystick hotkeys\n");
+ global_hotkeys_js->bind_action("toggle_show", [overlay](const std::string &id) {
+ fprintf(stderr, "pressed %s\n", id.c_str());
+ overlay->toggle_show();
+ });
+
global_hotkeys_js->bind_action("save_replay", [overlay](const std::string &id) {
fprintf(stderr, "pressed %s\n", id.c_str());
overlay->save_replay();
@@ -1144,6 +1156,7 @@ namespace gsr {
button->set_position((main_buttons_list_ptr->get_position() + main_buttons_size - mgl::vec2f(0.0f, settings_button_size*2) + mgl::vec2f(settings_button_size * 0.333f, 0.0f)).floor());
button->set_bg_hover_color(mgl::Color(0, 0, 0, 255));
button->set_icon(&get_theme().screenshot_texture);
+ button->set_icon_padding_scale(1.2f);
button->on_click = [&]() {
auto screenshot_settings_page = std::make_unique<ScreenshotSettingsPage>(&gsr_info, config, &page_stack);
page_stack.push(std::move(screenshot_settings_page));
@@ -1306,7 +1319,11 @@ namespace gsr {
}
void Overlay::take_screenshot() {
- on_press_take_screenshot(false);
+ on_press_take_screenshot(false, false);
+ }
+
+ void Overlay::take_screenshot_region() {
+ on_press_take_screenshot(false, true);
}
static const char* notification_type_to_string(NotificationType notification_type) {
@@ -2295,7 +2312,7 @@ namespace gsr {
show_notification("Streaming has started", notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::STREAM);
}
- void Overlay::on_press_take_screenshot(bool finished_region_selection) {
+ void Overlay::on_press_take_screenshot(bool finished_region_selection, bool force_region_capture) {
if(region_selector.is_started())
return;
@@ -2304,18 +2321,20 @@ namespace gsr {
return;
}
- if(!validate_capture_target(gsr_info, config.screenshot_config.record_area_option)) {
+ 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();
+ if(!validate_capture_target(gsr_info, record_area_option)) {
char err_msg[256];
- snprintf(err_msg, sizeof(err_msg), "Failed to take a screenshot, capture target \"%s\" is invalid. Please change capture target in settings", config.screenshot_config.record_area_option.c_str());
+ snprintf(err_msg, sizeof(err_msg), "Failed to take a screenshot, capture target \"%s\" is invalid. Please change capture target in settings", record_area_option);
show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0, 0), mgl::Color(255, 0, 0, 0), NotificationType::SCREENSHOT);
return;
}
- if(config.screenshot_config.record_area_option == "region" && !finished_region_selection) {
+ if(region_capture && !finished_region_selection) {
start_region_capture = true;
- on_region_selected = [this]() {
+ on_region_selected = [this, force_region_capture]() {
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);
+ on_press_take_screenshot(true, force_region_capture);
};
return;
}
@@ -2324,7 +2343,7 @@ namespace gsr {
const std::string output_file = config.screenshot_config.save_directory + "/Screenshot_" + get_date_str() + "." + config.screenshot_config.image_format; // TODO: Validate image format
std::vector<const char*> args = {
- "gpu-screen-recorder", "-w", config.screenshot_config.record_area_option.c_str(),
+ "gpu-screen-recorder", "-w", record_area_option,
"-cursor", config.screenshot_config.record_cursor ? "yes" : "no",
"-v", "no",
"-q", config.screenshot_config.image_quality.c_str(),
@@ -2345,7 +2364,7 @@ namespace gsr {
}
char region_str[128];
- if(config.screenshot_config.record_area_option == "region")
+ if(region_capture)
add_region_command(args, region_str, sizeof(region_str), region_selector);
args.push_back(nullptr);
diff --git a/src/Theme.cpp b/src/Theme.cpp
index edc8843..2001f7d 100644
--- a/src/Theme.cpp
+++ b/src/Theme.cpp
@@ -117,6 +117,9 @@ namespace gsr {
if(!theme->ps4_home_texture.load_from_file((resources_path + "images/ps4_home.png").c_str(), mgl::Texture::LoadOptions{false, false, true}))
goto error;
+ if(!theme->ps4_options_texture.load_from_file((resources_path + "images/ps4_options.png").c_str(), mgl::Texture::LoadOptions{false, false, true}))
+ goto error;
+
if(!theme->ps4_dpad_up_texture.load_from_file((resources_path + "images/ps4_dpad_up.png").c_str(), mgl::Texture::LoadOptions{false, false, true}))
goto error;
diff --git a/src/gui/Button.cpp b/src/gui/Button.cpp
index 476e679..d8cb85b 100644
--- a/src/gui/Button.cpp
+++ b/src/gui/Button.cpp
@@ -105,6 +105,10 @@ namespace gsr {
border_scale = scale;
}
+ void Button::set_icon_padding_scale(float scale) {
+ icon_padding_scale = scale;
+ }
+
void Button::set_bg_hover_color(mgl::Color color) {
bg_hover_color = color;
}
@@ -127,8 +131,8 @@ namespace gsr {
const float widget_height = get_button_height();
- const int padding_icon_top = padding_top_icon_scale * widget_height;
- const int padding_icon_bottom = padding_bottom_icon_scale * widget_height;
+ const int padding_icon_top = padding_top_icon_scale * icon_padding_scale * widget_height;
+ const int padding_icon_bottom = padding_bottom_icon_scale * icon_padding_scale * widget_height;
const float desired_height = widget_height - (padding_icon_top + padding_icon_bottom);
sprite.set_height((int)desired_height);
diff --git a/src/gui/GlobalSettingsPage.cpp b/src/gui/GlobalSettingsPage.cpp
index 1b6e07f..6162ec6 100644
--- a/src/gui/GlobalSettingsPage.cpp
+++ b/src/gui/GlobalSettingsPage.cpp
@@ -70,6 +70,10 @@ namespace gsr {
return 0;
}
+ static bool key_is_alpha_numerical(mgl::Keyboard::Key key) {
+ return key >= mgl::Keyboard::A && key <= mgl::Keyboard::Num9;
+ }
+
GlobalSettingsPage::GlobalSettingsPage(Overlay *overlay, const GsrInfo *gsr_info, Config &config, PageStack *page_stack) :
StaticPage(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()),
overlay(overlay),
@@ -97,13 +101,13 @@ namespace gsr {
mgl::Text title_text("Press a key combination to use for the hotkey \"" + hotkey_configure_action_name + "\":", get_theme().title_font);
mgl::Text hotkey_text(configure_hotkey_button->get_text(), get_theme().top_bar_font);
- mgl::Text description_text("The hotkey has to contain one or more of these keys: Alt, Ctrl, Shift and Super. Press Esc to cancel or Backspace to remove the hotkey.", get_theme().body_font);
+ mgl::Text description_text("Alpha-numerical keys can't be used alone in hotkeys, they have to be used one or more of these keys: Alt, Ctrl, Shift and Super.\nPress Esc to cancel or Backspace to remove the hotkey.", get_theme().body_font);
const float text_max_width = std::max(title_text.get_bounds().size.x, std::max(hotkey_text.get_bounds().size.x, description_text.get_bounds().size.x));
const float padding_horizontal = int(get_theme().window_height * 0.01f);
const float padding_vertical = int(get_theme().window_height * 0.01f);
- const mgl::vec2f bg_size = mgl::vec2f(text_max_width + padding_horizontal*2.0f, get_theme().window_height * 0.1f).floor();
+ const mgl::vec2f bg_size = mgl::vec2f(text_max_width + padding_horizontal*2.0f, get_theme().window_height * 0.13f).floor();
mgl::Rectangle bg_rect(mgl::vec2f(get_theme().window_width*0.5f - bg_size.x*0.5f, get_theme().window_height*0.5f - bg_size.y*0.5f).floor(), bg_size);
bg_rect.set_color(get_color_theme().page_bg_color);
window.draw(bg_rect);
@@ -114,9 +118,16 @@ namespace gsr {
window.draw(tint_rect);
title_text.set_position(mgl::vec2f(bg_rect.get_position() + mgl::vec2f(bg_rect.get_size().x*0.5f - title_text.get_bounds().size.x*0.5f, padding_vertical)).floor());
+ description_text.set_position(mgl::vec2f(bg_rect.get_position() + mgl::vec2f(bg_rect.get_size().x*0.5f - description_text.get_bounds().size.x*0.5f, bg_rect.get_size().y - description_text.get_bounds().size.y - padding_vertical)).floor());
+
window.draw(title_text);
- hotkey_text.set_position(mgl::vec2f(bg_rect.get_position() + bg_rect.get_size()*0.5f - hotkey_text.get_bounds().size*0.5f).floor());
+ const float title_text_bottom = title_text.get_position().y + title_text.get_bounds().size.y;
+ hotkey_text.set_position(
+ mgl::vec2f(
+ bg_rect.get_position().x + bg_rect.get_size().x*0.5f - hotkey_text.get_bounds().size.x*0.5f,
+ title_text_bottom + (description_text.get_position().y - title_text_bottom) * 0.5f - hotkey_text.get_bounds().size.y*0.5f
+ ).floor());
window.draw(hotkey_text);
const float caret_padding_x = int(0.001f * get_theme().window_height);
@@ -124,7 +135,6 @@ namespace gsr {
mgl::Rectangle caret_rect(hotkey_text.get_position() + mgl::vec2f(hotkey_text.get_bounds().size.x + caret_padding_x, hotkey_text.get_bounds().size.y*0.5f - caret_size.y*0.5f).floor(), caret_size);
window.draw(caret_rect);
- description_text.set_position(mgl::vec2f(bg_rect.get_position() + mgl::vec2f(bg_rect.get_size().x*0.5f - description_text.get_bounds().size.x*0.5f, bg_rect.get_size().y - description_text.get_bounds().size.y - padding_vertical)).floor());
window.draw(description_text);
};
hotkey_overlay->set_visible(false);
@@ -300,6 +310,21 @@ namespace gsr {
return list;
}
+ std::unique_ptr<List> GlobalSettingsPage::create_screenshot_region_hotkey_options() {
+ auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
+
+ list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Take a screenshot of a region:", get_color_theme().text_color));
+ auto take_screenshot_region_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
+ take_screenshot_region_button_ptr = take_screenshot_region_button.get();
+ list->add_widget(std::move(take_screenshot_region_button));
+
+ take_screenshot_region_button_ptr->on_click = [this] {
+ configure_hotkey_start(ConfigureHotkeyType::TAKE_SCREENSHOT_REGION);
+ };
+
+ return list;
+ }
+
std::unique_ptr<List> GlobalSettingsPage::create_hotkey_control_buttons() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
@@ -311,6 +336,7 @@ namespace gsr {
config.replay_config.start_stop_hotkey = {mgl::Keyboard::Unknown, 0};
config.replay_config.save_hotkey = {mgl::Keyboard::Unknown, 0};
config.screenshot_config.take_screenshot_hotkey = {mgl::Keyboard::Unknown, 0};
+ config.screenshot_config.take_screenshot_region_hotkey = {mgl::Keyboard::Unknown, 0};
config.main_config.show_hide_hotkey = {mgl::Keyboard::Unknown, 0};
load_hotkeys();
overlay->rebind_all_keyboard_hotkeys();
@@ -351,6 +377,7 @@ namespace gsr {
list_ptr->add_widget(create_record_hotkey_options());
list_ptr->add_widget(create_stream_hotkey_options());
list_ptr->add_widget(create_screenshot_hotkey_options());
+ list_ptr->add_widget(create_screenshot_region_hotkey_options());
list_ptr->add_widget(create_hotkey_control_buttons());
return subsection;
}
@@ -363,6 +390,7 @@ namespace gsr {
list_ptr->add_widget(std::make_unique<Label>(&get_theme().body_font, "Enable controller hotkeys?", get_color_theme().text_color));
list_ptr->add_widget(create_enable_joystick_hotkeys_button());
list_ptr->add_widget(std::make_unique<LineSeparator>(LineSeparator::Orientation::HORIZONTAL, subsection->get_inner_size().x));
+ list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_options_texture, get_theme().body_font.get_character_size(), "to show/hide the UI"));
list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_dpad_up_texture, get_theme().body_font.get_character_size(), "to take a screenshot"));
list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_dpad_down_texture, get_theme().body_font.get_character_size(), "to save a replay"));
list_ptr->add_widget(create_joystick_hotkey_text(&get_theme().ps4_home_texture, &get_theme().ps4_dpad_left_texture, get_theme().body_font.get_character_size(), "to start/stop recording"));
@@ -469,6 +497,7 @@ namespace gsr {
start_stop_streaming_button_ptr->set_text(config.streaming_config.start_stop_hotkey.to_string());
take_screenshot_button_ptr->set_text(config.screenshot_config.take_screenshot_hotkey.to_string());
+ take_screenshot_region_button_ptr->set_text(config.screenshot_config.take_screenshot_region_hotkey.to_string());
show_hide_button_ptr->set_text(config.main_config.show_hide_hotkey.to_string());
}
@@ -506,7 +535,7 @@ namespace gsr {
if(mgl::Keyboard::key_is_modifier(event.key.code)) {
configure_config_hotkey.modifiers |= mgl_modifier_to_hotkey_modifier(event.key.code);
configure_hotkey_button->set_text(configure_config_hotkey.to_string());
- } else if(configure_config_hotkey.modifiers != 0) {
+ } else if(configure_config_hotkey.modifiers != 0 || !key_is_alpha_numerical(event.key.code)) {
configure_config_hotkey.key = event.key.code;
configure_hotkey_button->set_text(configure_config_hotkey.to_string());
configure_hotkey_stop_and_save();
@@ -546,6 +575,8 @@ namespace gsr {
return start_stop_streaming_button_ptr;
case ConfigureHotkeyType::TAKE_SCREENSHOT:
return take_screenshot_button_ptr;
+ case ConfigureHotkeyType::TAKE_SCREENSHOT_REGION:
+ return take_screenshot_region_button_ptr;
case ConfigureHotkeyType::SHOW_HIDE:
return show_hide_button_ptr;
}
@@ -568,6 +599,8 @@ namespace gsr {
return &config.streaming_config.start_stop_hotkey;
case ConfigureHotkeyType::TAKE_SCREENSHOT:
return &config.screenshot_config.take_screenshot_hotkey;
+ case ConfigureHotkeyType::TAKE_SCREENSHOT_REGION:
+ return &config.screenshot_config.take_screenshot_region_hotkey;
case ConfigureHotkeyType::SHOW_HIDE:
return &config.main_config.show_hide_hotkey;
}
@@ -582,6 +615,7 @@ namespace gsr {
&config.record_config.pause_unpause_hotkey,
&config.streaming_config.start_stop_hotkey,
&config.screenshot_config.take_screenshot_hotkey,
+ &config.screenshot_config.take_screenshot_region_hotkey,
&config.main_config.show_hide_hotkey
};
for(ConfigHotkey *config_hotkey : config_hotkeys) {
@@ -621,6 +655,9 @@ namespace gsr {
case ConfigureHotkeyType::TAKE_SCREENSHOT:
hotkey_configure_action_name = "Take a screenshot";
break;
+ case ConfigureHotkeyType::TAKE_SCREENSHOT_REGION:
+ hotkey_configure_action_name = "Take a screenshot of a region";
+ break;
case ConfigureHotkeyType::SHOW_HIDE:
hotkey_configure_action_name = "Show/hide UI";
break;
diff --git a/src/gui/SettingsPage.cpp b/src/gui/SettingsPage.cpp
index be09f54..79b4525 100644
--- a/src/gui/SettingsPage.cpp
+++ b/src/gui/SettingsPage.cpp
@@ -370,7 +370,7 @@ namespace gsr {
std::unique_ptr<List> SettingsPage::create_video_bitrate() {
auto video_bitrate_list = std::make_unique<List>(List::Orientation::VERTICAL);
- video_bitrate_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Video bitrate (kbps):", get_color_theme().text_color));
+ video_bitrate_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Video bitrate (Kbps):", get_color_theme().text_color));
video_bitrate_list->add_widget(create_video_bitrate_entry());
video_bitrate_list_ptr = video_bitrate_list.get();
return video_bitrate_list;
diff --git a/src/main.cpp b/src/main.cpp
index 169721e..7c10a6e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -78,6 +78,11 @@ static void rpc_add_commands(gsr::Rpc *rpc, gsr::Overlay *overlay) {
fprintf(stderr, "rpc command executed: %s\n", name.c_str());
overlay->take_screenshot();
});
+
+ rpc->add_handler("take-screenshot-region", [overlay](const std::string &name) {
+ fprintf(stderr, "rpc command executed: %s\n", name.c_str());
+ overlay->take_screenshot_region();
+ });
}
static bool is_gsr_ui_virtual_keyboard_running() {
diff --git a/tools/gsr-global-hotkeys/keyboard_event.c b/tools/gsr-global-hotkeys/keyboard_event.c
index f3fba62..c2bd75a 100644
--- a/tools/gsr-global-hotkeys/keyboard_event.c
+++ b/tools/gsr-global-hotkeys/keyboard_event.c
@@ -575,6 +575,13 @@ static int parse_u8(const char *str, int size) {
return result;
}
+static bool is_key_alpha_numerical(uint8_t key) {
+ return (key >= KEY_1 && key <= KEY_0)
+ || (key >= KEY_Q && key <= KEY_P)
+ || (key >= KEY_A && key <= KEY_L)
+ || (key >= KEY_Z && key <= KEY_M);
+}
+
static bool keyboard_event_parse_bind_keys(const char *str, int size, uint8_t *key, uint32_t *modifiers) {
*key = 0;
*modifiers = 0;
@@ -609,13 +616,13 @@ static bool keyboard_event_parse_bind_keys(const char *str, int size, uint8_t *k
break;
}
- if(key == 0) {
+ if(*key == 0) {
fprintf(stderr, "Error: can't bind hotkey without a non-modifier key\n");
return false;
}
- if(modifiers == 0) {
- fprintf(stderr, "Error: can't bind hotkey without a modifier\n");
+ if(*modifiers == 0 && is_key_alpha_numerical(*key)) {
+ fprintf(stderr, "Error: can't bind hotkey without a modifier unless the key is a non alpha-numerical key\n");
return false;
}
diff --git a/tools/gsr-ui-cli/main.c b/tools/gsr-ui-cli/main.c
index 9f1eb03..c34888c 100644
--- a/tools/gsr-ui-cli/main.c
+++ b/tools/gsr-ui-cli/main.c
@@ -44,13 +44,22 @@ static void usage(void) {
printf("Run commands on the running gsr-ui instance.\n");
printf("\n");
printf("COMMANDS:\n");
- printf(" toggle-show Show/hide the UI.\n");
- printf(" toggle-record Start/stop recording.\n");
- printf(" toggle-pause Pause/unpause recording. Only applies to regular recording.\n");
- printf(" toggle-stream Start/stop streaming.\n");
- printf(" toggle-replay Start/stop replay.\n");
- printf(" replay-save Save replay.\n");
- printf(" take-screenshot Take a screenshot.\n");
+ printf(" toggle-show\n");
+ printf(" Show/hide the UI.\n");
+ printf(" toggle-record\n");
+ printf(" Start/stop recording.\n");
+ printf(" toggle-pause\n");
+ printf(" Pause/unpause recording. Only applies to regular recording.\n");
+ printf(" toggle-stream\n");
+ printf(" Start/stop streaming.\n");
+ printf(" toggle-replay\n");
+ printf(" Start/stop replay.\n");
+ printf(" replay-save\n");
+ printf(" Save replay.\n");
+ printf(" take-screenshot\n");
+ printf(" Take a screenshot.\n");
+ printf(" take-screenshot-region\n");
+ printf(" Take a screenshot of a region.\n");
printf("\n");
printf("EXAMPLES:\n");
printf(" gsr-ui-cli toggle-show\n");
@@ -67,6 +76,7 @@ static bool is_valid_command(const char *command) {
"toggle-replay",
"replay-save",
"take-screenshot",
+ "take-screenshot-region",
NULL
};