Linux捕捉鼠标事件和键盘事件的方法

前段时间,工作中需要完成一个判断一段时间内是否人工操作操作的功能,基本思路就是要在后台监听键盘和鼠标的输入事件。那么如何能够捕捉鼠标和键盘的事件呢?下面分享我们的实现原理·及方法。

捕捉设备输入事件的原理

打开/dev/input目录,执行ls命令,我们可以看到类似下面的文件列表。

$ ls -l
total 0
crw-r-----. 1 root root 13, 64 Jan 29  2018 event0
crw-r-----. 1 root root 13, 65 Jan 29  2018 event1
crw-r-----. 1 root root 13, 66 Jan 29  2018 event2
crw-r-----. 1 root root 13, 67 Jan 29  2018 event3
crw-r-----. 1 root root 13, 68 Jan 29  2018 event4
crw-r-----. 1 root root 13, 63 Jan 29  2018 mice
crw-r-----. 1 root root 13, 32 Jan 29  2018 mouse0
crw-r-----. 1 root root 13, 33 Jan 29  2018 mouse1
crw-r-----. 1 root root 13, 34 Jan 29  2018 mouse2

熟悉Linux的朋友一定已经知道这里列出的文件是设备文件。在Linux环境中,/dev/input目录下的事件文件(event*)都是在驱动中调用input_register_device(struct input_dev *dev)产生的。每个event将上报指定的事件,如触摸、Mouse、按键等。读取这些事件文件将获取该事件文件对应设备的输入信息。

事件数据结构

在linux/input.h文件中定义了event事件的输入数据的结构体,该结构体定义如下:

struct input_event {
    struct timeval time; 
    __u16 type;
    __u16 code;
    __s32 value;
};

time, 指事件发生的时间,具体定义如下:

struct timeval
{
    __time_t tv_sec;        /* Seconds.  */
    __suseconds_t tv_usec;  /* Microseconds.  */
};

type,指事件类型,常见的事件类型有:
EV_KEY,按键事件,键盘的按键,鼠标的左键右键等;
EV_REL,相对坐标,主要用于鼠标的移动事件;
EV_ABS,绝对坐标,主要用于触摸屏的移动事件。

code 事件代码,当事件类型为EV_KEY时,该代码为设备键盘代码,在input.h文件中以KEY_开头定义;
value 事件的值,当事件类型代码是EV_KEY时,按键操作值为1,释放操作值为0,事件类型代码为EV_REL是,value为正数值和负数值分别代表连个不同方向的值。

如何确定那个事件文件对应哪个设备

/proc/bus/input/device文件中描述了与event对应的相关设备信息,例如如下信息:

$cat devices 
I: Bus=0019 Vendor=0000 Product=0001 Version=0000
N: Name="Power Button"
P: Phys=LNXPWRBN/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
U: Uniq=
H: Handlers=kbd event0 
B: EV=3
B: KEY=10000000000000 0

I: Bus=0017 Vendor=0001 Product=0001 Version=0100
N: Name="Macintosh mouse button emulation"
P: Phys=
S: Sysfs=/devices/virtual/input/input1
U: Uniq=
H: Handlers=mouse0 event1 
B: EV=7
B: KEY=70000 0 0 0 0
B: REL=3

I: Bus=0011 Vendor=0001 Product=0001 Version=ab41
N: Name="AT Translated Set 2 keyboard"
P: Phys=isa0060/serio0/input0
S: Sysfs=/devices/platform/i8042/serio0/input/input2
U: Uniq=
H: Handlers=kbd event2 
B: EV=120013
B: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe
B: MSC=10
B: LED=7

I: Bus=0011 Vendor=0002 Product=0005 Version=0000
N: Name="ImPS/2 Generic Wheel Mouse"
P: Phys=isa0060/serio1/input0
S: Sysfs=/devices/platform/i8042/serio1/input/input3
U: Uniq=
H: Handlers=mouse1 event3 
B: EV=7
B: KEY=70000 0 0 0 0
B: REL=103

在上面的H:中可以看到对应的eventxx。

捕捉键盘事件的实现方法

通过上节列出的文件,我们可以获得键盘对应的事件文件。通常键盘对应的事件文件为event2。监听这个文件,我们就能捕获到键盘的事件。
以下代码是我实现的监听键盘事件的函数代码,20秒内没有键盘事件,程序退出:

#include <sys/types.h>
#include <fcntl.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <linux/input.h>

void listen_device(const char *dev, int timeout)
{
    int retval;
    fd_set readfds;
    struct timeval tv;

    int fd = open(dev, O_RDONLY);

    struct input_event event;

    if (fd < 0)
    {
        perror(dev);
        return;
    }

    while (1)
    {
        FD_ZERO(&readfds);
        FD_SET(fd, &readfds);
        tv.tv_sec = timeout;
        tv.tv_usec = 0;
        if((retval = select(fd+1, &readfds, NULL, NULL, &tv)) == 1)
        {
            if (read(fd, &event, sizeof(event)) == sizeof(event))
            {
                if (event.type == EV_KEY)
                {
                    if (event.value == 0 || event.value == 1)
                    {
                        printf("key %d %s\n", event.code, event.value ? "Pressed" : "Released");
                    }
                }
                else
                {
                    printf("type=%x %d %d\n", event.type, event.code, event.value);
                }
            }
        }
        else
        {
            break;
        }
    }

    close(fd);
}

void listen_keyboard(int timeout)
{
    listen_device("/dev/input/event2", timeout);
}

int main(int argc, char **argv)
{
    listen_keyboard(20);
    printf("keyboard timeout\n");
    return 0;
}

捕捉鼠标事件的实现方法

我们也可以通过上面的方面获取鼠标的event文件,从而实现鼠标事件的捕获。但事实上鼠标有更方便的捕获方法,就是同目录下的mice文件,通过该文件可以获取解析后的鼠标事件。
具体方法如下:
(1)打开"/dev/input/mice"文件。
(2)读3个字节。三个字节的值分别是“Button类型”,“X的相对位移”,“Y的相对位移”。这里先用Button, xRel, yRel表示。
(3)取Button的低3位(Button & 0x07)。0x00 = LeftButtonUp, 0x01 = LeftButtonDown, 0x02 = RightButtonDown.
以下代码是我实现的监鼠标事件的函数代码:

#include <sys/types.h>
#include <fcntl.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <linux/input.h>

void listen_mice(const char *dev, int timeout)
{
    char buf[256];
    int n_len;

    int retval;
    fd_set readfds;
    struct timeval tv;

    int fd = open(dev, O_RDONLY);

    if (fd < 0)
    {
        perror(dev);
        return;
    }

    while (1)
    {
        FD_ZERO(&readfds);
        FD_SET(fd, &readfds);
        tv.tv_sec = timeout;
        tv.tv_usec = 0;
        if((retval = select(fd+1, &readfds, NULL, NULL, &tv)) == 1)
        {
            if ((n_len = read(fd, buf, sizeof(buf))) > 0)
            {
                if (n_len == 3)
                {
                    printf("Button: %d, xRef=%d, yRef=%d\n", buf[0]&0x07, buf[1], buf[2]);
                }
            }
        }
        else
        {
            break;
        }
    }

    close(fd);
}

void listen_mouse(int timeout)
{
    listen_mice("/dev/input/mice", timeout);
}

int main(int argc, char **argv)
{
    listen_mouse (20);
    printf("mouse timeout\n");
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352