Linux下无X依赖检测键盘、鼠标及触控板活动的内核模块方案问询
Linux 无X依赖的输入活动检测(内核模块方案)
一、核心思路:复用Input子系统全局机制
不管键盘、鼠标还是触控板,本质上都是Linux Input子系统管理的input_dev设备,不需要单独为每种设备找回调。内核提供了全局的输入事件通知机制,能一次性捕获所有输入设备的活动,完全满足你“仅需知晓是否有输入”的需求,且不依赖X窗口。
二、内核模块实现方案
1. 推荐:注册全局输入事件通知器
使用register_input_notifier()函数,直接监听Input子系统的全局事件广播,所有输入设备的活动都会触发回调,代码简洁且无设备类型区分:
#include <linux/input.h> #include <linux/notifier.h> #include <linux/module.h> static int input_activity_notifier(struct notifier_block *nb, unsigned long action, void *data) { // 只要有输入事件产生,就会进入这里 if (action == INPUT_EVENT) { pr_info("Input activity detected\n"); // 这里可以添加你的逻辑:比如更新全局状态标记、唤醒进程等 } return NOTIFY_OK; } static struct notifier_block input_nb = { .notifier_call = input_activity_notifier, }; static int __init input_monitor_init(void) { return register_input_notifier(&input_nb); } static void __exit input_monitor_exit(void) { unregister_input_notifier(&input_nb); } module_init(input_monitor_init); module_exit(input_monitor_exit); MODULE_LICENSE("GPL");
2. 备选:遍历挂钩所有input_dev
如果需要更细粒度的设备控制,可以遍历系统中所有input_dev,为每个设备注册event回调(注意要处理原有回调的链式调用,避免覆盖):
#include <linux/input.h> #include <linux/mutex.h> #include <linux/module.h> // 保存原回调的结构体(可选,避免覆盖设备原有逻辑) struct input_dev_callback { struct input_dev *dev; void (*old_event)(struct input_dev *, unsigned int, unsigned int, int); struct list_head node; }; static LIST_HEAD(callback_list); static DEFINE_MUTEX(callback_mutex); static void custom_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct input_dev_callback *cb; pr_info("Activity from device: %s\n", dev->name); // 调用原设备的event回调 mutex_lock(&callback_mutex); list_for_each_entry(cb, &callback_list, node) { if (cb->dev == dev && cb->old_event) { cb->old_event(dev, type, code, value); break; } } mutex_unlock(&callback_mutex); } static int __init input_monitor_init(void) { struct input_dev *dev; struct input_dev_callback *cb; mutex_lock(&input_mutex); list_for_each_entry(dev, &input_dev_list, node) { cb = kmalloc(sizeof(*cb), GFP_KERNEL); if (!cb) continue; cb->dev = dev; cb->old_event = dev->event; dev->event = custom_input_event; list_add(&cb->node, &callback_list); } mutex_unlock(&input_mutex); return 0; } static void __exit input_monitor_exit(void) { struct input_dev_callback *cb, *tmp; mutex_lock(&input_mutex); list_for_each_entry_safe(cb, tmp, &callback_list, node) { cb->dev->event = cb->old_event; list_del(&cb->node); kfree(cb); } mutex_unlock(&input_mutex); } module_init(input_monitor_init); module_exit(input_monitor_exit); MODULE_LICENSE("GPL");
三、关于用户态evdev的疑问解答
/dev/input/mice是PS/2鼠标兼容设备,仅处理传统鼠标事件,不支持触控板和现代鼠标的全量事件,所以evdev示例针对event(n)设备是正确的——所有输入设备都会被映射到/dev/input/event*节点。- 用户态持续打开
event设备并通过select()/epoll()监听事件的方式是合理的,但内核模块方案更高效:无需常驻用户态进程,也不受用户权限限制。 - 若坚持用户态实现,可以遍历
/dev/input下所有event设备,逐个打开后加入epoll实例监听,就能捕获全系统输入活动,无需指定具体设备名。
内容的提问来源于stack exchange,提问作者JFBonzo
相关产品推荐
相关产品推荐

