// Weston-side keyboard events reach nested Niri's native grabs. Niri's wlr // virtual keyboard forwards to clients and cannot confirm/cancel those grabs. #include #include #include #include #include #include #include struct controller { struct weston_compositor *compositor; struct wl_event_source *source; struct wl_listener destroy; int fd; }; static int input(int fd, uint32_t mask, void *data) { (void)mask; struct controller *ctl = data; uint32_t command[3]; // expected nested client PID, evdev key, pressed assert(read(fd, command, sizeof(command)) == sizeof(command)); assert(command[0] > 1 && command[2] <= 1); assert(command[1] == 1 || command[1] == 28 || command[1] == 29 || command[1] == 46); struct weston_seat *seat; struct weston_keyboard *keyboard = NULL; wl_list_for_each(seat, &ctl->compositor->seat_list, link) { struct weston_keyboard *candidate = weston_seat_get_keyboard(seat); if (!candidate || !candidate->focus || !candidate->focus->resource) continue; pid_t pid; wl_client_get_credentials(wl_resource_get_client(candidate->focus->resource), &pid, NULL, NULL); if (pid == (pid_t)command[0]) { assert(!keyboard); keyboard = candidate; } } assert(keyboard); // Never redirect input to an unrelated surface. struct timespec now; weston_compositor_get_time(&now); weston_keyboard_send_key(keyboard, &now, command[1], command[2]); xkb_state_update_key(keyboard->xkb_state.state, command[1] + 8, command[2] ? XKB_KEY_DOWN : XKB_KEY_UP); weston_keyboard_send_modifiers(keyboard, wl_display_next_serial(ctl->compositor->wl_display), xkb_state_serialize_mods(keyboard->xkb_state.state, XKB_STATE_MODS_DEPRESSED), xkb_state_serialize_mods(keyboard->xkb_state.state, XKB_STATE_MODS_LATCHED), xkb_state_serialize_mods(keyboard->xkb_state.state, XKB_STATE_MODS_LOCKED), xkb_state_serialize_layout(keyboard->xkb_state.state, XKB_STATE_LAYOUT_EFFECTIVE)); return 0; } static void destroy(struct wl_listener *listener, void *data) { (void)data; struct controller *ctl = wl_container_of(listener, ctl, destroy); wl_event_source_remove(ctl->source); wl_list_remove(&ctl->destroy.link); close(ctl->fd); free(ctl); } WL_EXPORT int wet_module_init(struct weston_compositor *compositor, int *argc, char *argv[]) { (void)argc; (void)argv; assert(getenv("NUGULAND_UI_SANDBOX") && !strcmp(getenv("HOME"), "/home/test")); struct controller *ctl = calloc(1, sizeof(*ctl)); assert(ctl); ctl->compositor = compositor; ctl->fd = open("/run/user/1000/niri-integration-keyboard.fifo", O_RDWR | O_NONBLOCK); assert(ctl->fd >= 0); ctl->source = wl_event_loop_add_fd(wl_display_get_event_loop(compositor->wl_display), ctl->fd, WL_EVENT_READABLE, input, ctl); assert(ctl->source); weston_compositor_add_destroy_listener_once(compositor, &ctl->destroy, destroy); return 0; }