mirror of
https://repo.dec05eba.com/gpu-screen-recorder-ui
synced 2026-03-31 09:17:04 +09:00
Add option to save replay with controller (double-click share button), allow prime-run on wayland
This commit is contained in:
5
TODO
5
TODO
@@ -113,3 +113,8 @@ 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.
|
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).
|
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.
|
||||||
@@ -44,6 +44,7 @@ namespace gsr {
|
|||||||
int32_t config_file_version = 0;
|
int32_t config_file_version = 0;
|
||||||
bool software_encoding_warning_shown = false;
|
bool software_encoding_warning_shown = false;
|
||||||
std::string hotkeys_enable_option = "enable_hotkeys";
|
std::string hotkeys_enable_option = "enable_hotkeys";
|
||||||
|
std::string joystick_hotkeys_enable_option = "disable_hotkeys";
|
||||||
std::string tint_color;
|
std::string tint_color;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
53
include/GlobalHotkeysJoystick.hpp
Normal file
53
include/GlobalHotkeysJoystick.hpp
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "GlobalHotkeys.hpp"
|
||||||
|
#include "Hotplug.hpp"
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <thread>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <mglpp/system/Clock.hpp>
|
||||||
|
#include <linux/joystick.h>
|
||||||
|
|
||||||
|
namespace gsr {
|
||||||
|
static constexpr int max_js_poll_fd = 16;
|
||||||
|
|
||||||
|
class GlobalHotkeysJoystick : public GlobalHotkeys {
|
||||||
|
class GlobalHotkeysJoystickHotplugDelegate;
|
||||||
|
public:
|
||||||
|
GlobalHotkeysJoystick() = default;
|
||||||
|
GlobalHotkeysJoystick(const GlobalHotkeysJoystick&) = delete;
|
||||||
|
GlobalHotkeysJoystick& operator=(const GlobalHotkeysJoystick&) = delete;
|
||||||
|
~GlobalHotkeysJoystick() override;
|
||||||
|
|
||||||
|
bool start();
|
||||||
|
bool bind_action(const std::string &id, GlobalHotkeyCallback callback) override;
|
||||||
|
void poll_events() override;
|
||||||
|
private:
|
||||||
|
void read_events();
|
||||||
|
void process_js_event(int fd, js_event &event);
|
||||||
|
bool add_device(const char *dev_input_filepath, bool print_error = true);
|
||||||
|
bool remove_device(const char *dev_input_filepath);
|
||||||
|
bool remove_poll_fd(int index);
|
||||||
|
// Returns -1 if not found
|
||||||
|
int get_poll_fd_index_by_dev_input_id(int dev_input_id) const;
|
||||||
|
private:
|
||||||
|
struct ExtraData {
|
||||||
|
int dev_input_id = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<std::string, GlobalHotkeyCallback> bound_actions_by_id;
|
||||||
|
std::thread read_thread;
|
||||||
|
|
||||||
|
pollfd poll_fd[max_js_poll_fd];
|
||||||
|
ExtraData extra_data[max_js_poll_fd];
|
||||||
|
int num_poll_fd = 0;
|
||||||
|
int event_fd = -1;
|
||||||
|
int event_index = -1;
|
||||||
|
|
||||||
|
mgl::Clock double_click_clock;
|
||||||
|
int num_times_clicked = 0;
|
||||||
|
bool save_replay = false;
|
||||||
|
int hotplug_poll_index = -1;
|
||||||
|
Hotplug hotplug;
|
||||||
|
};
|
||||||
|
}
|
||||||
33
include/Hotplug.hpp
Normal file
33
include/Hotplug.hpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace gsr {
|
||||||
|
enum class HotplugAction {
|
||||||
|
ADD,
|
||||||
|
REMOVE
|
||||||
|
};
|
||||||
|
|
||||||
|
using HotplugEventCallback = std::function<void(HotplugAction hotplug_action, const char *devname)>;
|
||||||
|
|
||||||
|
class Hotplug {
|
||||||
|
public:
|
||||||
|
Hotplug() = default;
|
||||||
|
Hotplug(const Hotplug&) = delete;
|
||||||
|
Hotplug& operator=(const Hotplug&) = delete;
|
||||||
|
~Hotplug();
|
||||||
|
|
||||||
|
bool start();
|
||||||
|
int steal_fd();
|
||||||
|
void process_event_data(int fd, const HotplugEventCallback &callback);
|
||||||
|
private:
|
||||||
|
void parse_netlink_data(const char *line, const HotplugEventCallback &callback);
|
||||||
|
private:
|
||||||
|
int fd = -1;
|
||||||
|
bool started = false;
|
||||||
|
bool event_is_add = false;
|
||||||
|
bool event_is_remove = false;
|
||||||
|
bool subsystem_is_input = false;
|
||||||
|
char event_data[1024];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -61,6 +61,9 @@ namespace gsr {
|
|||||||
void exit();
|
void exit();
|
||||||
|
|
||||||
const Config& get_config() const;
|
const Config& get_config() const;
|
||||||
|
|
||||||
|
std::function<void(const char *hotkey_option)> on_keyboard_hotkey_changed;
|
||||||
|
std::function<void(const char *hotkey_option)> on_joystick_hotkey_changed;
|
||||||
private:
|
private:
|
||||||
void xi_setup();
|
void xi_setup();
|
||||||
void handle_xi_events();
|
void handle_xi_events();
|
||||||
|
|||||||
@@ -24,13 +24,15 @@ namespace gsr {
|
|||||||
void save();
|
void save();
|
||||||
void on_navigate_away_from_page() override;
|
void on_navigate_away_from_page() override;
|
||||||
|
|
||||||
// Called with (enable, exit_status)
|
std::function<void(bool enable, int exit_status)> on_startup_changed;
|
||||||
std::function<void(bool, int)> on_startup_changed;
|
std::function<void(const char *reason)> on_click_exit_program_button;
|
||||||
// Called with (reason)
|
std::function<void(const char *hotkey_option)> on_keyboard_hotkey_changed;
|
||||||
std::function<void(const char*)> on_click_exit_program_button;
|
std::function<void(const char *hotkey_option)> on_joystick_hotkey_changed;
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Subsection> create_appearance_subsection(ScrollablePage *parent_page);
|
std::unique_ptr<Subsection> create_appearance_subsection(ScrollablePage *parent_page);
|
||||||
std::unique_ptr<Subsection> create_startup_subsection(ScrollablePage *parent_page);
|
std::unique_ptr<Subsection> create_startup_subsection(ScrollablePage *parent_page);
|
||||||
|
std::unique_ptr<RadioButton> create_enable_keyboard_hotkeys_button();
|
||||||
|
std::unique_ptr<RadioButton> create_enable_joystick_hotkeys_button();
|
||||||
std::unique_ptr<Subsection> create_hotkey_subsection(ScrollablePage *parent_page);
|
std::unique_ptr<Subsection> create_hotkey_subsection(ScrollablePage *parent_page);
|
||||||
std::unique_ptr<Button> create_exit_program_button();
|
std::unique_ptr<Button> create_exit_program_button();
|
||||||
std::unique_ptr<Button> create_go_back_to_old_ui_button();
|
std::unique_ptr<Button> create_go_back_to_old_ui_button();
|
||||||
@@ -44,6 +46,7 @@ namespace gsr {
|
|||||||
PageStack *page_stack = nullptr;
|
PageStack *page_stack = nullptr;
|
||||||
RadioButton *tint_color_radio_button_ptr = nullptr;
|
RadioButton *tint_color_radio_button_ptr = nullptr;
|
||||||
RadioButton *startup_radio_button_ptr = nullptr;
|
RadioButton *startup_radio_button_ptr = nullptr;
|
||||||
RadioButton *enable_hotkeys_radio_button_ptr = nullptr;
|
RadioButton *enable_keyboard_hotkeys_radio_button_ptr = nullptr;
|
||||||
|
RadioButton *enable_joystick_hotkeys_radio_button_ptr = nullptr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -38,6 +38,8 @@ src = [
|
|||||||
'src/Overlay.cpp',
|
'src/Overlay.cpp',
|
||||||
'src/GlobalHotkeysX11.cpp',
|
'src/GlobalHotkeysX11.cpp',
|
||||||
'src/GlobalHotkeysLinux.cpp',
|
'src/GlobalHotkeysLinux.cpp',
|
||||||
|
'src/GlobalHotkeysJoystick.cpp',
|
||||||
|
'src/Hotplug.cpp',
|
||||||
'src/Rpc.cpp',
|
'src/Rpc.cpp',
|
||||||
'src/main.cpp',
|
'src/main.cpp',
|
||||||
]
|
]
|
||||||
@@ -49,6 +51,9 @@ prefix = get_option('prefix')
|
|||||||
datadir = get_option('datadir')
|
datadir = get_option('datadir')
|
||||||
gsr_ui_resources_path = join_paths(prefix, datadir, 'gsr-ui')
|
gsr_ui_resources_path = join_paths(prefix, datadir, 'gsr-ui')
|
||||||
|
|
||||||
|
add_project_arguments('-DGSR_UI_VERSION="' + meson.project_version() + '"', language: ['c', 'cpp'])
|
||||||
|
add_project_arguments('-DGSR_FLATPAK_VERSION="5.0.10"', language: ['c', 'cpp'])
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
meson.project_name(),
|
meson.project_name(),
|
||||||
src,
|
src,
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ namespace gsr {
|
|||||||
{"main.config_file_version", &config.main_config.config_file_version},
|
{"main.config_file_version", &config.main_config.config_file_version},
|
||||||
{"main.software_encoding_warning_shown", &config.main_config.software_encoding_warning_shown},
|
{"main.software_encoding_warning_shown", &config.main_config.software_encoding_warning_shown},
|
||||||
{"main.hotkeys_enable_option", &config.main_config.hotkeys_enable_option},
|
{"main.hotkeys_enable_option", &config.main_config.hotkeys_enable_option},
|
||||||
|
{"main.joystick_hotkeys_enable_option", &config.main_config.joystick_hotkeys_enable_option},
|
||||||
{"main.tint_color", &config.main_config.tint_color},
|
{"main.tint_color", &config.main_config.tint_color},
|
||||||
|
|
||||||
{"streaming.record_options.record_area_option", &config.streaming_config.record_options.record_area_option},
|
{"streaming.record_options.record_area_option", &config.streaming_config.record_options.record_area_option},
|
||||||
|
|||||||
236
src/GlobalHotkeysJoystick.cpp
Normal file
236
src/GlobalHotkeysJoystick.cpp
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
#include "../include/GlobalHotkeysJoystick.hpp"
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/eventfd.h>
|
||||||
|
|
||||||
|
namespace gsr {
|
||||||
|
static constexpr double double_click_timeout_seconds = 0.33;
|
||||||
|
|
||||||
|
// Returns -1 on error
|
||||||
|
static int get_js_dev_input_id_from_filepath(const char *dev_input_filepath) {
|
||||||
|
if(strncmp(dev_input_filepath, "/dev/input/js", 13) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int dev_input_id = -1;
|
||||||
|
if(sscanf(dev_input_filepath + 13, "%d", &dev_input_id) == 1)
|
||||||
|
return dev_input_id;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalHotkeysJoystick::~GlobalHotkeysJoystick() {
|
||||||
|
if(event_fd > 0) {
|
||||||
|
const uint64_t exit = 1;
|
||||||
|
write(event_fd, &exit, sizeof(exit));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(read_thread.joinable())
|
||||||
|
read_thread.join();
|
||||||
|
|
||||||
|
if(event_fd > 0)
|
||||||
|
close(event_fd);
|
||||||
|
|
||||||
|
for(int i = 0; i < num_poll_fd; ++i) {
|
||||||
|
close(poll_fd[i].fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GlobalHotkeysJoystick::start() {
|
||||||
|
if(num_poll_fd > 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
event_fd = eventfd(0, 0);
|
||||||
|
if(event_fd <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
event_index = num_poll_fd;
|
||||||
|
poll_fd[num_poll_fd] = {
|
||||||
|
event_fd,
|
||||||
|
POLLIN,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
extra_data[num_poll_fd] = {
|
||||||
|
-1
|
||||||
|
};
|
||||||
|
++num_poll_fd;
|
||||||
|
|
||||||
|
if(!hotplug.start()) {
|
||||||
|
fprintf(stderr, "Warning: failed to setup hotplugging\n");
|
||||||
|
} else {
|
||||||
|
hotplug_poll_index = num_poll_fd;
|
||||||
|
poll_fd[num_poll_fd] = {
|
||||||
|
hotplug.steal_fd(),
|
||||||
|
POLLIN,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
extra_data[num_poll_fd] = {
|
||||||
|
-1
|
||||||
|
};
|
||||||
|
++num_poll_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
char dev_input_path[128];
|
||||||
|
for(int i = 0; i < 8; ++i) {
|
||||||
|
snprintf(dev_input_path, sizeof(dev_input_path), "/dev/input/js%d", i);
|
||||||
|
add_device(dev_input_path, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(num_poll_fd == 0)
|
||||||
|
fprintf(stderr, "Info: no joysticks found, assuming they might be connected later\n");
|
||||||
|
|
||||||
|
read_thread = std::thread(&GlobalHotkeysJoystick::read_events, this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GlobalHotkeysJoystick::bind_action(const std::string &id, GlobalHotkeyCallback callback) {
|
||||||
|
return bound_actions_by_id.insert(std::make_pair(id, std::move(callback))).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalHotkeysJoystick::poll_events() {
|
||||||
|
if(num_poll_fd == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(save_replay) {
|
||||||
|
save_replay = false;
|
||||||
|
auto it = bound_actions_by_id.find("save_replay");
|
||||||
|
if(it != bound_actions_by_id.end())
|
||||||
|
it->second("save_replay");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalHotkeysJoystick::read_events() {
|
||||||
|
js_event event;
|
||||||
|
while(poll(poll_fd, num_poll_fd, -1) > 0) {
|
||||||
|
for(int i = 0; i < num_poll_fd; ++i) {
|
||||||
|
if(poll_fd[i].revents & (POLLHUP|POLLERR|POLLNVAL)) {
|
||||||
|
if(i == event_index)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if(remove_poll_fd(i))
|
||||||
|
--i; // This item was removed so we want to repeat the same index to continue to the next item
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(poll_fd[i].revents & POLLIN))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(i == event_index) {
|
||||||
|
goto done;
|
||||||
|
} else if(i == hotplug_poll_index) {
|
||||||
|
hotplug.process_event_data(poll_fd[i].fd, [&](HotplugAction hotplug_action, const char *devname) {
|
||||||
|
char dev_input_filepath[1024];
|
||||||
|
snprintf(dev_input_filepath, sizeof(dev_input_filepath), "/dev/%s", devname);
|
||||||
|
switch(hotplug_action) {
|
||||||
|
case HotplugAction::ADD: {
|
||||||
|
// Cant open the /dev/input device immediately or it fails.
|
||||||
|
// TODO: Remove this hack when a better solution is found.
|
||||||
|
usleep(50 * 1000);
|
||||||
|
add_device(dev_input_filepath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HotplugAction::REMOVE: {
|
||||||
|
if(remove_device(dev_input_filepath))
|
||||||
|
--i; // This item was removed so we want to repeat the same index to continue to the next item
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
process_js_event(poll_fd[i].fd, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalHotkeysJoystick::process_js_event(int fd, js_event &event) {
|
||||||
|
if(read(fd, &event, sizeof(event)) != sizeof(event))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if((event.type & JS_EVENT_BUTTON) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(event.number == 8 && event.value == 1) {
|
||||||
|
++num_times_clicked;
|
||||||
|
if(num_times_clicked == 1)
|
||||||
|
double_click_clock.restart();
|
||||||
|
else if(num_times_clicked == 2 && double_click_clock.restart() >= double_click_timeout_seconds)
|
||||||
|
num_times_clicked = 0;
|
||||||
|
|
||||||
|
if(num_times_clicked == 2) {
|
||||||
|
save_replay = true;
|
||||||
|
num_times_clicked = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GlobalHotkeysJoystick::add_device(const char *dev_input_filepath, bool print_error) {
|
||||||
|
if(num_poll_fd >= max_js_poll_fd) {
|
||||||
|
fprintf(stderr, "Warning: failed to add joystick device %s, too many joysticks have been added\n", dev_input_filepath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int dev_input_id = get_js_dev_input_id_from_filepath(dev_input_filepath);
|
||||||
|
if(dev_input_id == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int fd = open(dev_input_filepath, O_RDONLY);
|
||||||
|
if(fd <= 0) {
|
||||||
|
if(print_error)
|
||||||
|
fprintf(stderr, "Error: failed to add joystick %s, error: %s\n", dev_input_filepath, strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
poll_fd[num_poll_fd] = {
|
||||||
|
fd,
|
||||||
|
POLLIN,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
extra_data[num_poll_fd] = {
|
||||||
|
dev_input_id
|
||||||
|
};
|
||||||
|
|
||||||
|
++num_poll_fd;
|
||||||
|
fprintf(stderr, "Info: added joystick: %s\n", dev_input_filepath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GlobalHotkeysJoystick::remove_device(const char *dev_input_filepath) {
|
||||||
|
const int dev_input_id = get_js_dev_input_id_from_filepath(dev_input_filepath);
|
||||||
|
if(dev_input_id == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int poll_fd_index = get_poll_fd_index_by_dev_input_id(dev_input_id);
|
||||||
|
if(poll_fd_index == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fprintf(stderr, "Info: removed joystick: %s\n", dev_input_filepath);
|
||||||
|
return remove_poll_fd(poll_fd_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GlobalHotkeysJoystick::remove_poll_fd(int index) {
|
||||||
|
if(index < 0 || index >= num_poll_fd)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
close(poll_fd[index].fd);
|
||||||
|
for(int i = index + 1; i < num_poll_fd; ++i) {
|
||||||
|
poll_fd[i - 1] = poll_fd[i];
|
||||||
|
extra_data[i - 1] = extra_data[i];
|
||||||
|
}
|
||||||
|
--num_poll_fd;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GlobalHotkeysJoystick::get_poll_fd_index_by_dev_input_id(int dev_input_id) const {
|
||||||
|
for(int i = 0; i < num_poll_fd; ++i) {
|
||||||
|
if(dev_input_id == extra_data[i].dev_input_id)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -109,12 +109,12 @@ namespace gsr {
|
|||||||
|
|
||||||
void GlobalHotkeysLinux::poll_events() {
|
void GlobalHotkeysLinux::poll_events() {
|
||||||
if(process_id <= 0) {
|
if(process_id <= 0) {
|
||||||
fprintf(stderr, "error: GlobalHotkeysLinux::poll_events failed, process has not been started yet. Use GlobalHotkeysLinux::start to start the process first\n");
|
//fprintf(stderr, "error: GlobalHotkeysLinux::poll_events failed, process has not been started yet. Use GlobalHotkeysLinux::start to start the process first\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!read_file) {
|
if(!read_file) {
|
||||||
fprintf(stderr, "error: GlobalHotkeysLinux::poll_events failed, read file hasn't opened\n");
|
//fprintf(stderr, "error: GlobalHotkeysLinux::poll_events failed, read file hasn't opened\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -138,6 +138,9 @@ namespace gsr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GlobalHotkeysX11::poll_events() {
|
void GlobalHotkeysX11::poll_events() {
|
||||||
|
if(!dpy)
|
||||||
|
return;
|
||||||
|
|
||||||
while(XPending(dpy)) {
|
while(XPending(dpy)) {
|
||||||
XNextEvent(dpy, &xev);
|
XNextEvent(dpy, &xev);
|
||||||
if(xev.type == KeyPress) {
|
if(xev.type == KeyPress) {
|
||||||
|
|||||||
81
src/Hotplug.cpp
Normal file
81
src/Hotplug.cpp
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#include "../include/Hotplug.hpp"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
|
||||||
|
namespace gsr {
|
||||||
|
Hotplug::~Hotplug() {
|
||||||
|
if(fd > 0)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Hotplug::start() {
|
||||||
|
if(started)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct sockaddr_nl nls = {
|
||||||
|
AF_NETLINK,
|
||||||
|
0,
|
||||||
|
(unsigned int)getpid(),
|
||||||
|
(unsigned int)-1
|
||||||
|
};
|
||||||
|
|
||||||
|
fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
||||||
|
if(fd == -1)
|
||||||
|
return false; /* Not root user */
|
||||||
|
|
||||||
|
if(bind(fd, (const struct sockaddr*)&nls, sizeof(struct sockaddr_nl))) {
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
started = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Hotplug::steal_fd() {
|
||||||
|
const int val = fd;
|
||||||
|
fd = -1;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hotplug::process_event_data(int fd, const HotplugEventCallback &callback) {
|
||||||
|
const int bytes_read = read(fd, event_data, sizeof(event_data));
|
||||||
|
if(bytes_read <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Hotplug data ends with a newline and a null terminator */
|
||||||
|
int data_index = 0;
|
||||||
|
while(data_index < bytes_read) {
|
||||||
|
parse_netlink_data(event_data + data_index, callback);
|
||||||
|
data_index += strlen(event_data + data_index) + 1; /* Skip null terminator as well */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: This assumes SUBSYSTEM= is output before DEVNAME=, is that always true? */
|
||||||
|
void Hotplug::parse_netlink_data(const char *line, const HotplugEventCallback &callback) {
|
||||||
|
const char *at_symbol = strchr(line, '@');
|
||||||
|
if(at_symbol) {
|
||||||
|
event_is_add = strncmp(line, "add@", 4) == 0;
|
||||||
|
event_is_remove = strncmp(line, "remove@", 7) == 0;
|
||||||
|
subsystem_is_input = false;
|
||||||
|
} else if(event_is_add || event_is_remove) {
|
||||||
|
if(strcmp(line, "SUBSYSTEM=input") == 0)
|
||||||
|
subsystem_is_input = true;
|
||||||
|
|
||||||
|
if(subsystem_is_input && strncmp(line, "DEVNAME=", 8) == 0) {
|
||||||
|
if(event_is_add)
|
||||||
|
callback(HotplugAction::ADD, line+8);
|
||||||
|
else if(event_is_remove)
|
||||||
|
callback(HotplugAction::REMOVE, line+8);
|
||||||
|
|
||||||
|
event_is_add = false;
|
||||||
|
event_is_remove = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -942,10 +942,20 @@ namespace gsr {
|
|||||||
show_notification("Failed to remove GPU Screen Recorder from system startup", 3.0, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::NONE);
|
show_notification("Failed to remove GPU Screen Recorder from system startup", 3.0, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::NONE);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
settings_page->on_click_exit_program_button = [&](const char *reason) {
|
|
||||||
|
settings_page->on_click_exit_program_button = [this](const char *reason) {
|
||||||
do_exit = true;
|
do_exit = true;
|
||||||
exit_reason = reason;
|
exit_reason = reason;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
settings_page->on_keyboard_hotkey_changed = [this](const char *hotkey_option) {
|
||||||
|
on_keyboard_hotkey_changed(hotkey_option);
|
||||||
|
};
|
||||||
|
|
||||||
|
settings_page->on_joystick_hotkey_changed = [this](const char *hotkey_option) {
|
||||||
|
on_joystick_hotkey_changed(hotkey_option);
|
||||||
|
};
|
||||||
|
|
||||||
page_stack.push(std::move(settings_page));
|
page_stack.push(std::move(settings_page));
|
||||||
};
|
};
|
||||||
front_page_ptr->add_widget(std::move(button));
|
front_page_ptr->add_widget(std::move(button));
|
||||||
|
|||||||
@@ -9,6 +9,15 @@
|
|||||||
#include "../../include/gui/List.hpp"
|
#include "../../include/gui/List.hpp"
|
||||||
#include "../../include/gui/Label.hpp"
|
#include "../../include/gui/Label.hpp"
|
||||||
#include "../../include/gui/RadioButton.hpp"
|
#include "../../include/gui/RadioButton.hpp"
|
||||||
|
#include "../../include/gui/LineSeparator.hpp"
|
||||||
|
|
||||||
|
#ifndef GSR_UI_VERSION
|
||||||
|
#define GSR_UI_VERSION "unknown"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GSR_FLATPAK_VERSION
|
||||||
|
#define GSR_FLATPAK_VERSION "unknown"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace gsr {
|
namespace gsr {
|
||||||
static const char* gpu_vendor_to_color_name(GpuVendor vendor) {
|
static const char* gpu_vendor_to_color_name(GpuVendor vendor) {
|
||||||
@@ -21,6 +30,16 @@ namespace gsr {
|
|||||||
return "amd";
|
return "amd";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char* gpu_vendor_to_string(GpuVendor vendor) {
|
||||||
|
switch(vendor) {
|
||||||
|
case GpuVendor::UNKNOWN: return "Unknown";
|
||||||
|
case GpuVendor::AMD: return "AMD";
|
||||||
|
case GpuVendor::INTEL: return "Intel";
|
||||||
|
case GpuVendor::NVIDIA: return "NVIDIA";
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
GlobalSettingsPage::GlobalSettingsPage(const GsrInfo *gsr_info, Config &config, PageStack *page_stack) :
|
GlobalSettingsPage::GlobalSettingsPage(const GsrInfo *gsr_info, Config &config, PageStack *page_stack) :
|
||||||
StaticPage(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()),
|
StaticPage(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()),
|
||||||
config(config),
|
config(config),
|
||||||
@@ -88,29 +107,45 @@ namespace gsr {
|
|||||||
return std::make_unique<Subsection>("Startup", std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f));
|
return std::make_unique<Subsection>("Startup", std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Subsection> GlobalSettingsPage::create_hotkey_subsection(ScrollablePage *parent_page) {
|
std::unique_ptr<RadioButton> GlobalSettingsPage::create_enable_keyboard_hotkeys_button() {
|
||||||
const bool inside_flatpak = getenv("FLATPAK_ID") != NULL;
|
auto enable_hotkeys_radio_button = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::HORIZONTAL);
|
||||||
|
enable_keyboard_hotkeys_radio_button_ptr = enable_hotkeys_radio_button.get();
|
||||||
auto enable_hotkeys_radio_button = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::VERTICAL);
|
enable_hotkeys_radio_button->add_item("Yes", "enable_hotkeys");
|
||||||
enable_hotkeys_radio_button_ptr = enable_hotkeys_radio_button.get();
|
enable_hotkeys_radio_button->add_item("No", "disable_hotkeys");
|
||||||
enable_hotkeys_radio_button->add_item("Enable hotkeys", "enable_hotkeys");
|
|
||||||
if(!inside_flatpak)
|
|
||||||
enable_hotkeys_radio_button->add_item("Disable hotkeys", "disable_hotkeys");
|
|
||||||
enable_hotkeys_radio_button->add_item("Only grab virtual devices (supports input remapping software)", "enable_hotkeys_virtual_devices");
|
enable_hotkeys_radio_button->add_item("Only grab virtual devices (supports input remapping software)", "enable_hotkeys_virtual_devices");
|
||||||
enable_hotkeys_radio_button->on_selection_changed = [&](const std::string&, const std::string &id) {
|
enable_hotkeys_radio_button->on_selection_changed = [&](const std::string&, const std::string &id) {
|
||||||
if(!on_click_exit_program_button)
|
if(on_keyboard_hotkey_changed)
|
||||||
return true;
|
on_keyboard_hotkey_changed(id.c_str());
|
||||||
|
|
||||||
if(id == "enable_hotkeys")
|
|
||||||
on_click_exit_program_button("restart");
|
|
||||||
else if(id == "disable_hotkeys")
|
|
||||||
on_click_exit_program_button("restart");
|
|
||||||
else if(id == "enable_hotkeys_virtual_devices")
|
|
||||||
on_click_exit_program_button("restart");
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
return std::make_unique<Subsection>("Hotkeys", std::move(enable_hotkeys_radio_button), mgl::vec2f(parent_page->get_inner_size().x, 0.0f));
|
return enable_hotkeys_radio_button;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<RadioButton> GlobalSettingsPage::create_enable_joystick_hotkeys_button() {
|
||||||
|
auto enable_hotkeys_radio_button = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::HORIZONTAL);
|
||||||
|
enable_joystick_hotkeys_radio_button_ptr = enable_hotkeys_radio_button.get();
|
||||||
|
enable_hotkeys_radio_button->add_item("Yes", "enable_hotkeys");
|
||||||
|
enable_hotkeys_radio_button->add_item("No", "disable_hotkeys");
|
||||||
|
enable_hotkeys_radio_button->on_selection_changed = [&](const std::string&, const std::string &id) {
|
||||||
|
if(on_joystick_hotkey_changed)
|
||||||
|
on_joystick_hotkey_changed(id.c_str());
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
return enable_hotkeys_radio_button;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Subsection> GlobalSettingsPage::create_hotkey_subsection(ScrollablePage *parent_page) {
|
||||||
|
auto list = std::make_unique<List>(List::Orientation::VERTICAL);
|
||||||
|
List *list_ptr = list.get();
|
||||||
|
auto subsection = std::make_unique<Subsection>("Hotkeys", std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f));
|
||||||
|
|
||||||
|
list_ptr->add_widget(std::make_unique<Label>(&get_theme().body_font, "Enable keyboard hotkeys?", get_color_theme().text_color));
|
||||||
|
list_ptr->add_widget(create_enable_keyboard_hotkeys_button());
|
||||||
|
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(std::make_unique<Label>(&get_theme().body_font, "Double-click the share button to save a replay", get_color_theme().text_color));
|
||||||
|
return subsection;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Button> GlobalSettingsPage::create_exit_program_button() {
|
std::unique_ptr<Button> GlobalSettingsPage::create_exit_program_button() {
|
||||||
@@ -133,11 +168,32 @@ namespace gsr {
|
|||||||
|
|
||||||
std::unique_ptr<Subsection> GlobalSettingsPage::create_application_options_subsection(ScrollablePage *parent_page) {
|
std::unique_ptr<Subsection> GlobalSettingsPage::create_application_options_subsection(ScrollablePage *parent_page) {
|
||||||
const bool inside_flatpak = getenv("FLATPAK_ID") != NULL;
|
const bool inside_flatpak = getenv("FLATPAK_ID") != NULL;
|
||||||
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL);
|
auto list = std::make_unique<List>(List::Orientation::VERTICAL);
|
||||||
list->add_widget(create_exit_program_button());
|
List *list_ptr = list.get();
|
||||||
|
auto subsection = std::make_unique<Subsection>("Application options", std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f));
|
||||||
|
|
||||||
|
{
|
||||||
|
auto buttons_list = std::make_unique<List>(List::Orientation::HORIZONTAL);
|
||||||
|
buttons_list->add_widget(create_exit_program_button());
|
||||||
if(inside_flatpak)
|
if(inside_flatpak)
|
||||||
list->add_widget(create_go_back_to_old_ui_button());
|
buttons_list->add_widget(create_go_back_to_old_ui_button());
|
||||||
return std::make_unique<Subsection>("Application options", std::move(list), mgl::vec2f(parent_page->get_inner_size().x, 0.0f));
|
list_ptr->add_widget(std::move(buttons_list));
|
||||||
|
}
|
||||||
|
list_ptr->add_widget(std::make_unique<LineSeparator>(LineSeparator::Orientation::HORIZONTAL, subsection->get_inner_size().x));
|
||||||
|
{
|
||||||
|
char str[256];
|
||||||
|
snprintf(str, sizeof(str), "UI version: %s", GSR_UI_VERSION);
|
||||||
|
list_ptr->add_widget(std::make_unique<Label>(&get_theme().body_font, str, get_color_theme().text_color));
|
||||||
|
|
||||||
|
if(inside_flatpak) {
|
||||||
|
snprintf(str, sizeof(str), "Flatpak version: %s", GSR_FLATPAK_VERSION);
|
||||||
|
list_ptr->add_widget(std::make_unique<Label>(&get_theme().body_font, str, get_color_theme().text_color));
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(str, sizeof(str), "GPU vendor: %s", gpu_vendor_to_string(gsr_info->gpu_info.vendor));
|
||||||
|
list_ptr->add_widget(std::make_unique<Label>(&get_theme().body_font, str, get_color_theme().text_color));
|
||||||
|
}
|
||||||
|
return subsection;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalSettingsPage::add_widgets() {
|
void GlobalSettingsPage::add_widgets() {
|
||||||
@@ -169,12 +225,14 @@ namespace gsr {
|
|||||||
const int exit_status = exec_program_on_host_get_stdout(args, stdout_str);
|
const int exit_status = exec_program_on_host_get_stdout(args, stdout_str);
|
||||||
startup_radio_button_ptr->set_selected_item(exit_status == 0 ? "start_on_system_startup" : "dont_start_on_system_startup", false, false);
|
startup_radio_button_ptr->set_selected_item(exit_status == 0 ? "start_on_system_startup" : "dont_start_on_system_startup", false, false);
|
||||||
|
|
||||||
enable_hotkeys_radio_button_ptr->set_selected_item(config.main_config.hotkeys_enable_option, false, false);
|
enable_keyboard_hotkeys_radio_button_ptr->set_selected_item(config.main_config.hotkeys_enable_option, false, false);
|
||||||
|
enable_joystick_hotkeys_radio_button_ptr->set_selected_item(config.main_config.joystick_hotkeys_enable_option, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalSettingsPage::save() {
|
void GlobalSettingsPage::save() {
|
||||||
config.main_config.tint_color = tint_color_radio_button_ptr->get_selected_id();
|
config.main_config.tint_color = tint_color_radio_button_ptr->get_selected_id();
|
||||||
config.main_config.hotkeys_enable_option = enable_hotkeys_radio_button_ptr->get_selected_id();
|
config.main_config.hotkeys_enable_option = enable_keyboard_hotkeys_radio_button_ptr->get_selected_id();
|
||||||
|
config.main_config.joystick_hotkeys_enable_option = enable_joystick_hotkeys_radio_button_ptr->get_selected_id();
|
||||||
save_config(config);
|
save_config(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
119
src/main.cpp
119
src/main.cpp
@@ -1,7 +1,7 @@
|
|||||||
#include "../include/GsrInfo.hpp"
|
#include "../include/GsrInfo.hpp"
|
||||||
#include "../include/Overlay.hpp"
|
#include "../include/Overlay.hpp"
|
||||||
#include "../include/GlobalHotkeysX11.hpp"
|
|
||||||
#include "../include/GlobalHotkeysLinux.hpp"
|
#include "../include/GlobalHotkeysLinux.hpp"
|
||||||
|
#include "../include/GlobalHotkeysJoystick.hpp"
|
||||||
#include "../include/gui/Utils.hpp"
|
#include "../include/gui/Utils.hpp"
|
||||||
#include "../include/Process.hpp"
|
#include "../include/Process.hpp"
|
||||||
#include "../include/Rpc.hpp"
|
#include "../include/Rpc.hpp"
|
||||||
@@ -41,62 +41,6 @@ static void disable_prime_run() {
|
|||||||
unsetenv("DRI_PRIME");
|
unsetenv("DRI_PRIME");
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<gsr::GlobalHotkeysX11> register_x11_hotkeys(gsr::Overlay *overlay) {
|
|
||||||
auto global_hotkeys = std::make_unique<gsr::GlobalHotkeysX11>();
|
|
||||||
const bool show_hotkey_registered = global_hotkeys->bind_key_press({ XK_z, Mod1Mask }, "show_hide", [overlay](const std::string &id) {
|
|
||||||
fprintf(stderr, "pressed %s\n", id.c_str());
|
|
||||||
overlay->toggle_show();
|
|
||||||
});
|
|
||||||
|
|
||||||
const bool record_hotkey_registered = global_hotkeys->bind_key_press({ XK_F9, Mod1Mask }, "record", [overlay](const std::string &id) {
|
|
||||||
fprintf(stderr, "pressed %s\n", id.c_str());
|
|
||||||
overlay->toggle_record();
|
|
||||||
});
|
|
||||||
|
|
||||||
const bool pause_hotkey_registered = global_hotkeys->bind_key_press({ XK_F7, Mod1Mask }, "pause", [overlay](const std::string &id) {
|
|
||||||
fprintf(stderr, "pressed %s\n", id.c_str());
|
|
||||||
overlay->toggle_pause();
|
|
||||||
});
|
|
||||||
|
|
||||||
const bool stream_hotkey_registered = global_hotkeys->bind_key_press({ XK_F8, Mod1Mask }, "stream", [overlay](const std::string &id) {
|
|
||||||
fprintf(stderr, "pressed %s\n", id.c_str());
|
|
||||||
overlay->toggle_stream();
|
|
||||||
});
|
|
||||||
|
|
||||||
const bool replay_hotkey_registered = global_hotkeys->bind_key_press({ XK_F10, ShiftMask | Mod1Mask }, "replay_start", [overlay](const std::string &id) {
|
|
||||||
fprintf(stderr, "pressed %s\n", id.c_str());
|
|
||||||
overlay->toggle_replay();
|
|
||||||
});
|
|
||||||
|
|
||||||
const bool replay_save_hotkey_registered = global_hotkeys->bind_key_press({ XK_F10, Mod1Mask }, "replay_save", [overlay](const std::string &id) {
|
|
||||||
fprintf(stderr, "pressed %s\n", id.c_str());
|
|
||||||
overlay->save_replay();
|
|
||||||
});
|
|
||||||
|
|
||||||
if(!show_hotkey_registered)
|
|
||||||
fprintf(stderr, "error: failed to register hotkey alt+z for showing the overlay because the hotkey is registered by another program\n");
|
|
||||||
|
|
||||||
if(!record_hotkey_registered)
|
|
||||||
fprintf(stderr, "error: failed to register hotkey alt+f9 for recording because the hotkey is registered by another program\n");
|
|
||||||
|
|
||||||
if(!pause_hotkey_registered)
|
|
||||||
fprintf(stderr, "error: failed to register hotkey alt+f7 for pausing because the hotkey is registered by another program\n");
|
|
||||||
|
|
||||||
if(!stream_hotkey_registered)
|
|
||||||
fprintf(stderr, "error: failed to register hotkey alt+f8 for streaming because the hotkey is registered by another program\n");
|
|
||||||
|
|
||||||
if(!replay_hotkey_registered)
|
|
||||||
fprintf(stderr, "error: failed to register hotkey alt+shift+f10 for starting replay because the hotkey is registered by another program\n");
|
|
||||||
|
|
||||||
if(!replay_save_hotkey_registered)
|
|
||||||
fprintf(stderr, "error: failed to register hotkey alt+f10 for saving replay because the hotkey is registered by another program\n");
|
|
||||||
|
|
||||||
if(!show_hotkey_registered || !record_hotkey_registered || !pause_hotkey_registered || !stream_hotkey_registered || !replay_hotkey_registered || !replay_save_hotkey_registered)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return global_hotkeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::unique_ptr<gsr::GlobalHotkeysLinux> register_linux_hotkeys(gsr::Overlay *overlay, gsr::GlobalHotkeysLinux::GrabType grab_type) {
|
static std::unique_ptr<gsr::GlobalHotkeysLinux> register_linux_hotkeys(gsr::Overlay *overlay, gsr::GlobalHotkeysLinux::GrabType grab_type) {
|
||||||
auto global_hotkeys = std::make_unique<gsr::GlobalHotkeysLinux>(grab_type);
|
auto global_hotkeys = std::make_unique<gsr::GlobalHotkeysLinux>(grab_type);
|
||||||
if(!global_hotkeys->start())
|
if(!global_hotkeys->start())
|
||||||
@@ -135,6 +79,19 @@ static std::unique_ptr<gsr::GlobalHotkeysLinux> register_linux_hotkeys(gsr::Over
|
|||||||
return global_hotkeys;
|
return global_hotkeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<gsr::GlobalHotkeysJoystick> register_joystick_hotkeys(gsr::Overlay *overlay) {
|
||||||
|
auto global_hotkeys_js = std::make_unique<gsr::GlobalHotkeysJoystick>();
|
||||||
|
if(!global_hotkeys_js->start())
|
||||||
|
fprintf(stderr, "Warning: failed to start joystick hotkeys\n");
|
||||||
|
|
||||||
|
global_hotkeys_js->bind_action("save_replay", [overlay](const std::string &id) {
|
||||||
|
fprintf(stderr, "pressed %s\n", id.c_str());
|
||||||
|
overlay->save_replay();
|
||||||
|
});
|
||||||
|
|
||||||
|
return global_hotkeys_js;
|
||||||
|
}
|
||||||
|
|
||||||
static void rpc_add_commands(gsr::Rpc *rpc, gsr::Overlay *overlay) {
|
static void rpc_add_commands(gsr::Rpc *rpc, gsr::Overlay *overlay) {
|
||||||
rpc->add_handler("show_ui", [overlay](const std::string &name) {
|
rpc->add_handler("show_ui", [overlay](const std::string &name) {
|
||||||
fprintf(stderr, "rpc command executed: %s\n", name.c_str());
|
fprintf(stderr, "rpc command executed: %s\n", name.c_str());
|
||||||
@@ -292,9 +249,6 @@ int main(int argc, char **argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cant get window texture when prime-run is used
|
|
||||||
disable_prime_run();
|
|
||||||
|
|
||||||
// Stop nvidia driver from buffering frames
|
// Stop nvidia driver from buffering frames
|
||||||
setenv("__GL_MaxFramesAllowed", "1", true);
|
setenv("__GL_MaxFramesAllowed", "1", true);
|
||||||
// If this is set to 1 then cuGraphicsGLRegisterImage will fail for egl context with error: invalid OpenGL or DirectX context,
|
// If this is set to 1 then cuGraphicsGLRegisterImage will fail for egl context with error: invalid OpenGL or DirectX context,
|
||||||
@@ -307,11 +261,6 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
signal(SIGINT, sigint_handler);
|
signal(SIGINT, sigint_handler);
|
||||||
|
|
||||||
if(mgl_init() != 0) {
|
|
||||||
fprintf(stderr, "Error: failed to initialize mgl. Failed to either connect to the X11 server or setup opengl\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
gsr::GsrInfo gsr_info;
|
gsr::GsrInfo gsr_info;
|
||||||
// TODO: Show the error in ui
|
// TODO: Show the error in ui
|
||||||
gsr::GsrInfoExitStatus gsr_info_exit_status = gsr::get_gpu_screen_recorder_info(&gsr_info);
|
gsr::GsrInfoExitStatus gsr_info_exit_status = gsr::get_gpu_screen_recorder_info(&gsr_info);
|
||||||
@@ -321,8 +270,17 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const gsr::DisplayServer display_server = gsr_info.system_info.display_server;
|
const gsr::DisplayServer display_server = gsr_info.system_info.display_server;
|
||||||
if(display_server == gsr::DisplayServer::WAYLAND)
|
if(display_server == gsr::DisplayServer::WAYLAND) {
|
||||||
fprintf(stderr, "Warning: Wayland support is experimental and requires XWayland. Things may not work as expected.\n");
|
fprintf(stderr, "Warning: Wayland doesn't support this program properly and XWayland is required. Things may not work as expected. Use X11 if you experience issues.\n");
|
||||||
|
} else {
|
||||||
|
// Cant get window texture when prime-run is used
|
||||||
|
disable_prime_run();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mgl_init() != 0) {
|
||||||
|
fprintf(stderr, "Error: failed to initialize mgl. Failed to either connect to the X11 server or setup opengl\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
gsr::SupportedCaptureOptions capture_options = gsr::get_supported_capture_options(gsr_info);
|
gsr::SupportedCaptureOptions capture_options = gsr::get_supported_capture_options(gsr_info);
|
||||||
|
|
||||||
@@ -368,6 +326,28 @@ int main(int argc, char **argv) {
|
|||||||
else if(overlay->get_config().main_config.hotkeys_enable_option == "enable_hotkeys_virtual_devices")
|
else if(overlay->get_config().main_config.hotkeys_enable_option == "enable_hotkeys_virtual_devices")
|
||||||
global_hotkeys = register_linux_hotkeys(overlay.get(), gsr::GlobalHotkeysLinux::GrabType::VIRTUAL);
|
global_hotkeys = register_linux_hotkeys(overlay.get(), gsr::GlobalHotkeysLinux::GrabType::VIRTUAL);
|
||||||
|
|
||||||
|
overlay->on_keyboard_hotkey_changed = [&](const char *hotkey_option) {
|
||||||
|
global_hotkeys.reset();
|
||||||
|
if(strcmp(hotkey_option, "enable_hotkeys") == 0)
|
||||||
|
global_hotkeys = register_linux_hotkeys(overlay.get(), gsr::GlobalHotkeysLinux::GrabType::ALL);
|
||||||
|
else if(strcmp(hotkey_option, "enable_hotkeys_virtual_devices") == 0)
|
||||||
|
global_hotkeys = register_linux_hotkeys(overlay.get(), gsr::GlobalHotkeysLinux::GrabType::VIRTUAL);
|
||||||
|
else if(strcmp(hotkey_option, "disable_hotkeys") == 0)
|
||||||
|
global_hotkeys.reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<gsr::GlobalHotkeysJoystick> global_hotkeys_js = nullptr;
|
||||||
|
if(overlay->get_config().main_config.joystick_hotkeys_enable_option == "enable_hotkeys")
|
||||||
|
global_hotkeys_js = register_joystick_hotkeys(overlay.get());
|
||||||
|
|
||||||
|
overlay->on_joystick_hotkey_changed = [&](const char *hotkey_option) {
|
||||||
|
global_hotkeys_js.reset();
|
||||||
|
if(strcmp(hotkey_option, "enable_hotkeys") == 0)
|
||||||
|
global_hotkeys_js = register_joystick_hotkeys(overlay.get());
|
||||||
|
else if(strcmp(hotkey_option, "disable_hotkeys") == 0)
|
||||||
|
global_hotkeys_js.reset();
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: Add hotkeys in Overlay when using x11 global hotkeys. The hotkeys in Overlay should duplicate each key that is used for x11 global hotkeys.
|
// TODO: Add hotkeys in Overlay when using x11 global hotkeys. The hotkeys in Overlay should duplicate each key that is used for x11 global hotkeys.
|
||||||
|
|
||||||
std::string exit_reason;
|
std::string exit_reason;
|
||||||
@@ -382,6 +362,9 @@ int main(int argc, char **argv) {
|
|||||||
if(global_hotkeys)
|
if(global_hotkeys)
|
||||||
global_hotkeys->poll_events();
|
global_hotkeys->poll_events();
|
||||||
|
|
||||||
|
if(global_hotkeys_js)
|
||||||
|
global_hotkeys_js->poll_events();
|
||||||
|
|
||||||
overlay->handle_events(global_hotkeys.get());
|
overlay->handle_events(global_hotkeys.get());
|
||||||
if(!overlay->draw()) {
|
if(!overlay->draw()) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
@@ -391,8 +374,8 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
fprintf(stderr, "Info: shutting down!\n");
|
fprintf(stderr, "Info: shutting down!\n");
|
||||||
rpc.reset();
|
rpc.reset();
|
||||||
if(global_hotkeys)
|
|
||||||
global_hotkeys.reset();
|
global_hotkeys.reset();
|
||||||
|
global_hotkeys_js.reset();
|
||||||
overlay.reset();
|
overlay.reset();
|
||||||
mgl_deinit();
|
mgl_deinit();
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ bool hotplug_event_init(hotplug_event *self) {
|
|||||||
|
|
||||||
const int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
const int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
||||||
if(fd == -1)
|
if(fd == -1)
|
||||||
return false; /* Not root user */
|
return false;
|
||||||
|
|
||||||
if(bind(fd, (void*)&nls, sizeof(struct sockaddr_nl))) {
|
if(bind(fd, (void*)&nls, sizeof(struct sockaddr_nl))) {
|
||||||
close(fd);
|
close(fd);
|
||||||
@@ -56,19 +56,21 @@ static void hotplug_event_parse_netlink_data(hotplug_event *self, const char *li
|
|||||||
if(strcmp(line, "SUBSYSTEM=input") == 0)
|
if(strcmp(line, "SUBSYSTEM=input") == 0)
|
||||||
self->subsystem_is_input = true;
|
self->subsystem_is_input = true;
|
||||||
|
|
||||||
if(self->subsystem_is_input && strncmp(line, "DEVNAME=", 8) == 0)
|
if(self->subsystem_is_input && strncmp(line, "DEVNAME=", 8) == 0) {
|
||||||
callback(line+8, userdata);
|
callback(line+8, userdata);
|
||||||
|
self->event_is_add = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Netlink uevent structure is documented here: https://web.archive.org/web/20160127215232/https://www.kernel.org/doc/pending/hotplug.txt */
|
/* Netlink uevent structure is documented here: https://web.archive.org/web/20160127215232/https://www.kernel.org/doc/pending/hotplug.txt */
|
||||||
void hotplug_event_process_event_data(hotplug_event *self, int fd, hotplug_device_added_callback callback, void *userdata) {
|
void hotplug_event_process_event_data(hotplug_event *self, int fd, hotplug_device_added_callback callback, void *userdata) {
|
||||||
const int bytes_read = read(fd, self->event_data, sizeof(self->event_data));
|
const int bytes_read = read(fd, self->event_data, sizeof(self->event_data));
|
||||||
int data_index = 0;
|
|
||||||
if(bytes_read <= 0)
|
if(bytes_read <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Hotplug data ends with a newline and a null terminator */
|
/* Hotplug data ends with a newline and a null terminator */
|
||||||
|
int data_index = 0;
|
||||||
while(data_index < bytes_read) {
|
while(data_index < bytes_read) {
|
||||||
hotplug_event_parse_netlink_data(self, self->event_data + data_index, callback, userdata);
|
hotplug_event_parse_netlink_data(self, self->event_data + data_index, callback, userdata);
|
||||||
data_index += strlen(self->event_data + data_index) + 1; /* Skip null terminator as well */
|
data_index += strlen(self->event_data + data_index) + 1; /* Skip null terminator as well */
|
||||||
|
|||||||
@@ -116,6 +116,24 @@ static x11_context setup_x11_context(void) {
|
|||||||
return x_context;
|
return x_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_gsr_global_hotkeys_already_running(void) {
|
||||||
|
FILE *f = fopen("/proc/bus/input/devices", "rb");
|
||||||
|
if(!f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool virtual_keyboard_running = false;
|
||||||
|
char line[1024];
|
||||||
|
while(fgets(line, sizeof(line), f)) {
|
||||||
|
if(strstr(line, "gsr-ui virtual keyboard")) {
|
||||||
|
virtual_keyboard_running = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
return virtual_keyboard_running;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
keyboard_grab_type grab_type = KEYBOARD_GRAB_TYPE_ALL;
|
keyboard_grab_type grab_type = KEYBOARD_GRAB_TYPE_ALL;
|
||||||
if(argc == 2) {
|
if(argc == 2) {
|
||||||
@@ -135,6 +153,11 @@ int main(int argc, char **argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(is_gsr_global_hotkeys_already_running()) {
|
||||||
|
fprintf(stderr, "Error: gsr-global-hotkeys is already running\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
x11_context x_context = setup_x11_context();
|
x11_context x_context = setup_x11_context();
|
||||||
|
|
||||||
const uid_t user_id = getuid();
|
const uid_t user_id = getuid();
|
||||||
|
|||||||
Reference in New Issue
Block a user