求助:使用libinput获取键盘信息时完全无法接收任何事件
解决libinput无法获取设备事件的问题
问题背景
使用libinput编写C++程序获取键盘相关信息,但调用libinput_resume()和libinput_dispatch()后无法收到任何事件,运行日志显示多数输入设备打开失败,少数设备打开后立即被关闭。
原问题代码
#include <cerrno> #include <iostream> #include <libinput.h> #include <libudev.h> #include <unistd.h> #include <fcntl.h> template<typename... Args> void log_debug(Args&&... args) { (std::clog << ... << std::forward<Args>(args)) << '\n'; } template<typename... Args> void log_error(Args&&... args) { (std::cerr << ... << std::forward<Args>(args)) << '\n'; } int open_restricted(const char* path, int flags, void*) { log_debug("Opening device at path ", path); int fd = open(path, flags); log_debug("Device FD result : ",fd); return fd; } void close_restricted(int fd, void*) { log_debug("Closing device FD : ", fd); close(fd); } const static struct libinput_interface interface = { .open_restricted = open_restricted, .close_restricted = close_restricted, }; int main() { auto udev_ctx = udev_new(); auto libinput_ctx = libinput_udev_create_context(&interface, nullptr, udev_ctx); if(!udev_ctx || !libinput_ctx) { log_error("libinput error"); } int result = libinput_udev_assign_seat(libinput_ctx, "seat0"); if( result < 0) { log_error("Could not aquire udev seat!\n errno: ", result); } result = libinput_resume(libinput_ctx); if(result < 0) { log_error("Could not acquire libinput"); } result = libinput_dispatch(libinput_ctx); if(result < 0) { log_error("Could not dispatch libinput"); } while(auto evt = libinput_get_event(libinput_ctx)) { switch(libinput_event_get_type(evt)) { case LIBINPUT_EVENT_NONE: case LIBINPUT_EVENT_DEVICE_ADDED: case LIBINPUT_EVENT_DEVICE_REMOVED: default: { log_debug("HOORAY"); } break; } libinput_event_destroy(evt); } }
原运行日志
[17:09:49][DEBUG] Opening device at path /dev/input/event1 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event0 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event3 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event4 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event5 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event7 [17:09:49][DEBUG] Device FD result : 6 [17:09:49][DEBUG] Closing device FD : 6 [17:09:49][DEBUG] Opening device at path /dev/input/event10 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event11 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event8 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event9 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event2 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event12 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event13 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event14 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event15 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event16 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event17 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event18 [17:09:49][DEBUG] Device FD result : -1 [17:09:49][DEBUG] Opening device at path /dev/input/event6 [17:09:49][DEBUG] Device FD result : -1
修复后的代码
#include <cerrno> #include <iostream> #include <libinput.h> #include <libudev.h> #include <unistd.h> #include <fcntl.h> #include <cstring> #include <poll.h> template<typename... Args> void log_debug(Args&&... args) { (std::clog << ... << std::forward<Args>(args)) << '\n'; } template<typename... Args> void log_error(Args&&... args) { (std::cerr << ... << std::forward<Args>(args)) << '\n'; } int open_restricted(const char* path, int flags, void*) { log_debug("Opening device at path ", path); int fd = open(path, flags); if (fd == -1) { log_error("Failed to open ", path, ": ", strerror(errno)); } log_debug("Device FD result : ",fd); return fd; } void close_restricted(int fd, void*) { log_debug("Closing device FD : ", fd); close(fd); } const static struct libinput_interface interface = { .open_restricted = open_restricted, .close_restricted = close_restricted, }; int main() { auto udev_ctx = udev_new(); if (!udev_ctx) { log_error("Failed to create udev context"); return 1; } auto libinput_ctx = libinput_udev_create_context(&interface, nullptr, udev_ctx); if (!libinput_ctx) { log_error("Failed to create libinput context"); udev_unref(udev_ctx); return 1; } int result = libinput_udev_assign_seat(libinput_ctx, "seat0"); if( result < 0) { log_error("Could not acquire udev seat! Error code: ", result); libinput_unref(libinput_ctx); udev_unref(udev_ctx); return 1; } result = libinput_resume(libinput_ctx); if(result < 0) { log_error("Could not resume libinput"); libinput_unref(libinput_ctx); udev_unref(udev_ctx); return 1; } struct pollfd fds; fds.fd = libinput_get_fd(libinput_ctx); fds.events = POLLIN; while (true) { int poll_result = poll(&fds, 1, -1); if (poll_result == -1) { if (errno == EINTR) continue; log_error("Poll failed: ", strerror(errno)); break; } if (fds.revents & POLLIN) { result = libinput_dispatch(libinput_ctx); if (result < 0) { log_error("Could not dispatch libinput"); break; } while(auto evt = libinput_get_event(libinput_ctx)) { switch(libinput_event_get_type(evt)) { case LIBINPUT_EVENT_DEVICE_ADDED: log_debug("Device added"); auto dev = libinput_event_get_device(evt); if (libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_KEYBOARD)) { log_debug("Found keyboard: ", libinput_device_get_name(dev)); } break; case LIBINPUT_EVENT_DEVICE_REMOVED: log_debug("Device removed"); break; case LIBINPUT_EVENT_KEYBOARD_KEY: auto key_evt = libinput_event_get_keyboard_event(evt); log_debug("Key ", libinput_event_keyboard_get_key(key_evt), " state: ", libinput_event_keyboard_get_key_state(key_evt)); break; default: log_debug("Unhandled event type: ", libinput_event_get_type(evt)); break; } libinput_event_destroy(evt); } } } libinput_unref(libinput_ctx); udev_unref(udev_ctx); return 0; }
关键修复点
- 权限问题:日志中
open返回-1是因为普通用户无输入设备访问权限,执行sudo usermod -aG input $USER后重新登录即可解决。 - 事件循环逻辑:原代码仅调用一次
libinput_dispatch()就尝试取事件,正确做法是用poll监听libinput的文件描述符,有事件到来时再调度并处理。 - 错误处理完善:在
open_restricted中添加errno打印,便于定位设备打开失败原因;同时完善资源释放逻辑,避免内存泄漏。 - 事件类型覆盖:新增键盘按键事件处理,确保能捕获键盘输入;添加设备能力判断,精准识别键盘设备。
内容的提问来源于stack exchange,提问作者user3001150
相关产品推荐
相关产品推荐

