From 72d166c481d9bec66506c3064efb9ca650c05f87 Mon Sep 17 00:00:00 2001 From: biosfood Date: Sun, 12 Oct 2025 20:24:24 +0200 Subject: [PATCH] individual keyboard rules --- config.def.h | 18 ++++-- dwl.c | 160 ++++++++++++++++++++++++++------------------------- 2 files changed, 93 insertions(+), 85 deletions(-) diff --git a/config.def.h b/config.def.h index 95c2afa..fc33b55 100644 --- a/config.def.h +++ b/config.def.h @@ -52,12 +52,18 @@ static const MonitorRule monrules[] = { }; /* keyboard */ -static const struct xkb_rule_names xkb_rules = { - /* can specify fields: rules, model, layout, variant, options */ - /* example: - .options = "ctrl:nocaps", - */ - .options = NULL, +static const KeyboardRule keyboard_rules[] = { + { + "AT Translated Set 2 keyboard", + { .layout = "de", .options = "caps:super" } + }, + { + "", // fallback + { + .layout = "en", + /* can specify fields: rules, model, layout, variant, options */ + } + }, }; static const int repeat_rate = 25; diff --git a/dwl.c b/dwl.c index 12f441e..1871299 100644 --- a/dwl.c +++ b/dwl.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -149,7 +150,8 @@ typedef struct { } Key; typedef struct { - struct wlr_keyboard_group *wlr_group; + struct wl_list link; + struct wlr_keyboard *wlr_keyboard; int nsyms; const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ @@ -159,7 +161,12 @@ typedef struct { struct wl_listener modifiers; struct wl_listener key; struct wl_listener destroy; -} KeyboardGroup; +} Keyboard; + +typedef struct { + const char *name; + struct xkb_rule_names xkb_rules; +} KeyboardRule; typedef struct { /* Must keep this field first */ @@ -260,7 +267,6 @@ static void commitpopup(struct wl_listener *listener, void *data); static void createdecoration(struct wl_listener *listener, void *data); static void createidleinhibitor(struct wl_listener *listener, void *data); static void createkeyboard(struct wlr_keyboard *keyboard); -static KeyboardGroup *createkeyboardgroup(void); static void createlayersurface(struct wl_listener *listener, void *data); static void createlocksurface(struct wl_listener *listener, void *data); static void createmon(struct wl_listener *listener, void *data); @@ -280,7 +286,7 @@ static void destroylocksurface(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static void destroypointerconstraint(struct wl_listener *listener, void *data); static void destroysessionlock(struct wl_listener *listener, void *data); -static void destroykeyboardgroup(struct wl_listener *listener, void *data); +static void destroykeyboard(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); @@ -396,7 +402,7 @@ static struct wlr_scene_rect *locked_bg; static struct wlr_session_lock_v1 *cur_lock; static struct wlr_seat *seat; -static KeyboardGroup *kb_group; +static struct wl_list keyboards; static unsigned int cursor_mode; static Client *grabc; static int grabcx, grabcy; /* client-relative */ @@ -696,6 +702,19 @@ checkidleinhibitor(struct wlr_surface *exclude) wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); } +void +cleanupkeyboard(struct wl_listener *listener, void *data) +{ + Keyboard *kb = wl_container_of(listener, kb, destroy); + + wl_event_source_remove(kb->key_repeat_source); + wl_list_remove(&kb->link); + wl_list_remove(&kb->modifiers.link); + wl_list_remove(&kb->key.link); + wl_list_remove(&kb->destroy.link); + free(kb); +} + void cleanup(void) { @@ -711,8 +730,6 @@ cleanup(void) } wlr_xcursor_manager_destroy(cursor_mgr); - destroykeyboardgroup(&kb_group->destroy, NULL); - /* If it's not destroyed manually, it will cause a use-after-free of wlr_seat. * Destroy it until it's fixed on the wlroots side */ wlr_backend_destroy(backend); @@ -940,48 +957,45 @@ createidleinhibitor(struct wl_listener *listener, void *data) void createkeyboard(struct wlr_keyboard *keyboard) { - /* Set the keymap to match the group keymap */ - wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap); + const struct xkb_rule_names *rules; + size_t i; + for (i = 0; i < LENGTH(keyboard_rules); i++) { + if (strcmp(keyboard->base.name, keyboard_rules[i].name) == 0 || + i == LENGTH(keyboard_rules) - 1) { + rules = &keyboard_rules[i].xkb_rules; + } + } - /* Add the new keyboard to the group */ - wlr_keyboard_group_add_keyboard(kb_group->wlr_group, keyboard); -} -KeyboardGroup * -createkeyboardgroup(void) -{ - KeyboardGroup *group = ecalloc(1, sizeof(*group)); struct xkb_context *context; struct xkb_keymap *keymap; + Keyboard *kb = keyboard->data = ecalloc(1, sizeof(*kb)); + kb->wlr_keyboard = keyboard; - group->wlr_group = wlr_keyboard_group_create(); - group->wlr_group->data = group; - - /* Prepare an XKB keymap and assign it to the keyboard group. */ + /* Prepare an XKB keymap and assign it to the keyboard. */ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, - XKB_KEYMAP_COMPILE_NO_FLAGS))) - die("failed to compile keymap"); + keymap = xkb_keymap_new_from_names(context, rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) + die("createkeyboard: failed to compile keymap"); - wlr_keyboard_set_keymap(&group->wlr_group->keyboard, keymap); + wlr_keyboard_set_keymap(keyboard, keymap); xkb_keymap_unref(keymap); xkb_context_unref(context); + wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay); - wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, repeat_rate, repeat_delay); + /* Here we set up listeners for keyboard events. */ + LISTEN(&keyboard->events.modifiers, &kb->modifiers, keypressmod); + LISTEN(&keyboard->events.key, &kb->key, keypress); + LISTEN(&keyboard->base.events.destroy, &kb->destroy, cleanupkeyboard); - /* Set up listeners for keyboard events */ - LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress); - LISTEN(&group->wlr_group->keyboard.events.modifiers, &group->modifiers, keypressmod); + wlr_seat_set_keyboard(seat, keyboard); - group->key_repeat_source = wl_event_loop_add_timer(event_loop, keyrepeat, group); + kb->key_repeat_source = wl_event_loop_add_timer( + wl_display_get_event_loop(dpy), keyrepeat, kb); - /* A seat can only have one keyboard, but this is a limitation of the - * Wayland protocol - not wlroots. We assign all connected keyboards to the - * same wlr_keyboard_group, which provides a single wlr_keyboard interface for - * all of them. Set this combined wlr_keyboard as the seat keyboard. - */ - wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); - return group; + /* And add the keyboard to our list of keyboards */ + wl_list_insert(&keyboards, &kb->link); } void @@ -1372,15 +1386,14 @@ destroysessionlock(struct wl_listener *listener, void *data) } void -destroykeyboardgroup(struct wl_listener *listener, void *data) +destroykeyboard(struct wl_listener *listener, void *data) { - KeyboardGroup *group = wl_container_of(listener, group, destroy); - wl_event_source_remove(group->key_repeat_source); - wl_list_remove(&group->key.link); - wl_list_remove(&group->modifiers.link); - wl_list_remove(&group->destroy.link); - wlr_keyboard_group_destroy(group->wlr_group); - free(group); + Keyboard *kb = wl_container_of(listener, kb, destroy); + wl_event_source_remove(kb->key_repeat_source); + wl_list_remove(&kb->key.link); + wl_list_remove(&kb->modifiers.link); + wl_list_remove(&kb->destroy.link); + free(kb); } Monitor * @@ -1600,8 +1613,7 @@ inputdevice(struct wl_listener *listener, void *data) * there are no pointer devices, so we always include that capability. */ /* TODO do we actually require a cursor? */ caps = WL_SEAT_CAPABILITY_POINTER; - if (!wl_list_empty(&kb_group->wlr_group->devices)) - caps |= WL_SEAT_CAPABILITY_KEYBOARD; + caps |= WL_SEAT_CAPABILITY_KEYBOARD; wlr_seat_set_capabilities(seat, caps); } @@ -1629,7 +1641,7 @@ keypress(struct wl_listener *listener, void *data) { int i; /* This event is raised when a key is pressed or released. */ - KeyboardGroup *group = wl_container_of(listener, group, key); + Keyboard *kb = wl_container_of(listener, kb, key); struct wlr_keyboard_key_event *event = data; /* Translate libinput keycode -> xkbcommon */ @@ -1637,10 +1649,10 @@ keypress(struct wl_listener *listener, void *data) /* Get a list of keysyms based on the keymap for this keyboard */ const xkb_keysym_t *syms; int nsyms = xkb_state_key_get_syms( - group->wlr_group->keyboard.xkb_state, keycode, &syms); + kb->wlr_keyboard->xkb_state, keycode, &syms); int handled = 0; - uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard); + uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard); wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); @@ -1650,22 +1662,21 @@ keypress(struct wl_listener *listener, void *data) for (i = 0; i < nsyms; i++) handled = keybinding(mods, syms[i]) || handled; } - - if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) { - group->mods = mods; - group->keysyms = syms; - group->nsyms = nsyms; - wl_event_source_timer_update(group->key_repeat_source, - group->wlr_group->keyboard.repeat_info.delay); + if (handled && kb->wlr_keyboard->repeat_info.delay > 0) { + kb->mods = mods; + kb->keysyms = syms; + kb->nsyms = nsyms; + wl_event_source_timer_update(kb->key_repeat_source, + kb->wlr_keyboard->repeat_info.delay); } else { - group->nsyms = 0; - wl_event_source_timer_update(group->key_repeat_source, 0); + kb->nsyms = 0; + wl_event_source_timer_update(kb->key_repeat_source, 0); } if (handled) return; - wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + wlr_seat_set_keyboard(seat, kb->wlr_keyboard); /* Pass unhandled keycodes along to the client. */ wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, event->state); @@ -1676,27 +1687,27 @@ keypressmod(struct wl_listener *listener, void *data) { /* This event is raised when a modifier key, such as shift or alt, is * pressed. We simply communicate this to the client. */ - KeyboardGroup *group = wl_container_of(listener, group, modifiers); + Keyboard *kb = wl_container_of(listener, kb, modifiers); - wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); + wlr_seat_set_keyboard(seat, kb->wlr_keyboard); /* Send modifiers to the client. */ wlr_seat_keyboard_notify_modifiers(seat, - &group->wlr_group->keyboard.modifiers); + &kb->wlr_keyboard->modifiers); } int keyrepeat(void *data) { - KeyboardGroup *group = data; + Keyboard *kb = data; int i; - if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0) + if (!kb->nsyms || kb->wlr_keyboard->repeat_info.rate <= 0) return 0; - wl_event_source_timer_update(group->key_repeat_source, - 1000 / group->wlr_group->keyboard.repeat_info.rate); + wl_event_source_timer_update(kb->key_repeat_source, + 1000 / kb->wlr_keyboard->repeat_info.rate); - for (i = 0; i < group->nsyms; i++) - keybinding(group->mods, group->keysyms[i]); + for (i = 0; i < kb->nsyms; i++) + keybinding(kb->mods, kb->keysyms[i]); return 0; } @@ -2448,6 +2459,7 @@ setup(void) struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; sigemptyset(&sa.sa_mask); + wl_list_init(&keyboards); for (i = 0; i < (int)LENGTH(sig); i++) sigaction(sig[i], &sa, NULL); @@ -2638,9 +2650,6 @@ setup(void) wl_signal_add(&seat->events.request_start_drag, &request_start_drag); wl_signal_add(&seat->events.start_drag, &start_drag); - kb_group = createkeyboardgroup(); - wl_list_init(&kb_group->destroy.link); - output_mgr = wlr_output_manager_v1_create(dpy); wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); wl_signal_add(&output_mgr->events.test, &output_mgr_test); @@ -2982,14 +2991,7 @@ void virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *kb = data; - /* virtual keyboards shouldn't share keyboard group */ - KeyboardGroup *group = createkeyboardgroup(); - /* Set the keymap to match the group keymap */ - wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap); - LISTEN(&kb->keyboard.base.events.destroy, &group->destroy, destroykeyboardgroup); - - /* Add the new keyboard to the group */ - wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard); + createkeyboard(&kb->keyboard); } void -- 2.51.2