diff --git a/client/include/evdev.h b/client/include/evdev.h index 03c74b3a..ea236548 100644 --- a/client/include/evdev.h +++ b/client/include/evdev.h @@ -44,3 +44,8 @@ void evdev_grabKeyboard(void); * ungrab the keyboard */ void evdev_ungrabKeyboard(void); + +/** + * returns true if input should only be processed by evdev + */ +bool evdev_isExclusive(void); diff --git a/client/src/app.c b/client/src/app.c index 7deeab48..9bdebf70 100644 --- a/client/src/app.c +++ b/client/src/app.c @@ -18,13 +18,14 @@ * Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "app.h" +#include "app_internal.h" #include "main.h" #include "core.h" #include "util.h" #include "clipboard.h" #include "render_queue.h" +#include "evdev.h" #include "kb.h" @@ -119,7 +120,7 @@ void app_handleFocusEvent(bool focused) if (g_params.releaseKeysOnFocusLoss) for (int key = 0; key < KEY_MAX; key++) if (g_state.keyDown[key]) - app_handleKeyRelease(key); + app_handleKeyReleaseInternal(key); g_state.escapeActive = false; @@ -311,7 +312,7 @@ void app_handleWheelMotion(double motion) g_state.io->MouseWheel -= motion; } -void app_handleKeyPress(int sc) +void app_handleKeyPressInternal(int sc) { if (!app_isOverlayMode() || !g_state.io->WantCaptureKeyboard) { @@ -375,7 +376,7 @@ void app_handleKeyPress(int sc) } } -void app_handleKeyRelease(int sc) +void app_handleKeyReleaseInternal(int sc) { if (g_state.escapeActive) { @@ -420,6 +421,18 @@ void app_handleKeyRelease(int sc) } } +void app_handleKeyPress(int sc) +{ + if (!evdev_isExclusive()) + app_handleKeyPressInternal(sc); +} + +void app_handleKeyRelease(int sc) +{ + if (!evdev_isExclusive()) + app_handleKeyReleaseInternal(sc); +} + void app_handleKeyboardTyped(const char * typed) { ImGuiIO_AddInputCharactersUTF8(g_state.io, typed); diff --git a/client/src/app_internal.h b/client/src/app_internal.h index 961cd375..29e2bab7 100644 --- a/client/src/app_internal.h +++ b/client/src/app_internal.h @@ -21,6 +21,8 @@ #ifndef _H_LG_APP_INTERNAL_ #define _H_LG_APP_INTERNAL_ +#include "app.h" + void app_handleKeyPressInternal(int scancode); void app_handleKeyReleaseInternal(int scancode); diff --git a/client/src/evdev.c b/client/src/evdev.c index 6a9534cd..29a83186 100644 --- a/client/src/evdev.c +++ b/client/src/evdev.c @@ -27,7 +27,8 @@ #include #include -#include "app.h" +#include "app_internal.h" +#include "main.h" #include "common/debug.h" #include "common/option.h" @@ -47,9 +48,23 @@ struct EvdevState char * deviceList; EvdevDevice * devices; int deviceCount; + bool exclusive; + int keys[KEY_MAX]; + + void (*dsGrabKeyboard)(void); + void (*dsUngrabKeyboard)(void); + int epoll; LGThread * thread; bool grabbed; + + enum + { + PENDING_NONE, + PENDING_GRAB, + PENDING_UNGRAB + } + pending; }; static struct EvdevState state = {}; @@ -64,6 +79,14 @@ static struct Option options[] = .type = OPTION_TYPE_STRING, .value.x_string = NULL, }, + { + .module = "input", + .name = "evdevExclusive", + .description = "Only use evdev devices for keyboard input when in capture " + "mode", + .type = OPTION_TYPE_BOOL, + .value.x_bool = true + }, {0} }; @@ -89,13 +112,35 @@ static int evdev_thread(void * opaque) continue; } - if (!state.grabbed || ev.type != EV_KEY) + if (ev.type != EV_KEY) continue; + bool grabbed = state.grabbed; if (ev.value == 1) - app_handleKeyPress(ev.code); - else if (ev.value == 0) - app_handleKeyRelease(ev.code); + { + ++state.keys[ev.code]; + + if (grabbed && state.keys[ev.code] == 1) + app_handleKeyPressInternal(ev.code); + } + else if (ev.value == 0 && --state.keys[ev.code] <= 0) + { + state.keys[ev.code] = 0; + + if (state.pending == PENDING_GRAB) + { + state.pending = PENDING_NONE; + evdev_grabKeyboard(); + } + else if (state.pending == PENDING_UNGRAB) + { + state.pending = PENDING_NONE; + evdev_ungrabKeyboard(); + } + + if (grabbed) + app_handleKeyReleaseInternal(ev.code); + } } } DEBUG_INFO("evdev_thread Stopped"); @@ -128,6 +173,8 @@ bool evdev_start(void) if (state.deviceCount == 0) return false; + state.exclusive = option_get("input", "evdevExclusive"); + state.epoll = epoll_create1(0); if (state.epoll < 0) { @@ -166,6 +213,12 @@ bool evdev_start(void) return false; } + //hook the display server's grab methods + state.dsGrabKeyboard = g_state.ds->grabKeyboard; + state.dsUngrabKeyboard = g_state.ds->ungrabKeyboard; + g_state.ds->grabKeyboard = &evdev_grabKeyboard; + g_state.ds->ungrabKeyboard = &evdev_ungrabKeyboard; + return true; } @@ -201,6 +254,19 @@ void evdev_stop(void) void evdev_grabKeyboard(void) { + if (state.grabbed) + return; + + // we must be in a neutral state + for(int i = 0; i < KEY_MAX; ++i) + if (state.keys[i] > 0) + { + state.pending = PENDING_GRAB; + return; + } + +// state.dsGrabKeyboard(); + for(EvdevDevice * device = state.devices; device->path; ++device) { if (device->fd <= 0 || device->grabbed) @@ -220,6 +286,17 @@ void evdev_grabKeyboard(void) void evdev_ungrabKeyboard(void) { + if (!state.grabbed) + return; + + // we must be in a neutral state + for(int i = 0; i < KEY_MAX; ++i) + if (state.keys[i] > 0) + { + state.pending = PENDING_UNGRAB; + return; + } + for(EvdevDevice * device = state.devices; device->path; ++device) { if (device->fd <= 0 || !device->grabbed) @@ -234,5 +311,13 @@ void evdev_ungrabKeyboard(void) DEBUG_INFO("Ungrabbed %s", device->path); device->grabbed = false; } + +// state.dsUngrabKeyboard(); + state.grabbed = false; } + +bool evdev_isExclusive(void) +{ + return state.exclusive && state.grabbed && !app_isOverlayMode(); +} diff --git a/client/src/main.c b/client/src/main.c index e15b80f6..d7bf16e1 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -1242,12 +1242,7 @@ static int lg_run(void) } if (evdev_start()) - { DEBUG_INFO("Using evdev for keyboard capture"); - //override the display server's grab methods if we are using evdev - g_state.ds->grabKeyboard = &evdev_grabKeyboard; - g_state.ds->ungrabKeyboard = &evdev_ungrabKeyboard; - } // override the SIGINIT handler so that we can tell the difference between // SIGINT and the user sending a close event, such as ALT+F4 diff --git a/client/src/main.h b/client/src/main.h index f59baeab..e2f7ed14 100644 --- a/client/src/main.h +++ b/client/src/main.h @@ -72,6 +72,7 @@ struct AppState bool modSuper; uint64_t lastImGuiFrame; bool renderImGuiTwice; + bool exclusiveEvdev; struct LG_DisplayServerOps * ds; bool dsInitialized;