diff --git a/src/backend/wayland/wl_input_fwd.c b/src/backend/wayland/wl_input_fwd.c index 6e9afee..6d9e768 100644 --- a/src/backend/wayland/wl_input_fwd.c +++ b/src/backend/wayland/wl_input_fwd.c @@ -12,9 +12,18 @@ #include #include "wl_types.h" +/* Wrapper struct for per-keyboard listeners */ +struct wl_keyboard_listener { + struct wlr_keyboard *keyboard; + struct wl_listener key; + struct wl_listener modifiers; + struct wl_listener destroy; +}; + /* Forward declarations */ void handle_keyboard_key(struct wl_listener *listener, void *data); void handle_keyboard_modifiers(struct wl_listener *listener, void *data); +static void handle_keyboard_destroy(struct wl_listener *listener, void *data); void handle_pointer_motion(struct wl_listener *listener, void *data); void handle_pointer_motion_absolute(struct wl_listener *listener, void *data); void handle_pointer_button(struct wl_listener *listener, void *data); @@ -61,12 +70,21 @@ real_pointer_update_global(struct wl_real_pointer_listener *pl) static void handle_keyboard_destroy(struct wl_listener *listener, void *data) { - (void)listener; (void)data; - INPUT_LISTENER_REMOVE(wl_state.real_keyboard_key_listener); - INPUT_LISTENER_REMOVE(wl_state.real_keyboard_modifiers_listener); - INPUT_LISTENER_REMOVE(wl_state.real_keyboard_destroy_listener); - wl_state.real_keyboard_dev = NULL; - wl_state.keyboard_dev = NULL; + (void)data; + struct wl_keyboard_listener *kl = + wl_container_of(listener, kl, destroy); + wl_list_remove(&kl->key.link); + wl_list_remove(&kl->modifiers.link); + wl_list_remove(&kl->destroy.link); + /* Clear global if this was the tracked keyboard */ + if (wl_state.keyboard_dev) { + struct wlr_keyboard *kb = wlr_keyboard_from_input_device(wl_state.keyboard_dev); + if (kb == kl->keyboard) { + wl_state.real_keyboard_dev = NULL; + wl_state.keyboard_dev = NULL; + } + } + free(kl); } static void @@ -160,19 +178,16 @@ handle_backend_new_input(struct wl_listener *listener, void *data) } if (wl_state.seat) wlr_seat_set_keyboard(wl_state.seat, kb); - /* Wire key events — use wlr_keyboard_group or attach to each device. - * wlroots seat aggregates all keyboards automatically when we call - * wlr_seat_set_keyboard, but we still need per-device listeners for - * the key events to reach our handler. Use dynamic allocation. */ - struct wl_listener *key_l = calloc(1, sizeof(*key_l)); - struct wl_listener *mod_l = calloc(1, sizeof(*mod_l)); - if (key_l) { - key_l->notify = handle_keyboard_key; - wl_signal_add(&kb->events.key, key_l); - } - if (mod_l) { - mod_l->notify = handle_keyboard_modifiers; - wl_signal_add(&kb->events.modifiers, mod_l); + /* Wire key events with wrapper structs that track the keyboard */ + struct wl_keyboard_listener *kl = calloc(1, sizeof(*kl)); + if (kl) { + kl->keyboard = kb; + kl->key.notify = handle_keyboard_key; + wl_signal_add(&kb->events.key, &kl->key); + kl->modifiers.notify = handle_keyboard_modifiers; + wl_signal_add(&kb->events.modifiers, &kl->modifiers); + kl->destroy.notify = handle_keyboard_destroy; + wl_signal_add(&dev->events.destroy, &kl->destroy); } wwarning("wl_backend: keyboard wired dev=%p xkb_state=%s", (void*)dev, kb->xkb_state ? "yes" : "no"); diff --git a/src/backend/wayland/wl_keyboard.c b/src/backend/wayland/wl_keyboard.c index bb16427..6115b2b 100644 --- a/src/backend/wayland/wl_keyboard.c +++ b/src/backend/wayland/wl_keyboard.c @@ -15,6 +15,14 @@ int wWaylandKeyPress(unsigned int keycode, unsigned int modifiers); #include "wl_types.h" #include +/* Wrapper struct for per-keyboard listeners (defined in wl_input_fwd.c) */ +struct wl_keyboard_listener { + struct wlr_keyboard *keyboard; + struct wl_listener key; + struct wl_listener modifiers; + struct wl_listener destroy; +}; + /* Forward declarations */ WMScreen *wl_get_wmscreen(void); void W_WL_EnqueueEvent(struct W_Screen *scr, const WMEvent *ev, struct W_View *target); @@ -24,19 +32,19 @@ void handle_keyboard_key(struct wl_listener *listener, void *data) { struct wlr_keyboard_key_event *event = data; - (void)listener; - - wwarning("handle_keyboard_key: keycode=%u state=%d", event->keycode, event->state); + struct wl_keyboard_listener *kl = + wl_container_of(listener, kl, key); + struct wlr_keyboard *kb = kl->keyboard; if (!wl_state.seat) return; - struct wlr_keyboard *kb = wl_state.seat->keyboard_state.keyboard; - if (!kb) { - wwarning("handle_keyboard_key: no seat keyboard for event keycode=%u dev=%p", event->keycode, (void*)wl_state.keyboard_dev); + if (!kb || !kb->xkb_state) { + wwarning("handle_keyboard_key: no xkb_state for keycode=%u", event->keycode); return; } + wlr_seat_set_keyboard(wl_state.seat, kb); wlr_seat_keyboard_notify_modifiers(wl_state.seat, &kb->modifiers); uint32_t keycode = event->keycode + 8; @@ -102,10 +110,12 @@ handle_keyboard_key(struct wl_listener *listener, void *data) void handle_keyboard_modifiers(struct wl_listener *listener, void *data) { - (void)listener; (void)data; - if (!wl_state.seat) return; - struct wlr_keyboard *kb = wl_state.seat->keyboard_state.keyboard; - if (!kb) return; + (void)data; + struct wl_keyboard_listener *kl = + wl_container_of(listener, kl, modifiers); + struct wlr_keyboard *kb = kl->keyboard; + if (!wl_state.seat || !kb) return; + wlr_seat_set_keyboard(wl_state.seat, kb); wlr_seat_keyboard_notify_modifiers(wl_state.seat, &kb->modifiers); /* Cache the real keyboard's depressed modifiers so pointer button * handlers can read them regardless of which keyboard the seat