From ca89ada4b108a36441832b7f11ed3f9b8886f887 Mon Sep 17 00:00:00 2001 From: Arek Date: Sat, 13 Jun 2026 10:22:08 +0200 Subject: [PATCH] feat: Initial usage of xkb. --- AGENTS.md | 6 ++++ CMakeLists.txt | 14 +++++++++ include/tkeyboard.h | 12 ++++++++ tkeyboard.c | 69 +++++++++++++++++++++++++++++++++++++++------ wlgol.c | 28 ++++++++++++++++++ 5 files changed, 121 insertions(+), 8 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index c301ce1..ba00389 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,6 +28,12 @@ Build programs: cmake --build ./build ``` +Run tests: + +```bash +ctest --test-dir build +``` + Run program: ```bash diff --git a/CMakeLists.txt b/CMakeLists.txt index 3124799..e0398aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,9 @@ project(wlgol DESCRIPTION "Wayland Game Of Life" LANGUAGES C) +find_package(PkgConfig REQUIRED) +pkg_check_modules(XKBCOMMON REQUIRED xkbcommon) + # Download xdg-shell.xml # file(DOWNLOAD "https://cgit.freedesktop.org/wayland/wayland-protocols/plain/stable/xdg-shell/xdg-shell.xml" "${CMAKE_CURRENT_BINARY_DIR}/xdg-shell.xml") @@ -37,11 +40,17 @@ add_executable(wlgol wlgol.c ${SOURCES} ${GENHEADERS}) target_include_directories(wlgol PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include + PUBLIC ${XKBCOMMON_INCLUDE_DIRS} ) target_link_libraries(wlgol wayland-client wayland-cursor + ${XKBCOMMON_LIBRARIES} +) + +target_compile_options(wlgol PRIVATE + ${XKBCOMMON_CFLAGS_OTHER} ) @@ -52,10 +61,15 @@ add_executable(test_hashtable tests/test_hashtable.c target_link_libraries(test_hashtable wayland-client wayland-cursor + ${XKBCOMMON_LIBRARIES} ) target_include_directories(test_hashtable PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include + PUBLIC ${XKBCOMMON_INCLUDE_DIRS} +) +target_compile_options(test_hashtable PRIVATE + ${XKBCOMMON_CFLAGS_OTHER} ) enable_testing() diff --git a/include/tkeyboard.h b/include/tkeyboard.h index 65fd506..8f3870b 100644 --- a/include/tkeyboard.h +++ b/include/tkeyboard.h @@ -1,12 +1,24 @@ #ifndef TKEYBOARD_H #define TKEYBOARD_H +#include #include +#include + +typedef void (*keyboard_key_handler_t)(uint32_t key, uint32_t state, xkb_keysym_t sym, void *user_data); struct keyboard_data { struct wl_keyboard *keyboard; + struct xkb_context *xkb_context; + struct xkb_keymap *xkb_keymap; + struct xkb_state *xkb_state; + + keyboard_key_handler_t handler; + void *user_data; }; extern const struct wl_keyboard_listener keyboard_listener; +void keyboard_set_handler(struct keyboard_data *kbd, keyboard_key_handler_t handler, void *user_data); + #endif diff --git a/tkeyboard.c b/tkeyboard.c index 35f86ff..41397e7 100644 --- a/tkeyboard.c +++ b/tkeyboard.c @@ -1,33 +1,82 @@ #include +#include +#include +#include +#include + +#include +#include #include static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) { - // not implemented + struct keyboard_data *kbd = data; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) + { + close(fd); + return; + } + + char *map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (map_str == MAP_FAILED) + { + close(fd); + return; + } + + kbd->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + kbd->xkb_keymap = xkb_keymap_new_from_string( + kbd->xkb_context, map_str, + XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS); + kbd->xkb_state = xkb_state_new(kbd->xkb_keymap); + + munmap(map_str, size); + close(fd); } static void keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { printf("keyboard_enter\n"); - // not implemented } static void keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) { printf("keyboard_leave\n"); - // not implemented } static void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { - printf("keyboard_key: %d %d\n", key, state); - // not implemented + struct keyboard_data *kbd = data; + xkb_keysym_t sym = XKB_KEY_NoSymbol; + + if (kbd->xkb_state != NULL) + { + // Wayland keycodes are Linux evdev scancodes; + // xkbcommon expects keycodes offset by 8. + sym = xkb_state_key_get_one_sym(kbd->xkb_state, key + 8); + } + + printf("keyboard_key: scancode=%d state=%d keysym=%u\n", key, state, sym); + + if (kbd->handler != NULL) + { + kbd->handler(key, state, sym, kbd->user_data); + } } static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { - // not implemented + struct keyboard_data *kbd = data; + + if (kbd->xkb_state != NULL) + { + xkb_state_update_mask(kbd->xkb_state, + mods_depressed, mods_latched, mods_locked, + 0, 0, group); + } } static void keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay) @@ -41,6 +90,10 @@ const struct wl_keyboard_listener keyboard_listener = { .leave = keyboard_leave, .key = keyboard_key, .modifiers = keyboard_modifiers, - .repeat_info = keyboard_repeat_info -}; + .repeat_info = keyboard_repeat_info}; +void keyboard_set_handler(struct keyboard_data *kbd, keyboard_key_handler_t handler, void *user_data) +{ + kbd->handler = handler; + kbd->user_data = user_data; +} diff --git a/wlgol.c b/wlgol.c index f034d2a..9df8376 100644 --- a/wlgol.c +++ b/wlgol.c @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include @@ -142,6 +144,18 @@ const struct wl_buffer_listener wl_buffer_listener = { void redraw(); // forward declaration +static void handle_key(uint32_t key, uint32_t state, xkb_keysym_t sym, void *user_data) +{ + (void)key; + (void)user_data; + + if (state == WL_KEYBOARD_KEY_STATE_PRESSED && sym == XKB_KEY_Escape) + { + printf("Escape pressed, exiting.\n"); + running = 0; + } +} + void wl_callack_done(void *data, struct wl_callback *callback, uint32_t time) { if (canvas.frame) @@ -187,6 +201,7 @@ int main(void) wl_surface_commit(canvas.surface); keyboard_data.keyboard = wl_seat_get_keyboard(wl_seat); + keyboard_set_handler(&keyboard_data, handle_key, NULL); wl_keyboard_add_listener(keyboard_data.keyboard, &keyboard_listener, &keyboard_data); pointer_init_cursor(&pointer_data, compositor, shm); @@ -230,6 +245,19 @@ int main(void) xdg_surface_destroy(xdg_surface); wl_surface_destroy(canvas.surface); wl_shm_pool_destroy(pool); + wl_keyboard_destroy(keyboard_data.keyboard); + if (keyboard_data.xkb_state != NULL) + { + xkb_state_unref(keyboard_data.xkb_state); + } + if (keyboard_data.xkb_keymap != NULL) + { + xkb_keymap_unref(keyboard_data.xkb_keymap); + } + if (keyboard_data.xkb_context != NULL) + { + xkb_context_unref(keyboard_data.xkb_context); + } wl_registry_destroy(registry); wl_display_disconnect(display); }