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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 08:35:06