Add hotkey for region/window recording

This commit is contained in:
dec05eba
2026-01-19 22:26:03 +01:00
parent 0269387b9a
commit 5f484bd82c
10 changed files with 153 additions and 38 deletions

View File

@@ -145,6 +145,8 @@ namespace gsr {
record_config.start_stop_hotkey = {mgl::Keyboard::F9, HOTKEY_MOD_LALT};
record_config.pause_unpause_hotkey = {mgl::Keyboard::F7, HOTKEY_MOD_LALT};
record_config.start_stop_region_hotkey = {mgl::Keyboard::F9, HOTKEY_MOD_LCTRL};
record_config.start_stop_window_hotkey = {mgl::Keyboard::F9, HOTKEY_MOD_LSHIFT};
replay_config.start_stop_hotkey = {mgl::Keyboard::F10, HOTKEY_MOD_LALT | HOTKEY_MOD_LSHIFT};
replay_config.save_hotkey = {mgl::Keyboard::F10, HOTKEY_MOD_LALT};
@@ -262,6 +264,8 @@ namespace gsr {
{"record.container", &config.record_config.container},
{"record.start_stop_hotkey", &config.record_config.start_stop_hotkey},
{"record.pause_unpause_hotkey", &config.record_config.pause_unpause_hotkey},
{"record.start_stop_region_hotkey", &config.record_config.start_stop_region_hotkey},
{"record.start_stop_window_hotkey", &config.record_config.start_stop_window_hotkey},
{"replay.record_options.record_area_option", &config.replay_config.record_options.record_area_option},
{"replay.record_options.record_area_width", &config.replay_config.record_options.record_area_width},

View File

@@ -323,7 +323,7 @@ namespace gsr {
config_hotkey_to_hotkey(overlay->get_config().record_config.start_stop_hotkey),
"record", [overlay](const std::string &id) {
fprintf(stderr, "pressed %s\n", id.c_str());
overlay->toggle_record();
overlay->toggle_record(RecordForceType::NONE);
});
global_hotkeys->bind_key_press(
@@ -333,6 +333,20 @@ namespace gsr {
overlay->toggle_pause();
});
global_hotkeys->bind_key_press(
config_hotkey_to_hotkey(overlay->get_config().record_config.start_stop_region_hotkey),
"record_region", [overlay](const std::string &id) {
fprintf(stderr, "pressed %s\n", id.c_str());
overlay->toggle_record(RecordForceType::REGION);
});
global_hotkeys->bind_key_press(
config_hotkey_to_hotkey(overlay->get_config().record_config.start_stop_window_hotkey),
"record_window", [overlay](const std::string &id) {
fprintf(stderr, "pressed %s\n", id.c_str());
overlay->toggle_record(RecordForceType::WINDOW);
});
global_hotkeys->bind_key_press(
config_hotkey_to_hotkey(overlay->get_config().streaming_config.start_stop_hotkey),
"stream", [overlay](const std::string &id) {
@@ -441,7 +455,7 @@ namespace gsr {
global_hotkeys_js->bind_action("toggle_record", [overlay](const std::string &id) {
fprintf(stderr, "pressed %s\n", id.c_str());
overlay->toggle_record();
overlay->toggle_record(RecordForceType::NONE);
});
global_hotkeys_js->bind_action("toggle_replay", [overlay](const std::string &id) {
@@ -1285,7 +1299,7 @@ namespace gsr {
} else if(id == "pause") {
toggle_pause();
} else if(id == "start") {
on_press_start_record(false);
on_press_start_record(false, RecordForceType::NONE);
}
};
button->set_item_enabled("pause", false);
@@ -1529,8 +1543,8 @@ namespace gsr {
}
}
void Overlay::toggle_record() {
on_press_start_record(false);
void Overlay::toggle_record(RecordForceType force_type) {
on_press_start_record(false, force_type);
}
void Overlay::toggle_pause() {
@@ -2504,7 +2518,7 @@ namespace gsr {
args.push_back(region_str);
}
static void add_common_gpu_screen_recorder_args(std::vector<const char*> &args, const RecordOptions &record_options, const std::vector<std::string> &audio_tracks, const std::string &video_bitrate, const char *region, char *region_str, int region_str_size, const RegionSelector &region_selector) {
static void add_common_gpu_screen_recorder_args(std::vector<const char*> &args, const RecordOptions &record_options, const std::vector<std::string> &audio_tracks, const std::string &video_bitrate, const char *region, char *region_str, int region_str_size, const RegionSelector &region_selector, const std::string &region_area_option) {
if(record_options.video_quality == "custom") {
args.push_back("-bm");
args.push_back("cbr");
@@ -2515,7 +2529,7 @@ namespace gsr {
args.push_back(record_options.video_quality.c_str());
}
if(record_options.record_area_option == "focused" || record_options.change_video_resolution) {
if(region_area_option == "focused" || record_options.change_video_resolution) {
args.push_back("-s");
args.push_back(region);
}
@@ -2535,7 +2549,7 @@ namespace gsr {
args.push_back("yes");
}
if(record_options.record_area_option == "region")
if(region_area_option == "region")
add_region_command(args, region_str, region_str_size, region_selector);
}
@@ -2892,7 +2906,7 @@ namespace gsr {
}
char region_str[128];
add_common_gpu_screen_recorder_args(args, config.replay_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector);
add_common_gpu_screen_recorder_args(args, config.replay_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector, config.replay_config.record_options.record_area_option);
if(gsr_info.system_info.gsr_version >= GsrVersion{5, 4, 0}) {
args.push_back("-ro");
@@ -2941,7 +2955,7 @@ namespace gsr {
return true;
}
void Overlay::on_press_start_record(bool finished_selection) {
void Overlay::on_press_start_record(bool finished_selection, RecordForceType force_type) {
if(region_selector.is_started() || window_selector.is_started())
return;
@@ -3043,27 +3057,40 @@ namespace gsr {
update_upause_status();
std::string record_area_option;
switch(force_type) {
case RecordForceType::NONE:
record_area_option = config.record_config.record_options.record_area_option;
break;
case RecordForceType::REGION:
record_area_option = "region";
break;
case RecordForceType::WINDOW:
record_area_option = gsr_info.system_info.display_server == DisplayServer::X11 ? "window" : "portal";
break;
}
const SupportedCaptureOptions capture_options = get_supported_capture_options(gsr_info);
recording_capture_target = get_capture_target(config.record_config.record_options.record_area_option, capture_options);
if(!validate_capture_target(config.record_config.record_options.record_area_option, capture_options)) {
recording_capture_target = get_capture_target(record_area_option, capture_options);
if(!validate_capture_target(record_area_option, capture_options)) {
char err_msg[256];
snprintf(err_msg, sizeof(err_msg), "Failed to start recording, capture target \"%s\" is invalid.\nPlease change capture target in settings", recording_capture_target.c_str());
show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::RECORD, nullptr, NotificationLevel::ERROR);
return;
}
if(config.record_config.record_options.record_area_option == "region" && !finished_selection) {
if(record_area_option == "region" && !finished_selection) {
start_region_capture = true;
on_region_selected = [this]() {
on_press_start_record(true);
on_region_selected = [this, force_type]() {
on_press_start_record(true, force_type);
};
return;
}
if(config.record_config.record_options.record_area_option == "window" && !finished_selection) {
if(record_area_option == "window" && !finished_selection) {
start_window_capture = true;
on_window_selected = [this]() {
on_press_start_record(true);
on_window_selected = [this, force_type]() {
on_press_start_record(true, force_type);
};
return;
}
@@ -3083,10 +3110,10 @@ namespace gsr {
char size[64];
size[0] = '\0';
if(config.record_config.record_options.record_area_option == "focused")
if(record_area_option == "focused")
snprintf(size, sizeof(size), "%dx%d", (int)config.record_config.record_options.record_area_width, (int)config.record_config.record_options.record_area_height);
if(config.record_config.record_options.record_area_option != "focused" && config.record_config.record_options.change_video_resolution)
if(record_area_option != "focused" && config.record_config.record_options.change_video_resolution)
snprintf(size, sizeof(size), "%dx%d", (int)config.record_config.record_options.video_width, (int)config.record_config.record_options.video_height);
const std::string capture_source_arg = compose_capture_source_arg(recording_capture_target, config.record_config.record_options);
@@ -3106,7 +3133,7 @@ namespace gsr {
};
char region_str[128];
add_common_gpu_screen_recorder_args(args, config.record_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector);
add_common_gpu_screen_recorder_args(args, config.record_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector, record_area_option);
args.push_back(nullptr);
@@ -3139,7 +3166,7 @@ namespace gsr {
show_notification(msg, short_notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::RECORD, recording_capture_target.c_str());
}
if(config.record_config.record_options.record_area_option == "portal")
if(record_area_option == "portal")
hide_ui = true;
// TODO: This will be incorrect if the user uses portal capture, as capture wont start until the user has
@@ -3304,7 +3331,7 @@ namespace gsr {
};
char region_str[128];
add_common_gpu_screen_recorder_args(args, config.streaming_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector);
add_common_gpu_screen_recorder_args(args, config.streaming_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector, config.streaming_config.record_options.record_area_option);
if(gsr_info.system_info.gsr_version >= GsrVersion{5, 4, 0}) {
args.push_back("-ro");

View File

@@ -304,6 +304,36 @@ namespace gsr {
return list;
}
std::unique_ptr<List> GlobalSettingsPage::create_record_hotkey_window_region_options() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Start/stop recording a region:", get_color_theme().text_color));
auto start_stop_recording_region_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
start_stop_recording_region_button_ptr = start_stop_recording_region_button.get();
list->add_widget(std::move(start_stop_recording_region_button));
char str[128];
if(gsr_info->system_info.display_server == DisplayServer::X11)
snprintf(str, sizeof(str), "Start/stop recording a window:");
else
snprintf(str, sizeof(str), "Start/stop recording with desktop portal:");
list->add_widget(std::make_unique<Label>(&get_theme().body_font, str, get_color_theme().text_color));
auto start_stop_recording_window_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
start_stop_recording_window_button_ptr = start_stop_recording_window_button.get();
list->add_widget(std::move(start_stop_recording_window_button));
start_stop_recording_region_button_ptr->on_click = [this] {
configure_hotkey_start(ConfigureHotkeyType::RECORD_START_STOP_REGION);
};
start_stop_recording_window_button_ptr->on_click = [this] {
configure_hotkey_start(ConfigureHotkeyType::RECORD_START_STOP_WINDOW);
};
return list;
}
std::unique_ptr<List> GlobalSettingsPage::create_stream_hotkey_options() {
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
@@ -375,17 +405,9 @@ namespace gsr {
auto clear_hotkeys_button = std::make_unique<Button>(&get_theme().body_font, "Clear hotkeys", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
clear_hotkeys_button->on_click = [this] {
config.streaming_config.start_stop_hotkey = {mgl::Keyboard::Unknown, 0};
config.record_config.start_stop_hotkey = {mgl::Keyboard::Unknown, 0};
config.record_config.pause_unpause_hotkey = {mgl::Keyboard::Unknown, 0};
config.replay_config.start_stop_hotkey = {mgl::Keyboard::Unknown, 0};
config.replay_config.save_hotkey = {mgl::Keyboard::Unknown, 0};
config.replay_config.save_1_min_hotkey = {mgl::Keyboard::Unknown, 0};
config.replay_config.save_10_min_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.screenshot_config.take_screenshot_window_hotkey = {mgl::Keyboard::Unknown, 0};
config.main_config.show_hide_hotkey = {mgl::Keyboard::Unknown, 0};
for_each_config_hotkey([&](ConfigHotkey *config_hotkey_item) {
*config_hotkey_item = {mgl::Keyboard::Unknown, 0};
});
load_hotkeys();
overlay->rebind_all_keyboard_hotkeys();
};
@@ -424,6 +446,7 @@ namespace gsr {
list_ptr->add_widget(create_replay_hotkey_options());
list_ptr->add_widget(create_replay_partial_save_hotkey_options());
list_ptr->add_widget(create_record_hotkey_options());
list_ptr->add_widget(create_record_hotkey_window_region_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());
@@ -595,6 +618,8 @@ namespace gsr {
start_stop_recording_button_ptr->set_text(config.record_config.start_stop_hotkey.to_string());
pause_unpause_recording_button_ptr->set_text(config.record_config.pause_unpause_hotkey.to_string());
start_stop_recording_region_button_ptr->set_text(config.record_config.start_stop_region_hotkey.to_string());
start_stop_recording_window_button_ptr->set_text(config.record_config.start_stop_window_hotkey.to_string());
start_stop_streaming_button_ptr->set_text(config.streaming_config.start_stop_hotkey.to_string());
@@ -679,6 +704,10 @@ namespace gsr {
return start_stop_recording_button_ptr;
case ConfigureHotkeyType::RECORD_PAUSE_UNPAUSE:
return pause_unpause_recording_button_ptr;
case ConfigureHotkeyType::RECORD_START_STOP_REGION:
return start_stop_recording_region_button_ptr;
case ConfigureHotkeyType::RECORD_START_STOP_WINDOW:
return start_stop_recording_window_button_ptr;
case ConfigureHotkeyType::STREAM_START_STOP:
return start_stop_streaming_button_ptr;
case ConfigureHotkeyType::TAKE_SCREENSHOT:
@@ -709,6 +738,10 @@ namespace gsr {
return &config.record_config.start_stop_hotkey;
case ConfigureHotkeyType::RECORD_PAUSE_UNPAUSE:
return &config.record_config.pause_unpause_hotkey;
case ConfigureHotkeyType::RECORD_START_STOP_REGION:
return &config.record_config.start_stop_region_hotkey;
case ConfigureHotkeyType::RECORD_START_STOP_WINDOW:
return &config.record_config.start_stop_window_hotkey;
case ConfigureHotkeyType::STREAM_START_STOP:
return &config.streaming_config.start_stop_hotkey;
case ConfigureHotkeyType::TAKE_SCREENSHOT:
@@ -727,8 +760,12 @@ namespace gsr {
ConfigHotkey *config_hotkeys[] = {
&config.replay_config.start_stop_hotkey,
&config.replay_config.save_hotkey,
&config.replay_config.save_1_min_hotkey,
&config.replay_config.save_10_min_hotkey,
&config.record_config.start_stop_hotkey,
&config.record_config.pause_unpause_hotkey,
&config.record_config.start_stop_region_hotkey,
&config.record_config.start_stop_window_hotkey,
&config.streaming_config.start_stop_hotkey,
&config.screenshot_config.take_screenshot_hotkey,
&config.screenshot_config.take_screenshot_region_hotkey,
@@ -772,6 +809,15 @@ namespace gsr {
case ConfigureHotkeyType::RECORD_PAUSE_UNPAUSE:
hotkey_configure_action_name = "Pause/unpause recording";
break;
case ConfigureHotkeyType::RECORD_START_STOP_REGION:
hotkey_configure_action_name = "Start/stop recording a region";
break;
case ConfigureHotkeyType::RECORD_START_STOP_WINDOW:
if(gsr_info->system_info.display_server == DisplayServer::X11)
hotkey_configure_action_name = "Start/stop recording a window";
else
hotkey_configure_action_name = "Start/stop recording with desktop portal";
break;
case ConfigureHotkeyType::STREAM_START_STOP:
hotkey_configure_action_name = "Start/stop streaming";
break;

View File

@@ -228,6 +228,7 @@ namespace gsr {
if(!it->mjpeg_setups.empty())
webcam_video_format_box_ptr->add_item("Motion-JPEG", "mjpeg");
webcam_video_format_box_ptr->set_selected_item("auto");
webcam_video_format_box_ptr->set_selected_item(get_current_record_options().webcam_video_format);
selected_camera = *it;
@@ -551,6 +552,7 @@ namespace gsr {
Subsection *audio_subsection = dynamic_cast<Subsection*>(child_widget.get());
List *audio_track_section_items_list_ptr = dynamic_cast<List*>(audio_subsection->get_inner_widget());
List *audio_input_list_ptr = dynamic_cast<List*>(audio_track_section_items_list_ptr->get_child_widget_by_index(2));
CheckBox *application_audio_invert_checkbox_ptr = dynamic_cast<CheckBox*>(audio_track_section_items_list_ptr->get_child_widget_by_index(3));
List *application_audio_warning_list_ptr = dynamic_cast<List*>(audio_track_section_items_list_ptr->get_child_widget_by_index(4));
int num_output_devices = 0;
@@ -576,7 +578,7 @@ namespace gsr {
return true;
});
application_audio_warning_list_ptr->set_visible(num_output_devices > 0 && num_application_audio > 0);
application_audio_warning_list_ptr->set_visible(num_output_devices > 0 && (num_application_audio > 0 || application_audio_invert_checkbox_ptr->is_checked()));
return true;
});
}
@@ -668,6 +670,9 @@ namespace gsr {
std::unique_ptr<CheckBox> SettingsPage::create_application_audio_invert_checkbox() {
auto application_audio_invert_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Record audio from all applications except the selected ones");
application_audio_invert_checkbox->set_checked(false);
application_audio_invert_checkbox->on_changed = [this](bool) {
update_application_audio_warning_visibility();
};
return application_audio_invert_checkbox;
}
@@ -1741,6 +1746,8 @@ namespace gsr {
record_options.use_led_indicator = led_indicator_checkbox_ptr->is_checked();
record_options.low_power_mode = low_power_mode_checkbox_ptr->is_checked();
// TODO: Set selected_camera_setup properly when updating and shit
if(selected_camera_setup.has_value())
webcam_box_size = clamp_keep_aspect_ratio(selected_camera_setup->resolution.to_vec2f(), webcam_box_size);

View File

@@ -56,7 +56,7 @@ static void rpc_add_commands(gsr::Rpc *rpc, gsr::Overlay *overlay) {
rpc->add_handler("toggle-record", [overlay](const std::string &name) {
fprintf(stderr, "rpc command executed: %s\n", name.c_str());
overlay->toggle_record();
overlay->toggle_record(gsr::RecordForceType::NONE);
});
rpc->add_handler("toggle-pause", [overlay](const std::string &name) {
@@ -64,6 +64,16 @@ static void rpc_add_commands(gsr::Rpc *rpc, gsr::Overlay *overlay) {
overlay->toggle_pause();
});
rpc->add_handler("toggle-record-region", [overlay](const std::string &name) {
fprintf(stderr, "rpc command executed: %s\n", name.c_str());
overlay->toggle_record(gsr::RecordForceType::REGION);
});
rpc->add_handler("toggle-record-window", [overlay](const std::string &name) {
fprintf(stderr, "rpc command executed: %s\n", name.c_str());
overlay->toggle_record(gsr::RecordForceType::WINDOW);
});
rpc->add_handler("toggle-stream", [overlay](const std::string &name) {
fprintf(stderr, "rpc command executed: %s\n", name.c_str());
overlay->toggle_stream();