Compare commits

...

21 Commits
1.1.2 ... 1.1.7

Author SHA1 Message Date
dec05eba
b0ab2099fd 1.1.7 2025-02-05 22:36:19 +01:00
dec05eba
4a0612ae8f Update flatpak version 2025-02-05 22:16:22 +01:00
dec05eba
c650974a11 Launch gsr-global-hotkeys in flatpak through kms-server-proxy 2025-02-05 22:12:10 +01:00
dec05eba
6fe9f1a8d5 Fix global hotkeys when using virtual mapper that pretends to be a joystick as well (kanata) 2025-02-05 21:03:42 +01:00
dec05eba
8c148aceda Limit combobox item width, use multiple rows 2025-02-05 20:41:11 +01:00
dec05eba
b4c85910ce 1.1.6 2025-02-03 20:43:08 +01:00
dec05eba
fd63ac3626 Fix for steamdeck 2025-02-03 20:27:35 +01:00
dec05eba
2a0782eb02 Attempt to fix global hotkeys not working on steam deck (grabs keys, cant press buttons) 2025-02-03 19:58:42 +01:00
dec05eba
f505323d56 1.1.5 2025-02-03 01:25:32 +01:00
dec05eba
309cc3425b Use bundled cursor if cursor fails to load 2025-01-27 17:35:35 +01:00
dec05eba
81cb8f539f banana 2025-01-27 16:47:55 +01:00
dec05eba
5214fb1d7f Try fixing missing cursor texture on some broken systems 2025-01-27 16:46:54 +01:00
dec05eba
9aebe81ec4 amend 2025-01-27 11:56:37 +01:00
dec05eba
d73bd68a70 Default to default cursor if cursor not found 2025-01-27 11:53:49 +01:00
dec05eba
3cb156aecb Delegate keyboard grab until a button has been pressed if the device says its a mouse 2025-01-26 17:43:38 +01:00
dec05eba
dea4393588 Revert global hotkeys change, ignore mice again 2025-01-26 14:12:03 +01:00
dec05eba
269d55d7eb 1.1.3 2025-01-26 10:23:45 +01:00
dec05eba
c04e6a87e6 Fix hotkeys not working on some keyboards 2025-01-26 10:23:17 +01:00
dec05eba
d8acac6ba9 Minor visual change 2025-01-25 20:00:51 +01:00
dec05eba
010d4dd5aa Update images 2025-01-25 01:49:16 +01:00
dec05eba
e1397c1c97 Nicer hotkey input design 2025-01-25 00:23:24 +01:00
20 changed files with 155 additions and 92 deletions

View File

