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, &registry_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;