commit 9f8acc0
uint
·
2026-08-04 00:20:54 +0000 UTC
parent 9fa2383
Wayland: add xkbcommon key mapping
2 files changed,
+162,
-11
+11,
-0
1@@ -20,6 +20,10 @@ struct xdg_wm_base;
2 struct xdg_surface;
3 struct xdg_toplevel;
4
5+struct xkb_context;
6+struct xkb_keymap;
7+struct xkb_state;
8+
9 typedef struct {
10 int8_t pending;
11 int32_t type;
12@@ -33,6 +37,8 @@ typedef struct {
13 uint8_t mouse_pressed;
14
15 uint32_t key_code;
16+ uint32_t key_sym;
17+ char key_text;
18 uint8_t key_pressed;
19 } MausEventPending;
20
21@@ -50,6 +56,11 @@ typedef struct {
22 struct wl_pointer* pointer;
23 struct wl_keyboard* keyboard;
24
25+ struct xkb_context* xkb_context;
26+ struct xkb_keymap* xkb_keymap;
27+ struct xkb_state* xkb_state;
28+
29+
30 MausEventPending pending;
31
32 struct xdg_wm_base* wm_base;
+151,
-11
1@@ -7,6 +7,7 @@
2
3 #include <wayland-client.h>
4 #include <xdg-shell-client-protocol.h>
5+#include <xkbcommon/xkbcommon.h>
6
7 #include "maus.h"
8 #include "maus_wayland.h"
9@@ -59,6 +60,8 @@ static void keyboard_repeat_info(void* data, struct wl_keyboard* keyboard,
10 static void registry_global(void* data, struct wl_registry* registry,
11 uint32_t name, const char* interface,
12 uint32_t version);
13+static MausKey keysym_to_mauskey(xkb_keysym_t sym);
14+static MausMouseButton wl_button_to_maus(uint32_t button);
15 static struct wl_registry_listener registry_listener = { registry_global, registry_global_remove };
16 static struct xdg_surface_listener xdg_surface_listener = { xdg_surface_configure };
17 static struct xdg_toplevel_listener xdg_toplevel_listener = {
18@@ -252,7 +255,44 @@ static void pointer_axis_relative_direction(void* data, struct wl_pointer* point
19 uint32_t axis, uint32_t direction) { }
20
21 static void keyboard_keymap(void* data, struct wl_keyboard* keyboard, uint32_t format,
22- int32_t fd, uint32_t size) { }
23+ int32_t fd, uint32_t size)
24+{
25+ Maus* mw = data;
26+ MausBackend* be = &mw->backend;
27+ char* map;
28+
29+ (void)keyboard;
30+
31+ if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
32+ close(fd);
33+ return;
34+ }
35+
36+ map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
37+ if (map == MAP_FAILED) {
38+ close(fd);
39+ return;
40+ }
41+
42+ if (be->xkb_state)
43+ xkb_state_unref(be->xkb_state);
44+ if (be->xkb_keymap)
45+ xkb_keymap_unref(be->xkb_keymap);
46+
47+ be->xkb_keymap = xkb_keymap_new_from_string(
48+ be->xkb_context, map,
49+ XKB_KEYMAP_FORMAT_TEXT_V1,
50+ XKB_KEYMAP_COMPILE_NO_FLAGS
51+ );
52+
53+ munmap(map, size);
54+ close(fd);
55+
56+ if (!be->xkb_keymap)
57+ return;
58+
59+ be->xkb_state = xkb_state_new(be->xkb_keymap);
60+}
61
62 static void keyboard_enter(void* data, struct wl_keyboard* keyboard, uint32_t serial,
63 struct wl_surface* surface, struct wl_array* keys) { }
64@@ -264,25 +304,60 @@ static void keyboard_key(void* data, struct wl_keyboard* keyboard, uint32_t seri
65 uint32_t time, uint32_t key, uint32_t state)
66 {
67 Maus* mw = data;
68+ MausBackend* be = &mw->backend;
69 uint32_t code;
70+ xkb_keysym_t sym;
71+ char text[8];
72+ int len;
73
74 (void)keyboard;
75 (void)serial;
76 (void)time;
77
78 code = key + 8;
79- mw->backend.pending.pending = 1;
80- mw->backend.pending.type = MAUS_EV_KEY;
81- mw->backend.pending.key_code = code;
82- mw->backend.pending.key_pressed = state == WL_KEYBOARD_KEY_STATE_PRESSED;
83+ sym = XKB_KEY_NoSymbol;
84+ text[0] = 0;
85+
86+ if (be->xkb_state) {
87+ sym = xkb_state_key_get_one_sym(be->xkb_state, code);
88+ if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
89+ len = xkb_state_key_get_utf8(be->xkb_state, code, text, sizeof(text));
90+ if (len <= 0)
91+ text[0] = 0;
92+ }
93+ }
94+
95+ be->pending.pending = 1;
96+ be->pending.type = MAUS_EV_KEY;
97+ be->pending.key_code = code;
98+ be->pending.key_sym = keysym_to_mauskey(sym);
99+ be->pending.key_text = text[0];
100+ be->pending.key_pressed = state == WL_KEYBOARD_KEY_STATE_PRESSED;
101
102 if (code < MAUS_KEYCODE_LAST)
103- mw->key_codes[code] = mw->backend.pending.key_pressed;
104+ mw->key_codes[code] = be->pending.key_pressed;
105+ if (be->pending.key_sym != MAUS_KEY_NONE)
106+ mw->key_syms[be->pending.key_sym] = be->pending.key_pressed;
107 }
108
109 static void keyboard_modifiers(void* data, struct wl_keyboard* keyboard, uint32_t serial,
110 uint32_t mods_depressed, uint32_t mods_latched,
111- uint32_t mods_locked, uint32_t group) { }
112+ uint32_t mods_locked, uint32_t group)
113+{
114+ Maus* mw = data;
115+
116+ (void)keyboard;
117+ (void)serial;
118+
119+ if (!mw->backend.xkb_state)
120+ return;
121+
122+ xkb_state_update_mask(
123+ mw->backend.xkb_state, mods_depressed,
124+ mods_latched, mods_locked,
125+ 0, 0, group
126+ );
127+}
128
129 static void keyboard_repeat_info(void* data, struct wl_keyboard* keyboard,
130 int32_t rate, int32_t delay) { }
131@@ -291,7 +366,6 @@ static void keyboard_repeat_info(void* data, struct wl_keyboard* keyboard,
132 static int8_t fb_create(Maus* mw);
133 static int8_t fb_create_shm(size_t size);
134 static int8_t handle_event(Maus* mw, MausEvent* ev);
135-static MausMouseButton wl_button_to_maus(uint32_t button);
136
137 static int8_t fb_create(Maus* mw)
138 {
139@@ -389,8 +463,8 @@ static int8_t handle_event(Maus* mw, MausEvent* ev)
140 case MAUS_EV_KEY:
141 ev->key.code = be->pending.key_code;
142 ev->key.pressed = be->pending.key_pressed;
143- ev->key.key = MAUS_KEY_NONE;
144- ev->key.text = 0;
145+ ev->key.key = be->pending.key_sym;
146+ ev->key.text = be->pending.key_text;
147 return 1;
148
149 default:
150@@ -408,6 +482,56 @@ static MausMouseButton wl_button_to_maus(uint32_t button)
151 }
152 }
153
154+static MausKey keysym_to_mauskey(xkb_keysym_t sym)
155+{
156+ if (sym >= 0x20 && sym <= 0x7E)
157+ return (MausKey)sym;
158+
159+ if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F12)
160+ return MAUS_KEY_F1 + (sym - XKB_KEY_F1);
161+ if (sym >= XKB_KEY_KP_0 && sym <= XKB_KEY_KP_9)
162+ return MAUS_KEY_KP_0 + (sym - XKB_KEY_KP_0);
163+
164+ switch (sym) {
165+ case XKB_KEY_BackSpace: return MAUS_KEY_BACKSPACE;
166+ case XKB_KEY_Tab: return MAUS_KEY_TAB;
167+ case XKB_KEY_Return: return MAUS_KEY_ENTER;
168+ case XKB_KEY_Escape: return MAUS_KEY_ESCAPE;
169+ case XKB_KEY_Delete: return MAUS_KEY_DELETE;
170+ case XKB_KEY_Left: return MAUS_KEY_LEFT;
171+ case XKB_KEY_Right: return MAUS_KEY_RIGHT;
172+ case XKB_KEY_Up: return MAUS_KEY_UP;
173+ case XKB_KEY_Down: return MAUS_KEY_DOWN;
174+ case XKB_KEY_Home: return MAUS_KEY_HOME;
175+ case XKB_KEY_End: return MAUS_KEY_END;
176+ case XKB_KEY_Page_Up: return MAUS_KEY_PAGE_UP;
177+ case XKB_KEY_Page_Down: return MAUS_KEY_PAGE_DOWN;
178+ case XKB_KEY_Insert: return MAUS_KEY_INSERT;
179+ case XKB_KEY_Shift_L: return MAUS_KEY_SHIFT_L;
180+ case XKB_KEY_Shift_R: return MAUS_KEY_SHIFT_R;
181+ case XKB_KEY_Control_L: return MAUS_KEY_CONTROL_L;
182+ case XKB_KEY_Control_R: return MAUS_KEY_CONTROL_R;
183+ case XKB_KEY_Alt_L: return MAUS_KEY_ALT_L;
184+ case XKB_KEY_Alt_R: return MAUS_KEY_ALT_R;
185+ case XKB_KEY_Super_L: return MAUS_KEY_SUPER_L;
186+ case XKB_KEY_Super_R: return MAUS_KEY_SUPER_R;
187+ case XKB_KEY_Caps_Lock: return MAUS_KEY_CAPS_LOCK;
188+ case XKB_KEY_Num_Lock: return MAUS_KEY_NUM_LOCK;
189+ case XKB_KEY_Scroll_Lock: return MAUS_KEY_SCROLL_LOCK;
190+ case XKB_KEY_Print: return MAUS_KEY_PRINT_SCREEN;
191+ case XKB_KEY_Pause: return MAUS_KEY_PAUSE;
192+ case XKB_KEY_Menu: return MAUS_KEY_MENU;
193+ case XKB_KEY_KP_Decimal: return MAUS_KEY_KP_DECIMAL;
194+ case XKB_KEY_KP_Divide: return MAUS_KEY_KP_DIVIDE;
195+ case XKB_KEY_KP_Multiply: return MAUS_KEY_KP_MULTIPLY;
196+ case XKB_KEY_KP_Subtract: return MAUS_KEY_KP_SUBTRACT;
197+ case XKB_KEY_KP_Add: return MAUS_KEY_KP_ADD;
198+ case XKB_KEY_KP_Enter: return MAUS_KEY_KP_ENTER;
199+ case XKB_KEY_KP_Equal: return MAUS_KEY_KP_EQUAL;
200+ default: return MAUS_KEY_NONE;
201+ }
202+}
203+
204 void maus_clear(Maus* mw, MausColor col)
205 {
206 uint32_t up = MAUS_UNPACK_COL(col);
207@@ -462,6 +586,15 @@ void maus_close(Maus* mw)
208 if (be->seat)
209 wl_seat_destroy(be->seat);
210
211+ if (be->xkb_state)
212+ xkb_state_unref(be->xkb_state);
213+
214+ if (be->xkb_keymap)
215+ xkb_keymap_unref(be->xkb_keymap);
216+
217+ if (be->xkb_context)
218+ xkb_context_unref(be->xkb_context);
219+
220 if (be->wm_base)
221 xdg_wm_base_destroy(be->wm_base);
222
223@@ -562,6 +695,13 @@ Maus* maus_init(const char* title, int x, int y, int width, int height)
224 wl_registry_add_listener(be->registry, ®istry_listener, mw);
225 wl_display_roundtrip(be->display);
226
227+ be->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
228+ if (!be->xkb_context) {
229+ maus_close(mw);
230+ free(mw);
231+ return NULL;
232+ }
233+
234 if (!be->compositor || !be->shm || !be->wm_base) {
235 maus_close(mw);
236 free(mw);
237@@ -610,7 +750,7 @@ int8_t maus_event_poll(Maus* mw, MausEvent* ev)
238 pfd.fd = wl_display_get_fd(be->display);
239 pfd.events = POLLIN;
240 pfd.revents = 0;
241-
242+
243 if (poll(&pfd, 1, 0) > 0 && (pfd.revents & POLLIN)) {
244 if (wl_display_read_events(be->display) == -1) {
245 ev->type = MAUS_EV_CLOSE;