From 94c5e361fbb229b0cd6853e2102a7d95f1f358b3 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Mon, 12 Oct 2026 22:12:02 +0300 Subject: better public interface and doxygen --- src/wayland/keyboard.c | 94 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 15 deletions(-) (limited to 'src/wayland/keyboard.c') diff --git a/src/wayland/keyboard.c b/src/wayland/keyboard.c index 11c7f3f..f1170c6 100644 --- a/src/wayland/keyboard.c +++ b/src/wayland/keyboard.c @@ -1,8 +1,14 @@ #include "internal.h" +#include "common/keyboard.h" #define XKB_EVDEV_OFFSET 8 #define KEYMAP_MAX_BYTES (8u * 1024 * 1024) +void keyboard_text_reset(struct seat *s) +{ + if (s->compose) xkb_compose_state_reset(s->compose); +} + void keyboard_repeat_stop(struct seat *s) { if (!s->repeat_held) return; @@ -28,11 +34,10 @@ void keyboard_repeat_sync(struct seat *s) timerfd_settime(s->repeat_fd, 0, &timer, NULL); } -static const char *const input_mod_names[8] = { +static const char *const input_mod_names[5] = { XKB_MOD_NAME_SHIFT, XKB_MOD_NAME_ALT, XKB_MOD_NAME_CTRL, XKB_MOD_NAME_LOGO, - "Hyper", "Meta", - XKB_MOD_NAME_CAPS, XKB_MOD_NAME_NUM + XKB_MOD_NAME_CAPS }; static bool mod_active(const struct seat *s, const char *name) @@ -48,7 +53,7 @@ static void resolve_input_mod_masks(struct seat *s) if (!probe) return; for (unsigned real = 0; real < 8; real++) { xkb_state_update_mask(probe, 1u << real, 0, 0, 0, 0, 0); - for (unsigned i = 0; i < 8; i++) { + for (unsigned i = 0; i < 5; i++) { if (xkb_state_mod_name_is_active(probe, input_mod_names[i], XKB_STATE_MODS_EFFECTIVE) > 0) s->input_mod_masks[i] |= 1u << real; @@ -64,6 +69,7 @@ static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, (void)keyboard; struct seat *s = data; keyboard_repeat_stop(s); + keyboard_text_reset(s); s->input_mods_ready = false; if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); @@ -116,6 +122,7 @@ static void keyboard_reset_keys(struct seat *s, struct wayland_surface *w) { (void)w; keyboard_repeat_stop(s); + keyboard_text_reset(s); } bool conn_keyboard_on(const struct wayland_display *c, const struct wayland_surface *w, @@ -194,7 +201,7 @@ static unsigned input_modifiers(struct seat *s) unsigned mods = 0; xkb_mod_mask_t reported = 0; - for (unsigned i = 0; i < 8; i++) { + for (unsigned i = 0; i < 5; i++) { xkb_mod_mask_t mask = s->input_mod_masks[i]; if (mask && (mask & ~reported) && mod_active(s, input_mod_names[i])) { mods |= 1u << i; @@ -215,23 +222,75 @@ static struct yasl_key_event xkb_key_event(struct seat *s, uint32_t key, enum yasl_key_action action) { uint32_t code = key + XKB_EVDEV_OFFSET; - xkb_keysym_t sym = xkb_state_key_get_one_sym(s->xkb_state, code); xkb_layout_index_t layout = xkb_state_key_get_layout(s->xkb_state, code); struct yasl_key_event k = { - .key = sym, - .keypad = key >= KEY_KP0 && key <= KEY_KPCOMMA, + .key = yasl_key_from_evdev(key), .action = action, .mods = input_modifiers(s), - .codepoint = key_codepoint_at_level(s, key, layout, 0), - .shifted = key_codepoint_at_level(s, key, layout, 1), - .base = key, - .text = xkb_state_key_get_utf32(s->xkb_state, code), + .codepoint = yasl_key_label(key_codepoint_at_level(s, key, layout, 0)), + .shifted = yasl_key_label(key_codepoint_at_level(s, key, layout, 1)), + .native_code = key, }; - if (!k.codepoint) k.codepoint = xkb_keysym_to_utf32(sym); return k; } +static void keyboard_text(struct seat *s, struct wayland_surface *w, uint32_t key) +{ + uint32_t code = key + XKB_EVDEV_OFFSET; + unsigned mods = input_modifiers(s); + if ((mods & (YASL_MOD_CTRL | YASL_MOD_SUPER)) || + ((mods & YASL_MOD_ALT) && + !xkb_state_mod_index_is_consumed(s->xkb_state, code, s->mod_alt))) { + keyboard_text_reset(s); + return; + } + if (!s->compose_attempted) { + s->compose_attempted = true; + const char *locale = getenv("LC_ALL"); + if (!locale || !*locale) locale = getenv("LC_CTYPE"); + if (!locale || !*locale) locale = getenv("LANG"); + if (!locale || !*locale) locale = "C.UTF-8"; + struct xkb_compose_table *table = xkb_compose_table_new_from_locale( + s->conn->xkb_ctx, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); + if (table) { + s->compose = xkb_compose_state_new(table, XKB_COMPOSE_STATE_NO_FLAGS); + xkb_compose_table_unref(table); + } + } + bool composed = false; + if (s->compose) { + xkb_compose_state_feed(s->compose, xkb_state_key_get_one_sym(s->xkb_state, code)); + switch (xkb_compose_state_get_status(s->compose)) { + case XKB_COMPOSE_COMPOSING: return; + case XKB_COMPOSE_CANCELLED: keyboard_text_reset(s); return; + case XKB_COMPOSE_COMPOSED: composed = true; break; + default: break; + } + } + int len = composed ? xkb_compose_state_get_utf8(s->compose, NULL, 0) : + xkb_state_key_get_utf8(s->xkb_state, code, NULL, 0); + if (len > 0) { + char local[128]; + char *text = (size_t)len < sizeof(local) ? local : malloc((size_t)len + 1); + if (text) { + if (composed) xkb_compose_state_get_utf8(s->compose, text, (size_t)len + 1); + else xkb_state_key_get_utf8(s->xkb_state, code, text, (size_t)len + 1); + /* Editing commands belong to key events, not text insertion. */ + if ((unsigned char)text[0] >= 0x20 && text[0] != 0x7f) { + struct yasl_input_event ev = {.kind = YASL_INPUT_TEXT, + .surface = &w->base, .text = {text, (size_t)len}}; + input_queue_push(&w->input, &ev); + } + if (text != local) free(text); + } else { + struct yasl_input_event ev = {.kind = YASL_INPUT_RESET, .surface = &w->base}; + input_queue_push(&w->input, &ev); + } + } + if (composed) keyboard_text_reset(s); +} + static bool keyboard_dispatch_key(struct seat *s, struct wayland_surface *w, uint32_t key, enum yasl_key_action action) { @@ -243,7 +302,11 @@ static bool keyboard_dispatch_key(struct seat *s, struct wayland_surface *w, uin .surface = &w->base, .key = k, }; - input_queue_push(&w->input, &ev); + if (!input_queue_push(&w->input, &ev)) { + keyboard_text_reset(s); + return false; + } + if (action != YASL_KEY_RELEASE) keyboard_text(s, w, key); return action != YASL_KEY_RELEASE; } @@ -351,7 +414,8 @@ int seat_modifiers(const struct seat *s) return (mod_index_active(s, s->mod_shift) * YASL_MOD_SHIFT) | (mod_index_active(s, s->mod_alt) * YASL_MOD_ALT) | (mod_index_active(s, s->mod_ctrl) * YASL_MOD_CTRL) | - (mod_index_active(s, s->mod_super) * YASL_MOD_SUPER); + (mod_index_active(s, s->mod_super) * YASL_MOD_SUPER) | + (mod_active(s, XKB_MOD_NAME_CAPS) * YASL_MOD_CAPS); } int wayland_display_modifiers(const struct wayland_display *c) -- cgit v1.2.3