From 94010d6b9afae7d9dfde910cf18b81d148374426 Mon Sep 17 00:00:00 2001 From: TheOnlyMrCat Date: Wed, 11 Oct 2023 20:24:10 +1000 Subject: [PATCH] events: Use xkbcommon for keyboard event handling (#43) --- CMakeLists.txt | 2 +- nix/default.nix | 2 ++ src/events/Events.cpp | 47 ++++++++++++++++++++++++++++++++++++++++--- src/hyprpicker.cpp | 4 ++++ src/hyprpicker.hpp | 4 ++++ src/includes.hpp | 1 + 6 files changed, 56 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f122158..edbf5ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,7 @@ add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-m find_package(Threads REQUIRED) find_package(PkgConfig REQUIRED) -pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-client wayland-protocols cairo pango pangocairo libjpeg) +pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-client wayland-protocols xkbcommon cairo pango pangocairo libjpeg) file(GLOB_RECURSE SRCFILES "src/*.cpp") diff --git a/nix/default.nix b/nix/default.nix index f850743..85a9796 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -11,6 +11,7 @@ libselinux, libsepol, libthai, + libxkbcommon, pango, pcre, utillinux, @@ -50,6 +51,7 @@ stdenv.mkDerivation { wayland-scanner wlroots libXdmcp + libxkbcommon utillinux ]; diff --git a/src/events/Events.cpp b/src/events/Events.cpp index ccf333e..b6d3006 100644 --- a/src/events/Events.cpp +++ b/src/events/Events.cpp @@ -246,10 +246,46 @@ void Events::handlePointerButton(void* data, struct wl_pointer* wl_pointer, uint g_pHyprpicker->finish(); } -void Events::handleKeyboardKeymap(void* data, wl_keyboard* wl_keyboard, uint format, int fd, uint size) {} +void Events::handleKeyboardKeymap(void* data, wl_keyboard* wl_keyboard, uint format, int fd, uint size) { + if (!g_pHyprpicker->m_pXKBContext) + return; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + Debug::log(ERR, "Could not recognise keymap format"); + return; + } + + const char* buf = (const char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (buf == MAP_FAILED) { + Debug::log(ERR, "Failed to mmap xkb keymap: %d", errno); + return; + } + + g_pHyprpicker->m_pXKBKeymap = xkb_keymap_new_from_buffer(g_pHyprpicker->m_pXKBContext, buf, size - 1, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + + munmap((void*)buf, size); + close(fd); + + if (!g_pHyprpicker->m_pXKBKeymap) { + Debug::log(ERR, "Failed to compile xkb keymap"); + return; + } + + g_pHyprpicker->m_pXKBState = xkb_state_new(g_pHyprpicker->m_pXKBKeymap); + if (!g_pHyprpicker->m_pXKBState) { + Debug::log(ERR, "Failed to create xkb state"); + return; + } +} void Events::handleKeyboardKey(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { - if (key == 1) // escape + if (state != WL_KEYBOARD_KEY_STATE_PRESSED) + return; + + if (g_pHyprpicker->m_pXKBState) { + if (xkb_state_key_get_one_sym(g_pHyprpicker->m_pXKBState, key + 8) == XKB_KEY_Escape) + g_pHyprpicker->finish(); + } else if (key == 1) // Assume keycode 1 is escape g_pHyprpicker->finish(); } @@ -257,7 +293,12 @@ void Events::handleKeyboardEnter(void* data, wl_keyboard* wl_keyboard, uint seri void Events::handleKeyboardLeave(void* data, wl_keyboard* wl_keyboard, uint serial, wl_surface* surface) {} -void Events::handleKeyboardModifiers(void* data, wl_keyboard* wl_keyboard, uint serial, uint mods_depressed, uint mods_latched, uint mods_locked, uint group) {} +void Events::handleKeyboardModifiers(void* data, wl_keyboard* wl_keyboard, uint serial, uint mods_depressed, uint mods_latched, uint mods_locked, uint group) { + if (!g_pHyprpicker->m_pXKBState) + return; + + xkb_state_update_mask(g_pHyprpicker->m_pXKBState, mods_depressed, mods_latched, mods_locked, 0, 0, group); +} void Events::handleFrameDone(void* data, struct wl_callback* callback, uint32_t time) { CLayerSurface* pLS = (CLayerSurface*)data; diff --git a/src/hyprpicker.cpp b/src/hyprpicker.cpp index 6c3d0d9..3fa657c 100644 --- a/src/hyprpicker.cpp +++ b/src/hyprpicker.cpp @@ -8,6 +8,10 @@ void sigHandler(int sig) { } void CHyprpicker::init() { + m_pXKBContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!m_pXKBContext) + Debug::log(ERR, "Failed to create xkb context"); + m_pWLDisplay = wl_display_connect(nullptr); if (!m_pWLDisplay) { diff --git a/src/hyprpicker.hpp b/src/hyprpicker.hpp index 17fd15c..60a8851 100644 --- a/src/hyprpicker.hpp +++ b/src/hyprpicker.hpp @@ -26,6 +26,10 @@ class CHyprpicker { zwlr_layer_shell_v1* m_pLayerShell; zwlr_screencopy_manager_v1* m_pSCMgr; + xkb_context* m_pXKBContext = nullptr; + xkb_keymap* m_pXKBKeymap = nullptr; + xkb_state* m_pXKBState = nullptr; + eOutputMode m_bSelectedOutputMode = OUTPUT_HEX; bool m_bFancyOutput = true; diff --git a/src/includes.hpp b/src/includes.hpp index 4dff159..9890344 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -40,6 +40,7 @@ extern "C" { #include #include #include +#include #include #include