Compare commits

..

4 Commits
1.3.3 ... 1.3.4

Author SHA1 Message Date
dec05eba
e3e6c3c3b9 1.3.4 2025-04-11 23:24:08 +02:00
dec05eba
38feee9f29 Fix unable to change hotkey settings while recording 2025-04-11 21:51:38 +02:00
dec05eba
90a1272a65 Keyboard remapping info 2025-04-09 19:00:51 +02:00
dec05eba
9ada8caabc Add emergency exit buttons, (left) ctrl+shift+alt+esc to close gpu screen recorder and remove it from system startup 2025-04-09 18:27:45 +02:00
11 changed files with 84 additions and 31 deletions

View File

@@ -38,8 +38,11 @@ There are also additional dependencies needed at runtime:
* [GPU Screen Recorder Notification](https://git.dec05eba.com/gpu-screen-recorder-notification/)
## Program behavior notes
This program has to grab all keyboards and create a virtual keyboard (`gsr-ui virtual keyboard`) to make global hotkeys work on all Wayland compositors.
This might cause issues for you if you use input remapping software. To workaround this you can go into settings and select "Only grab virtual devices"
This program has to grab all keyboards and create a virtual keyboard (`gsr-ui virtual keyboard`) to make global hotkeys work on all Wayland compositors.\
This might cause issues for you if you use keyboard remapping software. To workaround this you can go into settings and select "Only grab virtual devices".\
If you use keyboard remapping software such as keyd then make sure to make it ignore "gsr-ui virtual keyboard" (dec0:5eba device id), otherwise your keyboard can get locked
as gpu screen recorder tries to grab keys and keyd grabs gpu screen recorder, leading to a lock.\
If you are stuck in such a lock where you cant press and keyboard keys you can press (left) ctrl+shift+alt+esc to close gpu screen recorder and remove it from system startup.
# 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`.\

4
TODO
View File

@@ -113,6 +113,8 @@ Check if "modprobe uinput" is needed on some systems (old fedora?).
Add recording timer to see duration of recording/streaming.
Make folder with window name work when using gamescope. Gamescope runs x11 itself so to get the window name inside that we have to connect to the gamescope X11 server (DISPLAY=:1 on x11 and DISPLAY=:2 on wayland, but not always).
Detect if the window is gamescope automatically (WM_CLASS = "gamescope") and get the x11 display automatically and connect to it to get the application its running.
This seems to only be an issue on wayland? the window title of the gamescope/steam bigpicture mode is the title of the game on x11, so it works automatically on x11.
When clicking on current directory in file manager show a dropdown menu where you can select common directories (HOME, Videos, Downloads and mounted drives) for quick navigation. Maybe even button to search.
@@ -158,3 +160,5 @@ Notification with the focused monitor (with CursorTrackerWayland) assumes that t
If CursorTrackerWayland fails then fallback to getting focused monitor by window creation trick. Need to take into consideration prime laptop with dGPU that controls external monitors which cant be captured (different /dev/dri/card device).
Maybe automatically switch to recording with the device that controls the monitor.
In that case also add all monitors available to capture in the capture list and automatically choose the gpu that controls the monitor.
Support cjk font. Use fc-match to find the location of the font. This also works in flatpak, in which case the fonts are in /run/host/..., where it lists system fonts.

View File

@@ -21,6 +21,8 @@ namespace gsr {
bool bind_key_press(Hotkey hotkey, const std::string &id, GlobalHotkeyCallback callback) override;
void unbind_all_keys() override;
void poll_events() override;
private:
void close_fds();
private:
pid_t process_id = 0;
int read_pipes[2];

View File

@@ -65,6 +65,7 @@ namespace gsr {
bool is_open() const;
bool should_exit(std::string &reason) const;
void exit();
void go_back_to_old_ui();
const Config& get_config() const;

View File

@@ -1,4 +1,4 @@
project('gsr-ui', ['c', 'cpp'], version : '1.3.3', default_options : ['warning_level=2', 'cpp_std=c++17'], subproject_dir : 'depends')
project('gsr-ui', ['c', 'cpp'], version : '1.3.4', default_options : ['warning_level=2', 'cpp_std=c++17'], subproject_dir : 'depends')
if get_option('buildtype') == 'debug'
add_project_arguments('-g3', language : ['c', 'cpp'])

View File

@@ -1,7 +1,7 @@
[package]
name = "gsr-ui"
type = "executable"
version = "1.3.3"
version = "1.3.4"
platforms = ["posix"]
[lang.cpp]

View File

@@ -1,5 +1,4 @@
#include "../include/GlobalHotkeysLinux.hpp"
#include <signal.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <limits.h>
@@ -71,22 +70,40 @@ namespace gsr {
}
GlobalHotkeysLinux::~GlobalHotkeysLinux() {
for(int i = 0; i < 2; ++i) {
if(read_pipes[i] > 0)
close(read_pipes[i]);
if(write_pipes[i] > 0)
close(write_pipes[i]);
if(write_pipes[PIPE_WRITE] > 0) {
char command[32];
const int command_size = snprintf(command, sizeof(command), "exit\n");
if(write(write_pipes[PIPE_WRITE], command, command_size) != command_size) {
fprintf(stderr, "Error: GlobalHotkeysLinux::~GlobalHotkeysLinux: failed to write command to gsr-global-hotkeys, error: %s\n", strerror(errno));
close_fds();
}
}
if(read_file)
fclose(read_file);
if(process_id > 0) {
kill(process_id, SIGKILL);
int status;
waitpid(process_id, &status, 0);
}
close_fds();
}
void GlobalHotkeysLinux::close_fds() {
for(int i = 0; i < 2; ++i) {
if(read_pipes[i] > 0) {
close(read_pipes[i]);
read_pipes[i] = -1;
}
if(write_pipes[i] > 0) {
close(write_pipes[i]);
write_pipes[i] = -1;
}
}
if(read_file) {
fclose(read_file);
read_file = nullptr;
}
}
bool GlobalHotkeysLinux::start() {

View File

@@ -338,6 +338,13 @@ namespace gsr {
fprintf(stderr, "pressed %s\n", id.c_str());
overlay->take_screenshot_region();
});
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) {
fprintf(stderr, "pressed %s\n", id.c_str());
overlay->go_back_to_old_ui();
});
}
static std::unique_ptr<GlobalHotkeysLinux> register_linux_hotkeys(Overlay *overlay, GlobalHotkeysLinux::GrabType grab_type) {
@@ -1468,6 +1475,19 @@ namespace gsr {
do_exit = true;
}
void Overlay::go_back_to_old_ui() {
const bool inside_flatpak = getenv("FLATPAK_ID") != NULL;
if(inside_flatpak)
exit_reason = "back-to-old-ui";
else
exit_reason = "exit";
const char *args[] = { "systemctl", "disable", "--user", "gpu-screen-recorder-ui", nullptr };
std::string stdout_str;
exec_program_on_host_get_stdout(args, stdout_str);
exit();
}
const Config& Overlay::get_config() const {
return config;
}
@@ -1560,9 +1580,9 @@ namespace gsr {
return;
if(is_capture_target_monitor(recording_capture_target.c_str()))
snprintf(msg, sizeof(msg), "Saved recording of this monitor to '%s'", filename.c_str());
snprintf(msg, sizeof(msg), "Saved a recording of this monitor to '%s'", filename.c_str());
else
snprintf(msg, sizeof(msg), "Saved recording of %s to '%s'", recording_capture_target.c_str(), filename.c_str());
snprintf(msg, sizeof(msg), "Saved a recording of %s to '%s'", recording_capture_target.c_str(), filename.c_str());
capture_target = recording_capture_target.c_str();
break;
@@ -1572,9 +1592,9 @@ namespace gsr {
return;
if(is_capture_target_monitor(replay_capture_target.c_str()))
snprintf(msg, sizeof(msg), "Saved replay of this monitor to '%s'", filename.c_str());
snprintf(msg, sizeof(msg), "Saved a replay of this monitor to '%s'", filename.c_str());
else
snprintf(msg, sizeof(msg), "Saved replay of %s to '%s'", replay_capture_target.c_str(), filename.c_str());
snprintf(msg, sizeof(msg), "Saved a replay of %s to '%s'", replay_capture_target.c_str(), filename.c_str());
capture_target = replay_capture_target.c_str();
break;
@@ -1584,9 +1604,9 @@ namespace gsr {
return;
if(is_capture_target_monitor(screenshot_capture_target.c_str()))
snprintf(msg, sizeof(msg), "Saved screenshot of this monitor to '%s'", filename.c_str());
snprintf(msg, sizeof(msg), "Saved a screenshot of this monitor to '%s'", filename.c_str());
else
snprintf(msg, sizeof(msg), "Saved screenshot of %s to '%s'", screenshot_capture_target.c_str(), filename.c_str());
snprintf(msg, sizeof(msg), "Saved a screenshot of %s to '%s'", screenshot_capture_target.c_str(), filename.c_str());
capture_target = screenshot_capture_target.c_str();
break;
@@ -1606,9 +1626,9 @@ namespace gsr {
const std::string filename = filepath_get_filename(replay_saved_filepath);
char msg[512];
if(is_capture_target_monitor(replay_capture_target.c_str()))
snprintf(msg, sizeof(msg), "Saved replay of this monitor to '%s'", filename.c_str());
snprintf(msg, sizeof(msg), "Saved a replay of this monitor to '%s'", filename.c_str());
else
snprintf(msg, sizeof(msg), "Saved replay of %s to '%s'", replay_capture_target.c_str(), filename.c_str());
snprintf(msg, sizeof(msg), "Saved a replay of %s to '%s'", replay_capture_target.c_str(), filename.c_str());
show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::REPLAY, replay_capture_target.c_str());
}
}
@@ -1709,9 +1729,9 @@ namespace gsr {
const std::string filename = filepath_get_filename(screenshot_filepath.c_str());
char msg[512];
if(is_capture_target_monitor(screenshot_capture_target.c_str()))
snprintf(msg, sizeof(msg), "Saved screenshot of this monitor to '%s'", filename.c_str());
snprintf(msg, sizeof(msg), "Saved a screenshot of this monitor to '%s'", filename.c_str());
else
snprintf(msg, sizeof(msg), "Saved screenshot of %s to '%s'", screenshot_capture_target.c_str(), filename.c_str());
snprintf(msg, sizeof(msg), "Saved a screenshot of %s to '%s'", screenshot_capture_target.c_str(), filename.c_str());
show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::SCREENSHOT, screenshot_capture_target.c_str());
}
} else {
@@ -1815,9 +1835,9 @@ namespace gsr {
const std::string filename = filepath_get_filename(record_filepath.c_str());
char msg[512];
if(is_capture_target_monitor(recording_capture_target.c_str()))
snprintf(msg, sizeof(msg), "Saved recording of this monitor to '%s'", filename.c_str());
snprintf(msg, sizeof(msg), "Saved a recording of this monitor to '%s'", filename.c_str());
else
snprintf(msg, sizeof(msg), "Saved recording of %s to '%s'", recording_capture_target.c_str(), filename.c_str());
snprintf(msg, sizeof(msg), "Saved a recording of %s to '%s'", recording_capture_target.c_str(), filename.c_str());
show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::RECORD, recording_capture_target.c_str());
}
} else {

View File

@@ -303,9 +303,6 @@ int main(int argc, char **argv) {
if(exit_reason == "back-to-old-ui") {
const char *args[] = { "gpu-screen-recorder-gtk", "use-old-ui", nullptr };
execvp(args[0], (char* const*)args);
} else if(exit_reason == "restart") {
const char *args[] = { "gsr-ui", "launch-show", nullptr };
execvp(args[0], (char* const*)args);
}
return 0;

View File

@@ -18,4 +18,10 @@ To unbind all keys send `unbind_all<newline>` to the programs stdin, for example
```
unbind_all
```
## Exit
To close gsr-global-hotkeys send `exit<newline>` to the programs stdin, for example:
```
exit
```

View File

@@ -707,8 +707,11 @@ static void keyboard_event_parse_stdin_command(keyboard_event *self, const char
}
self->num_global_hotkeys = 0;
fprintf(stderr, "Info: unbinded all hotkeys\n");
} else if(strncmp(command, "exit", 4) == 0) {
self->stdin_failed = true;
fprintf(stderr, "Info: received exit command\n");
} else {
fprintf(stderr, "Warning: got invalid command: \"%s\", expected command to start with either \"bind\" or \"unbind_all\"\n", command);
fprintf(stderr, "Warning: got invalid command: \"%s\", expected command to start with either \"bind\", \"unbind_all\" or \"exit\"\n", command);
}
}