You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为库添加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 = {&registry_add_object, &registry_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, &registry_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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 23:42:27