summaryrefslogtreecommitdiff
path: root/src/wayland/keyboard.c
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-12 22:12:02 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-12 22:12:02 +0300
commit94c5e361fbb229b0cd6853e2102a7d95f1f358b3 (patch)
tree3c0f11af9dcb84dac8067a31a6979acd6dd56fbf /src/wayland/keyboard.c
parent08dc9047098d6d96791024ac7d8f5837633673ef (diff)
better public interface and doxygen
Diffstat (limited to 'src/wayland/keyboard.c')
-rw-r--r--src/wayland/keyboard.c94
1 files changed, 79 insertions, 15 deletions
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)