Linux捕捉鼠標(biāo)事件和鍵盤事件的方法

前段時間往核,工作中需要完成一個判斷一段時間內(nèi)是否人工操作操作的功能瞧栗,基本思路就是要在后臺監(jiān)聽鍵盤和鼠標(biāo)的輸入事件尝蠕。那么如何能夠捕捉鼠標(biāo)和鍵盤的事件呢列肢?下面分享我們的實現(xiàn)原理·及方法血柳。

捕捉設(shè)備輸入事件的原理

打開/dev/input目錄官册,執(zhí)行l(wèi)s命令,我們可以看到類似下面的文件列表难捌。

$ 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的朋友一定已經(jīng)知道這里列出的文件是設(shè)備文件膝宁。在Linux環(huán)境中鸦难,/dev/input目錄下的事件文件(event*)都是在驅(qū)動中調(diào)用input_register_device(struct input_dev *dev)產(chǎn)生的。每個event將上報指定的事件员淫,如觸摸合蔽、Mouse、按鍵等介返。讀取這些事件文件將獲取該事件文件對應(yīng)設(shè)備的輸入信息拴事。

事件數(shù)據(jù)結(jié)構(gòu)

在linux/input.h文件中定義了event事件的輸入數(shù)據(jù)的結(jié)構(gòu)體,該結(jié)構(gòu)體定義如下:

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

time, 指事件發(fā)生的時間圣蝎,具體定義如下:

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

type刃宵,指事件類型,常見的事件類型有:
EV_KEY徘公,按鍵事件牲证,鍵盤的按鍵,鼠標(biāo)的左鍵右鍵等关面;
EV_REL坦袍,相對坐標(biāo),主要用于鼠標(biāo)的移動事件等太;
EV_ABS键闺,絕對坐標(biāo),主要用于觸摸屏的移動事件澈驼。

code 事件代碼,當(dāng)事件類型為EV_KEY時筛武,該代碼為設(shè)備鍵盤代碼缝其,在input.h文件中以KEY_開頭定義;
value 事件的值徘六,當(dāng)事件類型代碼是EV_KEY時内边,按鍵操作值為1,釋放操作值為0待锈,事件類型代碼為EV_REL是漠其,value為正數(shù)值和負(fù)數(shù)值分別代表連個不同方向的值。

如何確定那個事件文件對應(yīng)哪個設(shè)備

/proc/bus/input/device文件中描述了與event對應(yīng)的相關(guān)設(shè)備信息竿音,例如如下信息:

$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:中可以看到對應(yīng)的eventxx和屎。

捕捉鍵盤事件的實現(xiàn)方法

通過上節(jié)列出的文件,我們可以獲得鍵盤對應(yīng)的事件文件春瞬。通常鍵盤對應(yīng)的事件文件為event2柴信。監(jiān)聽這個文件,我們就能捕獲到鍵盤的事件宽气。
以下代碼是我實現(xiàn)的監(jiān)聽鍵盤事件的函數(shù)代碼随常,20秒內(nèi)沒有鍵盤事件潜沦,程序退出:

#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;
}

捕捉鼠標(biāo)事件的實現(xiàn)方法

我們也可以通過上面的方面獲取鼠標(biāo)的event文件,從而實現(xiàn)鼠標(biāo)事件的捕獲绪氛。但事實上鼠標(biāo)有更方便的捕獲方法唆鸡,就是同目錄下的mice文件,通過該文件可以獲取解析后的鼠標(biāo)事件枣察。
具體方法如下:
(1)打開"/dev/input/mice"文件争占。
(2)讀3個字節(jié)。三個字節(jié)的值分別是“Button類型”询件,“X的相對位移”燃乍,“Y的相對位移”。這里先用Button, xRel, yRel表示宛琅。
(3)取Button的低3位(Button & 0x07)刻蟹。0x00 = LeftButtonUp, 0x01 = LeftButtonDown, 0x02 = RightButtonDown.
以下代碼是我實現(xiàn)的監(jiān)鼠標(biāo)事件的函數(shù)代碼:

#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;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市嘿辟,隨后出現(xiàn)的幾起案子舆瘪,更是在濱河造成了極大的恐慌,老刑警劉巖红伦,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件英古,死亡現(xiàn)場離奇詭異,居然都是意外死亡昙读,警方通過查閱死者的電腦和手機召调,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛮浑,“玉大人唠叛,你說我怎么就攤上這事【谥桑” “怎么了艺沼?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蕴掏。 經(jīng)常有香客問我障般,道長,這世上最難降的妖魔是什么盛杰? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任挽荡,我火速辦了婚禮,結(jié)果婚禮上即供,老公的妹妹穿的比我還像新娘徐伐。我一直安慰自己,他們只是感情好募狂,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布办素。 她就那樣靜靜地躺著角雷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪性穿。 梳的紋絲不亂的頭發(fā)上勺三,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音需曾,去河邊找鬼吗坚。 笑死,一個胖子當(dāng)著我的面吹牛呆万,可吹牛的內(nèi)容都是我干的商源。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼谋减,長吁一口氣:“原來是場噩夢啊……” “哼牡彻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起出爹,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤庄吼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后严就,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體总寻,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年梢为,在試婚紗的時候發(fā)現(xiàn)自己被綠了渐行。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡铸董,死狀恐怖祟印,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情袒炉,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布樊零,位于F島的核電站我磁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏驻襟。R本人自食惡果不足惜夺艰,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沉衣。 院中可真熱鬧郁副,春花似錦、人聲如沸豌习。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至既荚,卻和暖如春稚失,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背恰聘。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工句各, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人晴叨。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓凿宾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親兼蕊。 傳聞我的和親對象是個殘疾皇子初厚,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345