为库添加Wayland支持:Seat监听器未触发,无法检测键盘能力
我正在为一个库添加Wayland支持,目前正在处理输入事件模块。尝试编译某示例代码时出现段错误,因此自行编写了如下版本:
#include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <wayland-client.h> #include <xkbcommon/xkbcommon.h> #include <wayland-egl.h> #include <EGL/egl.h> #include <GL/gl.h> struct wl_display *display = NULL; struct wl_seat *seat = NULL; EGLDisplay egl_display; struct xkb_context *xkb_context = NULL; int running = 1; // seat void seat_capabilities(void *data, struct wl_seat *seat, uint32_t capabilities) { printf("seat_capabilities(%u)\n", capabilities); if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { printf("kb capab\n"); } } struct wl_seat_listener seat_listener = {&seat_capabilities}; // reg void registry_add_object (void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { printf("registry_add_object(%s)\n", interface); if (!strcmp(interface, "wl_seat")) { printf(" binding seat\n"); seat = wl_registry_bind(registry, name, &wl_seat_interface, 1); wl_seat_add_listener(seat, &seat_listener, NULL); } } void registry_remove_object (void *data, struct wl_registry *registry, uint32_t name) { } struct wl_registry_listener registry_listener = {®istry_add_object, ®istry_remove_object}; int main(int argc, char **argv) { display = wl_display_connect(NULL); assert(display); printf("connected to display\n"); struct wl_registry *registry = wl_display_get_registry(display); assert(registry); wl_registry_add_listener(registry, ®istry_listener, NULL); // Complete init phase wl_display_roundtrip(display); egl_display = eglGetDisplay(display); eglInitialize(egl_display, NULL, NULL); xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); //sleep(2); eglTerminate(egl_display); wl_display_disconnect(display); printf("disconnected from display\n"); return 0; }
但运行后看不到任何键盘能力相关输出,Seat监听器始终未被调用,请问有什么解决思路?
添加事件循环处理后续事件:当前代码仅执行了一次
wl_display_roundtrip,仅能处理初始化阶段的registry对象添加事件,而seat的capabilities事件可能在后续事件流中才会发送。替换注释的sleep(2)为事件循环,确保客户端持续接收并处理事件:while (wl_display_dispatch(display) != -1 && running) { // 持续处理Wayland事件 }使用正确的seat接口版本绑定:绑定seat时指定的版本为1,部分Wayland compositor可能需要更高版本才能正常触发capabilities回调。建议使用registry返回的
version参数进行绑定,保证版本兼容性:seat = wl_registry_bind(registry, name, &wl_seat_interface, version);排除EGL初始化的干扰:暂时注释掉EGL相关代码(
eglGetDisplay、eglInitialize、eglTerminate),测试seat监听器是否能正常触发。部分环境下EGL初始化可能会影响Wayland事件处理,排除该因素后再逐步排查。增加关键操作的错误检查:为
wl_seat_add_listener、eglInitialize等函数添加返回值校验,确保操作未失败,比如:if (!wl_seat_add_listener(seat, &seat_listener, NULL)) { fprintf(stderr, "Failed to attach seat listener\n"); exit(EXIT_FAILURE); }验证系统层面的seat配置:使用
weston-info(Weston compositor)或对应compositor的工具,查看当前seat的能力,确认系统是否识别到键盘设备。如果compositor未配置键盘输入,客户端自然无法收到相关事件。
内容的提问来源于stack exchange,提问作者Ignatio Mobius