@@ -31,7 +31,7 @@ These are the dependencies needed to build GPU Screen Recorder UI:
## Runtime dependencies
There are also additional dependencies needed at runtime:
* [GPU Screen Recorder](https://git.dec05eba.com/gpu-screen-recorder/) (version 5.0.0 or greater)
* [GPU Screen Recorder](https://git.dec05eba.com/gpu-screen-recorder/) (version 5.0.0 or later)
* [GPU Screen Recorder Notification](https://git.dec05eba.com/gpu-screen-recorder-notification/)
## Program behavior notes
@@ -39,14 +39,14 @@ This program has to grab all keyboards and create a virtual keyboard (`gsr-ui vi
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"
# 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`.
This software is licensed under GPL3.0-only. Files under `fonts/` directory belong to the Noto Sans Google fonts project and they are licensed under `SIL Open Font License`. `images/default.cur` it part of the [Adwaita icon theme](https://gitlab.gnome.org/GNOME/adwaita-icon-theme/-/tree/master) which is licensed under `Creative Commons Attribution-Share Alike 3.0`.
# Demo
[![Click here to watch a demo video on youtube](https://img.youtube.com/vi/SOqXusCTXXA/0.jpg)](https://www.youtube.com/watch?v=SOqXusCTXXA)
# Screenshots
![](https://dec05eba.com/images/gsr-overlay-screenshot-front.webp)
![](https://dec05eba.com/images/gsr-overlay-screenshot-settings.webp)
![](https://dec05eba.com/images/front_page.jpg)
![](https://dec05eba.com/images/settings_page.jpg)
# Donations
If you want to donate you can donate via bitcoin or monero.

9
TODO
View File

@@ -107,4 +107,11 @@ When adding window capture only add it to recording and streaming and do the win
Show an error that prime run will be disabled when using desktop portal capture option. This can cause issues as the user may have selected a video codec option that isn't available on their iGPU but is available on the prime-run dGPU.
Is it possible to configure hotkey and the new hotkey to get triggered immediately?
Is it possible to configure hotkey and the new hotkey to get triggered immediately?
For keyboards that report supporting mice the keyboard grab will be delayed until any key has been pressed (and then released), see: https://github.com/dec05eba/gpu-screen-recorder-issues/issues/97
See if there is any way around this.
Instead of installing gsr-global-hotkeys in flatpak use kms-server-proxy to launch gsr-global-hotkeys inside the flatpak with root, just like gsr-kms-server. This removes the need to update gsr-global-hotkeys everytime there is an update.
Check if "modprobe uinput" is needed on some systems (old fedora?).

BIN
images/default.cur Normal file

Binary file not shown.

View File

@@ -1,4 +1,4 @@
project('gsr-ui', ['c', 'cpp'], version : '1.1.2', default_options : ['warning_level=2', 'cpp_std=c++17'], subproject_dir : 'depends')
project('gsr-ui', ['c', 'cpp'], version : '1.1.7', default_options : ['warning_level=2', 'cpp_std=c++17'], subproject_dir : 'depends')
if get_option('buildtype') == 'debug'
add_project_arguments('-g3', language : ['c', 'cpp'])
@@ -52,7 +52,7 @@ datadir = get_option('datadir')
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.1.0"', language: ['c', 'cpp'])
add_project_arguments('-DGSR_FLATPAK_VERSION="5.1.4"', language: ['c', 'cpp'])
executable(
meson.project_name(),
@@ -74,6 +74,7 @@ executable(
[
'tools/gsr-global-hotkeys/hotplug.c',
'tools/gsr-global-hotkeys/keyboard_event.c',
'tools/gsr-global-hotkeys/keys.c',
'tools/gsr-global-hotkeys/main.c'
],
c_args : '-fstack-protector-all',

View File

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

View File

@@ -6,7 +6,6 @@
#include <limits.h>
#include <inttypes.h>
#include <libgen.h>
#include <iostream>
#include <mglpp/window/Keyboard.hpp>
#define FORMAT_I32 "%" PRIi32

View File

@@ -91,15 +91,6 @@ namespace gsr {
if(!user_homepath)
user_homepath = "/tmp";
char gsr_global_hotkeys_flatpak[PATH_MAX];
snprintf(gsr_global_hotkeys_flatpak, sizeof(gsr_global_hotkeys_flatpak), "%s/.local/share/gpu-screen-recorder/gsr-global-hotkeys", user_homepath);
const char *display = getenv("DISPLAY");
if(!display)
display = ":0";
char env_arg[256];
snprintf(env_arg, sizeof(env_arg), "--env=DISPLAY=%s", display);
if(process_id > 0)
return false;
@@ -136,7 +127,7 @@ namespace gsr {
}
if(inside_flatpak) {
const char *args[] = { "flatpak-spawn", "--host", env_arg, "--", gsr_global_hotkeys_flatpak, grab_type_arg, nullptr };
const char *args[] = { "flatpak-spawn", "--host", "/var/lib/flatpak/app/com.dec05eba.gpu_screen_recorder/current/active/files/bin/kms-server-proxy", "launch-gsr-global-hotkeys", user_homepath, grab_type_arg, nullptr };
execvp(args[0], (char* const*)args);
} else {
const char *args[] = { "gsr-global-hotkeys", grab_type_arg, nullptr };

View File

@@ -772,9 +772,32 @@ namespace gsr {
if(cursor_size <= 1)
cursor_size = 24;
XcursorImage *cursor_image = XcursorShapeLoadImage(XC_left_ptr, cursor_theme, cursor_size);
XcursorImage *cursor_image = nullptr;
for(int cursor_size_test : {cursor_size, 24}) {
for(const char *cursor_theme_test : {cursor_theme, "default", "Adwaita"}) {
for(unsigned int shape : {XC_left_ptr, XC_arrow}) {
cursor_image = XcursorShapeLoadImage(shape, cursor_theme_test, cursor_size_test);
if(cursor_image)
goto done;
}
}
}
done:
if(!cursor_image) {
fprintf(stderr, "Error: failed to get cursor, loading bundled default cursor instead\n");
const std::string default_cursor_path = resources_path + "images/default.cur";
for(int cursor_size_test : {cursor_size, 24}) {
cursor_image = XcursorFilenameLoadImage(default_cursor_path.c_str(), cursor_size_test);
if(cursor_image)
break;
}
}
if(!cursor_image) {
fprintf(stderr, "Error: failed to get cursor\n");
XFixesShowCursor(xi_display, DefaultRootWindow(xi_display));
XFlush(xi_display);
return;
}

View File

@@ -26,16 +26,21 @@ namespace gsr {
return true;
if(event.type == mgl::Event::MouseButtonPressed && event.mouse_button.button == mgl::Mouse::Left) {
const int padding_top = padding_top_scale * get_theme().window_height;
const int padding_bottom = padding_bottom_scale * get_theme().window_height;
const mgl::vec2f mouse_pos = { (float)event.mouse_button.x, (float)event.mouse_button.y };
const mgl::vec2f item_size = get_size();
mgl::vec2f item_size = get_size();
if(show_dropdown) {
for(size_t i = 0; i < items.size(); ++i) {
Item &item = items[i];
item_size.y = padding_top + item.text.get_bounds().size.y + padding_bottom;
if(mgl::FloatRect(item.position, item_size).contains(mouse_pos)) {
const size_t prev_selected_item = selected_item;
selected_item = i;
show_dropdown = false;
dirty = true;
remove_widget_as_selected_in_parent();
if(selected_item != prev_selected_item && on_selection_changed)
@@ -47,6 +52,7 @@ namespace gsr {
}
const mgl::vec2f draw_pos = position + offset;
item_size = get_size();
if(mgl::FloatRect(draw_pos, item_size).contains(mouse_pos)) {
show_dropdown = !show_dropdown;
if(show_dropdown)
@@ -66,9 +72,10 @@ namespace gsr {
if(!visible)
return;
//const mgl::Scissor scissor = window.get_scissor();
update_if_dirty();
const mgl::vec2f draw_pos = (position + offset).floor();
//max_size.x = std::min((scissor.position.x + scissor.size.x) - draw_pos.x, max_size.x);
if(show_dropdown)
draw_selected(window, draw_pos);
@@ -78,6 +85,8 @@ namespace gsr {
void ComboBox::add_item(const std::string &text, const std::string &id) {
items.push_back({mgl::Text(text, *font), id, {0.0f, 0.0f}});
items.back().text.set_max_width(font->get_character_size() * 22); // TODO: Make a proper solution
//items.back().text.set_max_rows(1);
dirty = true;
}
@@ -87,6 +96,7 @@ namespace gsr {
if(item.id == id) {
const size_t prev_selected_item = selected_item;
selected_item = i;
dirty = true;
if(trigger_event && (trigger_event_even_if_selection_not_changed || selected_item != prev_selected_item) && on_selection_changed)
on_selection_changed(item.text.get_string(), item.id);
@@ -107,13 +117,13 @@ namespace gsr {
void ComboBox::draw_selected(mgl::Window &window, mgl::vec2f draw_pos) {
const int padding_top = padding_top_scale * get_theme().window_height;
const int padding_bottom = padding_bottom_scale * get_theme().window_height;
const int padding_left = padding_left_scale * get_theme().window_height;
mgl_scissor scissor;
mgl_window_get_scissor(window.internal_window(), &scissor);
const mgl::Scissor scissor = window.get_scissor();
const bool bottom_is_outside_scissor = draw_pos.y + max_size.y > scissor.position.y + scissor.size.y;
const mgl::vec2f item_size = get_size();
mgl::vec2f item_size = get_size();
mgl::vec2f items_draw_pos = draw_pos + mgl::vec2f(0.0f, item_size.y);
mgl::Rectangle background(draw_pos, item_size.floor());
@@ -137,6 +147,9 @@ namespace gsr {
const mgl::vec2f mouse_pos = window.get_mouse_position().to_vec2f();
for(size_t i = 0; i < items.size(); ++i) {
Item &item = items[i];
item_size.y = padding_top + item.text.get_bounds().size.y + padding_bottom;
if(!cursor_inside) {
cursor_inside = mgl::FloatRect(items_draw_pos, item_size).contains(mouse_pos);
if(cursor_inside) {
@@ -146,7 +159,6 @@ namespace gsr {
}
}
Item &item = items[i];
item.text.set_position((items_draw_pos + mgl::vec2f(padding_left, padding_top)).floor());
window.draw(item.text);
@@ -160,7 +172,7 @@ namespace gsr {
const int padding_left = padding_left_scale * get_theme().window_height;
const int padding_right = padding_right_scale * get_theme().window_height;
const mgl::vec2f item_size = get_size();
mgl::vec2f item_size = get_size();
mgl::Rectangle background(draw_pos.floor(), item_size.floor());
background.set_color(mgl::Color(0, 0, 0, 120));
window.draw(background);
@@ -197,11 +209,12 @@ namespace gsr {
const int padding_left = padding_left_scale * get_theme().window_height;
const int padding_right = padding_right_scale * get_theme().window_height;
max_size = { 0.0f, font->get_character_size() + (float)padding_top + (float)padding_bottom };
Item *selected_item_ptr = (selected_item < items.size()) ? &items[selected_item] : nullptr;
max_size = { 0.0f, padding_top + padding_bottom + (selected_item_ptr ? selected_item_ptr->text.get_bounds().size.y : 0.0f) };
for(Item &item : items) {
const mgl::vec2f bounds = item.text.get_bounds().size;
max_size.x = std::max(max_size.x, bounds.x + padding_left + padding_right);
max_size.y += bounds.y + padding_top + padding_bottom;
max_size.y += padding_top + bounds.y + padding_bottom;
}
if(max_size.x <= 0.001f)
@@ -219,7 +232,8 @@ namespace gsr {
const int padding_top = padding_top_scale * get_theme().window_height;
const int padding_bottom = padding_bottom_scale * get_theme().window_height;
return { max_size.x, font->get_character_size() + (float)padding_top + (float)padding_bottom };
Item *selected_item_ptr = (selected_item < items.size()) ? &items[selected_item] : nullptr;
return { max_size.x, padding_top + padding_bottom + (selected_item_ptr ? selected_item_ptr->text.get_bounds().size.y : 0.0f) };
}
float ComboBox::get_dropdown_arrow_height() const {

View File

@@ -17,19 +17,11 @@ namespace gsr {
const mgl::vec2f draw_pos = position + offset;
mgl_scissor prev_scissor;
mgl_window_get_scissor(window.internal_window(), &prev_scissor);
const mgl_scissor new_scissor = {
mgl_vec2i{(int)draw_pos.x, (int)draw_pos.y},
mgl_vec2i{(int)size.x, (int)size.y}
};
mgl_window_set_scissor(window.internal_window(), &new_scissor);
const mgl::Scissor prev_scissor = window.get_scissor();
window.set_scissor({draw_pos.to_vec2i(), size.to_vec2i()});
if(draw_handler)
draw_handler(window, draw_pos, size);
mgl_window_set_scissor(window.internal_window(), &prev_scissor);
window.set_scissor(prev_scissor);
}
mgl::vec2f CustomRendererWidget::get_size() {

View File

@@ -20,7 +20,7 @@ namespace gsr {
{
if(icon_texture && icon_texture->is_valid()) {
icon_sprite.set_texture(icon_texture);
icon_sprite.set_height((int)(size.y * 0.5f));
icon_sprite.set_height((int)(size.y * 0.45f));
}
this->description.set_color(mgl::Color(150, 150, 150));
}
@@ -242,4 +242,4 @@ namespace gsr {
update_if_dirty();
return size;
}
}
}

View File

@@ -65,8 +65,7 @@ namespace gsr {
if(!visible)
return;
mgl_scissor scissor;
mgl_window_get_scissor(window.internal_window(), &scissor);
const mgl::Scissor scissor = window.get_scissor();
const mgl::vec2f draw_pos = position + offset;
const mgl::vec2f mouse_pos = window.get_mouse_position().to_vec2f();

View File

@@ -153,11 +153,14 @@ namespace gsr {
title_text.set_position(mgl::vec2f(bg_rect.get_position() + mgl::vec2f(bg_rect.get_size().x*0.5f - title_text.get_bounds().size.x*0.5f, padding_vertical)).floor());
window.draw(title_text);
//const float description_bottom = description_text.get_position().y + description_text.get_bounds().size.y;
//const float remaining_height = (bg_rect.get_position().y + bg_rect.get_size().y) - description_bottom;
hotkey_text.set_position(mgl::vec2f(bg_rect.get_position() + bg_rect.get_size()*0.5f - hotkey_text.get_bounds().size*0.5f).floor());
window.draw(hotkey_text);
const float caret_padding_x = int(0.001f * get_theme().window_height);
const mgl::vec2f caret_size = mgl::vec2f(std::max(2.0f, 0.002f * get_theme().window_height), hotkey_text.get_bounds().size.y).floor();
mgl::Rectangle caret_rect(hotkey_text.get_position() + mgl::vec2f(hotkey_text.get_bounds().size.x + caret_padding_x, hotkey_text.get_bounds().size.y*0.5f - caret_size.y*0.5f).floor(), caret_size);
window.draw(caret_rect);
description_text.set_position(mgl::vec2f(bg_rect.get_position() + mgl::vec2f(bg_rect.get_size().x*0.5f - description_text.get_bounds().size.x*0.5f, bg_rect.get_size().y - description_text.get_bounds().size.y - padding_vertical)).floor());
window.draw(description_text);
};
@@ -580,6 +583,7 @@ namespace gsr {
content_page_ptr->set_visible(false);
hotkey_overlay_ptr->set_visible(true);
overlay->unbind_all_keyboard_hotkeys();
configure_hotkey_get_button_by_active_type()->set_text("");
switch(hotkey_type) {
case ConfigureHotkeyType::NONE:
@@ -646,4 +650,4 @@ namespace gsr {
hotkey_overlay_ptr->set_visible(false);
overlay->rebind_all_keyboard_hotkeys();
}
}
}

View File

@@ -102,15 +102,8 @@ namespace gsr {
void GsrPage::draw_children(mgl::Window &window, mgl::vec2f position) {
Widget *selected_widget = selected_child_widget;
mgl_scissor prev_scissor;
mgl_window_get_scissor(window.internal_window(), &prev_scissor);
const mgl::vec2f inner_size = get_inner_size();
const mgl_scissor new_scissor = {
mgl_vec2i{(int)position.x, (int)position.y},
mgl_vec2i{(int)inner_size.x, (int)inner_size.y}
};
mgl_window_set_scissor(window.internal_window(), &new_scissor);
const mgl::Scissor prev_scissor = window.get_scissor();
window.set_scissor({position.to_vec2i(), get_inner_size().to_vec2i()});
for(size_t i = 0; i < widgets.size(); ++i) {
auto &widget = widgets[i];
@@ -121,7 +114,7 @@ namespace gsr {
if(selected_widget)
selected_widget->draw(window, position);
mgl_window_set_scissor(window.internal_window(), &prev_scissor);
window.set_scissor(prev_scissor);
}
mgl::vec2f GsrPage::get_size() {

View File

@@ -89,8 +89,7 @@ namespace gsr {
offset = position + offset;
mgl_scissor prev_scissor;
mgl_window_get_scissor(window.internal_window(), &prev_scissor);
const mgl::Scissor prev_scissor = window.get_scissor();
const mgl::vec2f content_size = get_inner_size();
const mgl_scissor new_scissor = {
@@ -150,7 +149,7 @@ namespace gsr {
apply_animation();
limit_scroll(child_height);
mgl_window_set_scissor(window.internal_window(), &prev_scissor);
window.set_scissor(prev_scissor);
double scrollbar_height = 1.0;
if(child_height > 0.001)

View File

@@ -36,14 +36,8 @@ namespace gsr {
offset = draw_pos;
Widget *selected_widget = selected_child_widget;
mgl_scissor prev_scissor;
mgl_window_get_scissor(window.internal_window(), &prev_scissor);
const mgl_scissor new_scissor = {
mgl_vec2i{(int)draw_pos.x, (int)draw_pos.y},
mgl_vec2i{(int)size.x, (int)size.y}
};
mgl_window_set_scissor(window.internal_window(), &new_scissor);
const mgl::Scissor prev_scissor = window.get_scissor();
window.set_scissor({draw_pos.to_vec2i(), size.to_vec2i()});
for(size_t i = 0; i < widgets.size(); ++i) {
auto &widget = widgets[i];
@@ -54,7 +48,7 @@ namespace gsr {
if(selected_widget)
selected_widget->draw(window, offset);
mgl_window_set_scissor(window.internal_window(), &prev_scissor);
window.set_scissor(prev_scissor);
}
mgl::vec2f StaticPage::get_size() {

View File

@@ -1,4 +1,5 @@
#include "keyboard_event.h"
#include "keys.h"
/* C stdlib */
#include <stdio.h>
@@ -81,19 +82,19 @@ static void keyboard_event_fetch_update_key_states(keyboard_event *self, event_e
}
}
static void keyboard_event_process_key_state_change(keyboard_event *self, struct input_event event, event_extra_data *extra_data, int fd) {
if(event.type != EV_KEY)
static void keyboard_event_process_key_state_change(keyboard_event *self, const struct input_event *event, event_extra_data *extra_data, int fd) {
if(event->type != EV_KEY)
return;
if(!extra_data->key_states || event.code >= KEY_STATES_SIZE * 8)
if(!extra_data->key_states || event->code >= KEY_STATES_SIZE * 8)
return;
const unsigned int byte_index = event.code / 8;
const unsigned char bit_index = event.code % 8;
const unsigned int byte_index = event->code / 8;
const unsigned char bit_index = event->code % 8;
unsigned char key_byte_state = extra_data->key_states[byte_index];
const bool prev_key_pressed = (key_byte_state & (1 << bit_index)) != KEY_RELEASE;
if(event.value == KEY_RELEASE) {
if(event->value == KEY_RELEASE) {
key_byte_state &= ~(1 << bit_index);
if(prev_key_pressed)
--extra_data->num_keys_pressed;
@@ -171,8 +172,8 @@ static void keyboard_event_process_input_event_data(keyboard_event *self, event_
//fprintf(stderr, "fd: %d, type: %d, pressed %d, value: %d\n", fd, event.type, event.code, event.value);
//}
if(event.type == EV_KEY) {
keyboard_event_process_key_state_change(self, event, extra_data, fd);
if(event.type == EV_KEY && is_keyboard_key(event.code)) {
keyboard_event_process_key_state_change(self, &event, extra_data, fd);
const uint32_t modifier_bit = keycode_to_modifier_bit(event.code);
if(modifier_bit == 0) {
if(keyboard_event_on_key_pressed(self, &event, self->modifier_button_states))
@@ -270,7 +271,8 @@ static bool keyboard_event_try_add_device_if_keyboard(keyboard_event *self, cons
if(dev_input_id == -1)
return false;
if(self->grab_type == KEYBOARD_GRAB_TYPE_VIRTUAL && !dev_input_is_virtual(dev_input_id))
const bool is_virtual_device = dev_input_is_virtual(dev_input_id);
if(self->grab_type == KEYBOARD_GRAB_TYPE_VIRTUAL && !is_virtual_device)
return false;
if(keyboard_event_has_event_with_dev_input_fd(self, dev_input_id))
@@ -286,7 +288,7 @@ static bool keyboard_event_try_add_device_if_keyboard(keyboard_event *self, cons
unsigned long evbit = 0;
ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), &evbit);
const bool is_keyboard = evbit & (1 << EV_KEY);
const bool is_keyboard = (evbit & (1 << EV_SYN)) && (evbit & (1 << EV_KEY));
if(is_keyboard && strcmp(device_name, GSR_UI_VIRTUAL_KEYBOARD_NAME) != 0) {
unsigned char key_bits[KEY_MAX/8 + 1] = {0};
@@ -297,7 +299,7 @@ static bool keyboard_event_try_add_device_if_keyboard(keyboard_event *self, cons
//const bool supports_touch_events = key_bits[BTN_TOUCH/8] & (1 << (BTN_TOUCH % 8));
const bool supports_joystick_events = key_bits[BTN_JOYSTICK/8] & (1 << (BTN_JOYSTICK % 8));
const bool supports_wheel_events = key_bits[BTN_WHEEL/8] & (1 << (BTN_WHEEL % 8));
if(supports_key_events && !supports_mouse_events && !supports_joystick_events && !supports_wheel_events) {
if(supports_key_events && (is_virtual_device || (!supports_joystick_events && !supports_wheel_events))) {
unsigned char *key_states = calloc(1, KEY_STATES_SIZE);
if(key_states && self->num_event_polls < MAX_EVENT_POLLS) {
//fprintf(stderr, "%s (%s) supports key inputs\n", dev_input_filepath, device_name);
@@ -314,9 +316,16 @@ static bool keyboard_event_try_add_device_if_keyboard(keyboard_event *self, cons
.num_keys_pressed = 0
};
keyboard_event_fetch_update_key_states(self, &self->event_extra_data[self->num_event_polls], fd);
if(self->event_extra_data[self->num_event_polls].num_keys_pressed > 0)
fprintf(stderr, "Info: device not grabbed yet because some keys are still being pressed: /dev/input/event%d\n", dev_input_id);
if(supports_mouse_events || supports_joystick_events || supports_wheel_events) {
fprintf(stderr, "Info: device not grabbed yet because it might be a mouse: /dev/input/event%d\n", dev_input_id);
fsync(fd);
if(ioctl(fd, EVIOCGKEY(KEY_STATES_SIZE), self->event_extra_data[self->num_event_polls].key_states) == -1)
fprintf(stderr, "Warning: failed to fetch key states for device: /dev/input/event%d\n", dev_input_id);
} else {
keyboard_event_fetch_update_key_states(self, &self->event_extra_data[self->num_event_polls], fd);
if(self->event_extra_data[self->num_event_polls].num_keys_pressed > 0)
fprintf(stderr, "Info: device not grabbed yet because some keys are still being pressed: /dev/input/event%d\n", dev_input_id);
}
++self->num_event_polls;
return true;
@@ -389,14 +398,21 @@ static int setup_virtual_keyboard_input(const char *name) {
success &= (ioctl(fd, UI_SET_EVBIT, EV_SYN) != -1);
success &= (ioctl(fd, UI_SET_EVBIT, EV_MSC) != -1);
success &= (ioctl(fd, UI_SET_EVBIT, EV_KEY) != -1);
for(int i = 1; i < KEY_MAX; ++i) {
success &= (ioctl(fd, UI_SET_KEYBIT, i) != -1);
}
success &= (ioctl(fd, UI_SET_EVBIT, EV_REP) != -1);
success &= (ioctl(fd, UI_SET_EVBIT, EV_REL) != -1);
success &= (ioctl(fd, UI_SET_RELBIT, REL_X) != -1);
success &= (ioctl(fd, UI_SET_RELBIT, REL_Y) != -1);
success &= (ioctl(fd, UI_SET_RELBIT, REL_Z) != -1);
success &= (ioctl(fd, UI_SET_EVBIT, EV_LED) != -1);
success &= (ioctl(fd, UI_SET_MSCBIT, MSC_SCAN) != -1);
for(int i = 1; i < KEY_MAX; ++i) {
if(is_keyboard_key(i) || is_mouse_button(i))
success &= (ioctl(fd, UI_SET_KEYBIT, i) != -1);
}
for(int i = 0; i < REL_MAX; ++i) {
success &= (ioctl(fd, UI_SET_RELBIT, i) != -1);
}
for(int i = 0; i < LED_MAX; ++i) {
success &= (ioctl(fd, UI_SET_LEDBIT, i) != -1);
}
// success &= (ioctl(fd, UI_SET_EVBIT, EV_ABS) != -1);
// success &= (ioctl(fd, UI_SET_ABSBIT, ABS_X) != -1);

View File

@@ -0,0 +1,21 @@
#include "keys.h"
#include <linux/input-event-codes.h>
bool is_keyboard_key(uint32_t keycode) {
return (keycode >= KEY_ESC && keycode <= KEY_KPDOT)
|| (keycode >= KEY_ZENKAKUHANKAKU && keycode <= KEY_F24)
|| (keycode >= KEY_PLAYCD && keycode <= KEY_MICMUTE)
|| (keycode >= KEY_OK && keycode <= KEY_IMAGES)
|| (keycode >= KEY_DEL_EOL && keycode <= KEY_DEL_LINE)
|| (keycode >= KEY_FN && keycode <= KEY_FN_B)
|| (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT10)
|| (keycode >= KEY_NUMERIC_0 && keycode <= KEY_LIGHTS_TOGGLE)
|| (keycode == KEY_ALS_TOGGLE)
|| (keycode >= KEY_BUTTONCONFIG && keycode <= KEY_VOICECOMMAND)
|| (keycode >= KEY_BRIGHTNESS_MIN && keycode <= KEY_BRIGHTNESS_MAX)
|| (keycode >= KEY_KBDINPUTASSIST_PREV && keycode <= KEY_ONSCREEN_KEYBOARD);
}
bool is_mouse_button(uint32_t keycode) {
return (keycode >= BTN_MOUSE && keycode <= BTN_TASK);
}

View File

@@ -0,0 +1,10 @@
#ifndef KEYS_H
#define KEYS_H
#include <stdbool.h>
#include <stdint.h>
bool is_keyboard_key(uint32_t keycode);
bool is_mouse_button(uint32_t keycode);
#endif /* KEYS_H */