mirror of
https://repo.dec05eba.com/gpu-screen-recorder-ui
synced 2026-03-31 09:17:04 +09:00
Support more controllers than real ps4 controllers
This commit is contained in:
2
TODO
2
TODO
@@ -218,8 +218,6 @@ Steam overlay interfers with controller input in gsr ui. Maybe move controller h
|
|||||||
|
|
||||||
Add option to show recording status with scroll lock led (use x11 xkb). Blink when starting/stopping recording and set led on when recording is running and set led off when not recording.
|
Add option to show recording status with scroll lock led (use x11 xkb). Blink when starting/stopping recording and set led on when recording is running and set led off when not recording.
|
||||||
|
|
||||||
Use /dev/input/eventN or /dev/hidrawN for controller input since /dev/input/jsN buttons are different on different controllers, for example home button is different on ps4 (10), gamesir (8) and hori (12).
|
|
||||||
|
|
||||||
For joysticks (gamepads) create a virtual device for each one (/dev/uinput) that has the same vendor, product and name. This is to make sure that it behaves the same way in applications since applications
|
For joysticks (gamepads) create a virtual device for each one (/dev/uinput) that has the same vendor, product and name. This is to make sure that it behaves the same way in applications since applications
|
||||||
access joysticks directly through /dev/input/eventN or /dev/input/jsN. It needs the same number of buttons and pretend to be a controller of the same time, for example a ps4 controller
|
access joysticks directly through /dev/input/eventN or /dev/input/jsN. It needs the same number of buttons and pretend to be a controller of the same time, for example a ps4 controller
|
||||||
so that games automatically display ps4 buttons if supported.
|
so that games automatically display ps4 buttons if supported.
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
#include "../Hotplug.hpp"
|
#include "../Hotplug.hpp"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <linux/joystick.h>
|
#include <linux/input.h>
|
||||||
|
|
||||||
namespace gsr {
|
namespace gsr {
|
||||||
static constexpr int max_js_poll_fd = 16;
|
static constexpr int max_js_poll_fd = 16;
|
||||||
@@ -30,8 +32,10 @@ namespace gsr {
|
|||||||
bool bind_action(const std::string &id, GlobalHotkeyCallback callback) override;
|
bool bind_action(const std::string &id, GlobalHotkeyCallback callback) override;
|
||||||
void poll_events() override;
|
void poll_events() override;
|
||||||
private:
|
private:
|
||||||
|
void close_fds();
|
||||||
void read_events();
|
void read_events();
|
||||||
void process_js_event(int fd, js_event &event);
|
void process_input_event(int fd, input_event &event);
|
||||||
|
void add_all_joystick_devices();
|
||||||
bool add_device(const char *dev_input_filepath, bool print_error = true);
|
bool add_device(const char *dev_input_filepath, bool print_error = true);
|
||||||
bool remove_device(const char *dev_input_filepath);
|
bool remove_device(const char *dev_input_filepath);
|
||||||
bool remove_poll_fd(int index);
|
bool remove_poll_fd(int index);
|
||||||
@@ -45,6 +49,11 @@ namespace gsr {
|
|||||||
std::unordered_map<std::string, GlobalHotkeyCallback> bound_actions_by_id;
|
std::unordered_map<std::string, GlobalHotkeyCallback> bound_actions_by_id;
|
||||||
std::thread read_thread;
|
std::thread read_thread;
|
||||||
|
|
||||||
|
std::thread close_fd_thread;
|
||||||
|
std::vector<int> fds_to_close;
|
||||||
|
std::mutex close_fd_mutex;
|
||||||
|
std::condition_variable close_fd_cv;
|
||||||
|
|
||||||
pollfd poll_fd[max_js_poll_fd];
|
pollfd poll_fd[max_js_poll_fd];
|
||||||
ExtraData extra_data[max_js_poll_fd];
|
ExtraData extra_data[max_js_poll_fd];
|
||||||
int num_poll_fd = 0;
|
int num_poll_fd = 0;
|
||||||
@@ -56,8 +65,6 @@ namespace gsr {
|
|||||||
bool down_pressed = false;
|
bool down_pressed = false;
|
||||||
bool left_pressed = false;
|
bool left_pressed = false;
|
||||||
bool right_pressed = false;
|
bool right_pressed = false;
|
||||||
bool l3_button_pressed = false;
|
|
||||||
bool r3_button_pressed = false;
|
|
||||||
|
|
||||||
bool save_replay = false;
|
bool save_replay = false;
|
||||||
bool save_1_min_replay = false;
|
bool save_1_min_replay = false;
|
||||||
|
|||||||
@@ -3,92 +3,48 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <dirent.h>
|
||||||
#include <sys/eventfd.h>
|
#include <sys/eventfd.h>
|
||||||
|
|
||||||
namespace gsr {
|
namespace gsr {
|
||||||
static constexpr int button_pressed = 1;
|
static constexpr int button_pressed = 1;
|
||||||
static constexpr int cross_button = 0;
|
|
||||||
static constexpr int triangle_button = 2;
|
|
||||||
static constexpr int options_button = 9;
|
|
||||||
static constexpr int playstation_button = 10;
|
|
||||||
static constexpr int l3_button = 11;
|
|
||||||
static constexpr int r3_button = 12;
|
|
||||||
static constexpr int axis_up_down = 7;
|
|
||||||
static constexpr int axis_left_right = 6;
|
|
||||||
|
|
||||||
struct DeviceId {
|
|
||||||
uint16_t vendor;
|
|
||||||
uint16_t product;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool read_file_hex_number(const char *path, unsigned int *value) {
|
|
||||||
*value = 0;
|
|
||||||
FILE *f = fopen(path, "rb");
|
|
||||||
if(!f)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
fscanf(f, "%x", value);
|
|
||||||
fclose(f);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DeviceId joystick_get_device_id(const char *path) {
|
|
||||||
DeviceId device_id;
|
|
||||||
device_id.vendor = 0;
|
|
||||||
device_id.product = 0;
|
|
||||||
|
|
||||||
const char *js_path_id = nullptr;
|
|
||||||
const int len = strlen(path);
|
|
||||||
for(int i = len - 1; i >= 0; --i) {
|
|
||||||
if(path[i] == '/') {
|
|
||||||
js_path_id = path + i + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!js_path_id)
|
|
||||||
return device_id;
|
|
||||||
|
|
||||||
unsigned int vendor = 0;
|
|
||||||
unsigned int product = 0;
|
|
||||||
char path_buf[1024];
|
|
||||||
|
|
||||||
snprintf(path_buf, sizeof(path_buf), "/sys/class/input/%s/device/id/vendor", js_path_id);
|
|
||||||
if(!read_file_hex_number(path_buf, &vendor))
|
|
||||||
return device_id;
|
|
||||||
|
|
||||||
snprintf(path_buf, sizeof(path_buf), "/sys/class/input/%s/device/id/product", js_path_id);
|
|
||||||
if(!read_file_hex_number(path_buf, &product))
|
|
||||||
return device_id;
|
|
||||||
|
|
||||||
device_id.vendor = vendor;
|
|
||||||
device_id.product = product;
|
|
||||||
return device_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_ps4_controller(DeviceId device_id) {
|
|
||||||
return device_id.vendor == 0x054C && (device_id.product == 0x09CC || device_id.product == 0x0BA0 || device_id.product == 0x05C4);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_ps5_controller(DeviceId device_id) {
|
|
||||||
return device_id.vendor == 0x054C && (device_id.product == 0x0DF2 || device_id.product == 0x0CE6);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_stadia_controller(DeviceId device_id) {
|
|
||||||
return device_id.vendor == 0x18D1 && (device_id.product == 0x9400);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns -1 on error
|
// Returns -1 on error
|
||||||
static int get_js_dev_input_id_from_filepath(const char *dev_input_filepath) {
|
static int get_dev_input_event_id_from_filepath(const char *dev_input_filepath) {
|
||||||
if(strncmp(dev_input_filepath, "/dev/input/js", 13) != 0)
|
if(strncmp(dev_input_filepath, "/dev/input/event", 16) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int dev_input_id = -1;
|
int dev_input_id = -1;
|
||||||
if(sscanf(dev_input_filepath + 13, "%d", &dev_input_id) == 1)
|
if(sscanf(dev_input_filepath + 16, "%d", &dev_input_id) == 1)
|
||||||
return dev_input_id;
|
return dev_input_id;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool supports_key(unsigned char *key_bits, unsigned int key) {
|
||||||
|
return key_bits[key/8] & (1 << (key % 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool supports_joystick_keys(unsigned char *key_bits) {
|
||||||
|
const int keys[7] = { BTN_A, BTN_B, BTN_X, BTN_Y, BTN_SELECT, BTN_START, BTN_SELECT };
|
||||||
|
for(int i = 0; i < 7; ++i) {
|
||||||
|
if(supports_key(key_bits, keys[i]))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_input_device_joystick(int input_fd) {
|
||||||
|
unsigned long evbit = 0;
|
||||||
|
ioctl(input_fd, EVIOCGBIT(0, sizeof(evbit)), &evbit);
|
||||||
|
if((evbit & (1 << EV_SYN)) && (evbit & (1 << EV_KEY))) {
|
||||||
|
unsigned char key_bits[KEY_MAX/8 + 1];
|
||||||
|
memset(key_bits, 0, sizeof(key_bits));
|
||||||
|
ioctl(input_fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), &key_bits);
|
||||||
|
return supports_joystick_keys(key_bits);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
GlobalHotkeysJoystick::~GlobalHotkeysJoystick() {
|
GlobalHotkeysJoystick::~GlobalHotkeysJoystick() {
|
||||||
if(event_fd > 0) {
|
if(event_fd > 0) {
|
||||||
const uint64_t exit = 1;
|
const uint64_t exit = 1;
|
||||||
@@ -98,8 +54,18 @@ namespace gsr {
|
|||||||
if(read_thread.joinable())
|
if(read_thread.joinable())
|
||||||
read_thread.join();
|
read_thread.join();
|
||||||
|
|
||||||
if(event_fd > 0)
|
if(event_fd > 0) {
|
||||||
close(event_fd);
|
close(event_fd);
|
||||||
|
event_fd = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
close_fd_cv.notify_one();
|
||||||
|
if(close_fd_thread.joinable())
|
||||||
|
close_fd_thread.join();
|
||||||
|
|
||||||
|
for(int fd : fds_to_close) {
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < num_poll_fd; ++i) {
|
for(int i = 0; i < num_poll_fd; ++i) {
|
||||||
if(poll_fd[i].fd > 0)
|
if(poll_fd[i].fd > 0)
|
||||||
@@ -141,16 +107,10 @@ namespace gsr {
|
|||||||
++num_poll_fd;
|
++num_poll_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
char dev_input_path[128];
|
add_all_joystick_devices();
|
||||||
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);
|
read_thread = std::thread(&GlobalHotkeysJoystick::read_events, this);
|
||||||
|
close_fd_thread = std::thread(&GlobalHotkeysJoystick::close_fds, this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,8 +174,30 @@ namespace gsr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retarded linux takes very long time to close /dev/input/eventN files, even though they are virtual and opened read-only
|
||||||
|
void GlobalHotkeysJoystick::close_fds() {
|
||||||
|
std::vector<int> current_fds_to_close;
|
||||||
|
while(event_fd > 0) {
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(close_fd_mutex);
|
||||||
|
close_fd_cv.wait(lock, [this]{ return !fds_to_close.empty() || event_fd <= 0; });
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(close_fd_mutex);
|
||||||
|
current_fds_to_close = std::move(fds_to_close);
|
||||||
|
fds_to_close.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int fd : current_fds_to_close) {
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
current_fds_to_close.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GlobalHotkeysJoystick::read_events() {
|
void GlobalHotkeysJoystick::read_events() {
|
||||||
js_event event;
|
input_event event;
|
||||||
while(poll(poll_fd, num_poll_fd, -1) > 0) {
|
while(poll(poll_fd, num_poll_fd, -1) > 0) {
|
||||||
for(int i = 0; i < num_poll_fd; ++i) {
|
for(int i = 0; i < num_poll_fd; ++i) {
|
||||||
if(poll_fd[i].revents & (POLLHUP|POLLERR|POLLNVAL)) {
|
if(poll_fd[i].revents & (POLLHUP|POLLERR|POLLNVAL)) {
|
||||||
@@ -223,7 +205,7 @@ namespace gsr {
|
|||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
char dev_input_filepath[256];
|
char dev_input_filepath[256];
|
||||||
snprintf(dev_input_filepath, sizeof(dev_input_filepath), "/dev/input/js%d", extra_data[i].dev_input_id);
|
snprintf(dev_input_filepath, sizeof(dev_input_filepath), "/dev/input/event%d", extra_data[i].dev_input_id);
|
||||||
fprintf(stderr, "Info: removed joystick: %s\n", dev_input_filepath);
|
fprintf(stderr, "Info: removed joystick: %s\n", dev_input_filepath);
|
||||||
if(remove_poll_fd(i))
|
if(remove_poll_fd(i))
|
||||||
--i; // This item was removed so we want to repeat the same index to continue to the next item
|
--i; // This item was removed so we want to repeat the same index to continue to the next item
|
||||||
@@ -240,7 +222,7 @@ namespace gsr {
|
|||||||
hotplug.process_event_data(poll_fd[i].fd, [&](HotplugAction hotplug_action, const char *devname) {
|
hotplug.process_event_data(poll_fd[i].fd, [&](HotplugAction hotplug_action, const char *devname) {
|
||||||
switch(hotplug_action) {
|
switch(hotplug_action) {
|
||||||
case HotplugAction::ADD: {
|
case HotplugAction::ADD: {
|
||||||
add_device(devname);
|
add_device(devname, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HotplugAction::REMOVE: {
|
case HotplugAction::REMOVE: {
|
||||||
@@ -251,7 +233,7 @@ namespace gsr {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
process_js_event(poll_fd[i].fd, event);
|
process_input_event(poll_fd[i].fd, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -260,54 +242,44 @@ namespace gsr {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalHotkeysJoystick::process_js_event(int fd, js_event &event) {
|
void GlobalHotkeysJoystick::process_input_event(int fd, input_event &event) {
|
||||||
if(read(fd, &event, sizeof(event)) != sizeof(event))
|
if(read(fd, &event, sizeof(event)) != sizeof(event))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if((event.type & JS_EVENT_BUTTON) == JS_EVENT_BUTTON) {
|
if(event.type == EV_KEY) {
|
||||||
switch(event.number) {
|
switch(event.code) {
|
||||||
case playstation_button: {
|
case BTN_MODE: {
|
||||||
// Workaround weird steam input (in-game) behavior where steam triggers playstation button + options when pressing both l3 and r3 at the same time
|
playstation_button_pressed = (event.value == button_pressed);
|
||||||
playstation_button_pressed = (event.value == button_pressed) && !l3_button_pressed && !r3_button_pressed;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case options_button: {
|
case BTN_START: {
|
||||||
if(playstation_button_pressed && event.value == button_pressed)
|
if(playstation_button_pressed && event.value == button_pressed)
|
||||||
toggle_show = true;
|
toggle_show = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case cross_button: {
|
case BTN_SOUTH: {
|
||||||
if(playstation_button_pressed && event.value == button_pressed)
|
if(playstation_button_pressed && event.value == button_pressed)
|
||||||
save_1_min_replay = true;
|
save_1_min_replay = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case triangle_button: {
|
case BTN_NORTH: {
|
||||||
if(playstation_button_pressed && event.value == button_pressed)
|
if(playstation_button_pressed && event.value == button_pressed)
|
||||||
save_10_min_replay = true;
|
save_10_min_replay = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case l3_button: {
|
|
||||||
l3_button_pressed = event.value == button_pressed;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case r3_button: {
|
|
||||||
r3_button_pressed = event.value == button_pressed;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if((event.type & JS_EVENT_AXIS) == JS_EVENT_AXIS && playstation_button_pressed) {
|
} else if(event.type == EV_ABS && playstation_button_pressed) {
|
||||||
const int trigger_threshold = 16383;
|
|
||||||
const bool prev_up_pressed = up_pressed;
|
const bool prev_up_pressed = up_pressed;
|
||||||
const bool prev_down_pressed = down_pressed;
|
const bool prev_down_pressed = down_pressed;
|
||||||
const bool prev_left_pressed = left_pressed;
|
const bool prev_left_pressed = left_pressed;
|
||||||
const bool prev_right_pressed = right_pressed;
|
const bool prev_right_pressed = right_pressed;
|
||||||
|
|
||||||
if(event.number == axis_up_down) {
|
if(event.code == ABS_HAT0Y) {
|
||||||
up_pressed = event.value <= -trigger_threshold;
|
up_pressed = event.value == -1;
|
||||||
down_pressed = event.value >= trigger_threshold;
|
down_pressed = event.value == 1;
|
||||||
} else if(event.number == axis_left_right) {
|
} else if(event.code == ABS_HAT0X) {
|
||||||
left_pressed = event.value <= -trigger_threshold;
|
left_pressed = event.value == -1;
|
||||||
right_pressed = event.value >= trigger_threshold;
|
right_pressed = event.value == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(up_pressed && !prev_up_pressed)
|
if(up_pressed && !prev_up_pressed)
|
||||||
@@ -321,13 +293,36 @@ namespace gsr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GlobalHotkeysJoystick::add_all_joystick_devices() {
|
||||||
|
DIR *dir = opendir("/dev/input");
|
||||||
|
if(!dir) {
|
||||||
|
fprintf(stderr, "Error: failed to open /dev/input, error: %s\n", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char dev_input_filepath[1024];
|
||||||
|
for(;;) {
|
||||||
|
struct dirent *entry = readdir(dir);
|
||||||
|
if(!entry)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(strncmp(entry->d_name, "event", 5) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(dev_input_filepath, sizeof(dev_input_filepath), "/dev/input/%s", entry->d_name);
|
||||||
|
add_device(dev_input_filepath, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
bool GlobalHotkeysJoystick::add_device(const char *dev_input_filepath, bool print_error) {
|
bool GlobalHotkeysJoystick::add_device(const char *dev_input_filepath, bool print_error) {
|
||||||
if(num_poll_fd >= max_js_poll_fd) {
|
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);
|
fprintf(stderr, "Warning: failed to add joystick device %s, too many joysticks have been added\n", dev_input_filepath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int dev_input_id = get_js_dev_input_id_from_filepath(dev_input_filepath);
|
const int dev_input_id = get_dev_input_event_id_from_filepath(dev_input_filepath);
|
||||||
if(dev_input_id == -1)
|
if(dev_input_id == -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -338,6 +333,15 @@ namespace gsr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!is_input_device_joystick(fd)) {
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(close_fd_mutex);
|
||||||
|
fds_to_close.push_back(fd);
|
||||||
|
}
|
||||||
|
close_fd_cv.notify_one();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
poll_fd[num_poll_fd] = {
|
poll_fd[num_poll_fd] = {
|
||||||
fd,
|
fd,
|
||||||
POLLIN,
|
POLLIN,
|
||||||
@@ -356,7 +360,7 @@ namespace gsr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GlobalHotkeysJoystick::remove_device(const char *dev_input_filepath) {
|
bool GlobalHotkeysJoystick::remove_device(const char *dev_input_filepath) {
|
||||||
const int dev_input_id = get_js_dev_input_id_from_filepath(dev_input_filepath);
|
const int dev_input_id = get_dev_input_event_id_from_filepath(dev_input_filepath);
|
||||||
if(dev_input_id == -1)
|
if(dev_input_id == -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -372,8 +376,13 @@ namespace gsr {
|
|||||||
if(index < 0 || index >= num_poll_fd)
|
if(index < 0 || index >= num_poll_fd)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(poll_fd[index].fd > 0)
|
if(poll_fd[index].fd > 0) {
|
||||||
close(poll_fd[index].fd);
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(close_fd_mutex);
|
||||||
|
fds_to_close.push_back(poll_fd[index].fd);
|
||||||
|
}
|
||||||
|
close_fd_cv.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = index + 1; i < num_poll_fd; ++i) {
|
for(int i = index + 1; i < num_poll_fd; ++i) {
|
||||||
poll_fd[i - 1] = poll_fd[i];
|
poll_fd[i - 1] = poll_fd[i];
|
||||||
|
|||||||
@@ -234,14 +234,23 @@ static void keyboard_event_process_input_event_data(keyboard_event *self, event_
|
|||||||
/* Retarded linux takes very long time to close /dev/input/eventN files, even though they are virtual and opened read-only */
|
/* Retarded linux takes very long time to close /dev/input/eventN files, even though they are virtual and opened read-only */
|
||||||
static void* keyboard_event_close_fds_callback(void *userdata) {
|
static void* keyboard_event_close_fds_callback(void *userdata) {
|
||||||
keyboard_event *self = userdata;
|
keyboard_event *self = userdata;
|
||||||
|
int fds_to_close_now[MAX_CLOSE_FDS];
|
||||||
|
int num_fds_to_close_now = 0;
|
||||||
|
|
||||||
while(self->running) {
|
while(self->running) {
|
||||||
pthread_mutex_lock(&self->close_dev_input_mutex);
|
pthread_mutex_lock(&self->close_dev_input_mutex);
|
||||||
for(int i = 0; i < self->num_close_fds; ++i) {
|
for(int i = 0; i < self->num_close_fds; ++i) {
|
||||||
close(self->close_fds[i]);
|
fds_to_close_now[i] = self->close_fds[i];
|
||||||
}
|
}
|
||||||
|
num_fds_to_close_now = self->num_close_fds;
|
||||||
self->num_close_fds = 0;
|
self->num_close_fds = 0;
|
||||||
pthread_mutex_unlock(&self->close_dev_input_mutex);
|
pthread_mutex_unlock(&self->close_dev_input_mutex);
|
||||||
|
|
||||||
|
for(int i = 0; i < num_fds_to_close_now; ++i) {
|
||||||
|
close(fds_to_close_now[i]);
|
||||||
|
}
|
||||||
|
num_fds_to_close_now = 0;
|
||||||
|
|
||||||
usleep(100 * 1000); /* 100 milliseconds */
|
usleep(100 * 1000); /* 100 milliseconds */
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -456,9 +465,13 @@ static void keyboard_event_remove_event(keyboard_event *self, int index) {
|
|||||||
if(index < 0 || index >= self->num_event_polls)
|
if(index < 0 || index >= self->num_event_polls)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(self->event_polls[index].fd > 0) {
|
const int poll_fd = self->event_polls[index].fd;
|
||||||
ioctl(self->event_polls[index].fd, EVIOCGRAB, 0);
|
if(poll_fd > 0) {
|
||||||
close(self->event_polls[index].fd);
|
ioctl(poll_fd, EVIOCGRAB, 0);
|
||||||
|
if(!keyboard_event_try_add_close_fd(self, poll_fd)) {
|
||||||
|
fprintf(stderr, "Error: failed to add immediately, closing now\n");
|
||||||
|
close(poll_fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(self->event_extra_data[index].key_states);
|
free(self->event_extra_data[index].key_states);
|
||||||
free(self->event_extra_data[index].key_presses_grabbed);
|
free(self->event_extra_data[index].key_presses_grabbed);
|
||||||
|
|||||||
Reference in New Issue
Block a user