小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

交互系統(tǒng)的構(gòu)建之(二)Linux上鼠標(biāo)和鍵盤的模擬控制

 mediatv 2012-11-30
交互系統(tǒng)的構(gòu)建之(二)Linux下鼠標(biāo)和鍵盤的模擬控制

交互系統(tǒng)的構(gòu)建之(二)Linux下鼠標(biāo)和鍵盤的模擬控制

zouxy09@qq.com

       交互系統(tǒng)的構(gòu)建之(一)http://blog.csdn.net/zouxy09/article/details/7919618 中提到我的整個(gè)交互系統(tǒng)包含以下部分: TLD系統(tǒng)、TTS語音合成、語音識(shí)別、手勢和語音控制鼠標(biāo)和鍵盤、運(yùn)行前加入手掌的檢測(這樣就不用鼠標(biāo)畫目標(biāo)box了)、拳頭的檢測等等。

 

目前已完成:

1、TLD系統(tǒng)的介紹與編譯:
http://blog.csdn.net/zouxy09/article/details/7893022

2TLD系統(tǒng)工作過程分析:
http://blog.csdn.net/zouxy09/article/details/7893026

3、重寫Makefile編譯TLD系統(tǒng):

http://blog.csdn.net/zouxy09/article/details/7919618

 

本文將完成:

        Linux下鼠標(biāo)和鍵盤的模擬控制,也就是為手勢和語音控制鼠標(biāo)和鍵盤部分服務(wù)的。

 

       有關(guān)于本系統(tǒng)構(gòu)建的文章結(jié)構(gòu)都會(huì)由三個(gè)部分來組織,一是該功能模塊的介紹和在Linux下簡單應(yīng)用程序的實(shí)現(xiàn);二是將該功能模塊整合到交互系統(tǒng)(先以TLD為地基)中去;三是分析目前存在的問題與未來的解決構(gòu)思。

 

一、input 子系統(tǒng)和模擬程序編寫:

        Linux 輸入子系統(tǒng)是 Linux內(nèi)核用于管理各種輸入設(shè)備(鍵盤,鼠標(biāo),遙控桿,書寫板等等)的。輸入子系統(tǒng)分為三塊: input core, drivers event handlers。正常的路徑是從底層硬件到驅(qū)動(dòng),從驅(qū)動(dòng)到 input core,從 input core event handler,從 event handler user space。

       這么說吧:如果是沒有這個(gè)input子系統(tǒng)的話,假如我們用鍵盤按下了一個(gè)鍵A,鍵盤會(huì)有一個(gè)linux的設(shè)備驅(qū)動(dòng)文件,假設(shè)是/dev/keyboard,我們的用戶空間的應(yīng)用程序就會(huì)打開并訪問這個(gè)設(shè)備文件/dev/keyboard,應(yīng)用程序會(huì)輪詢這個(gè)文件,一旦你按下了一個(gè)鍵A了,它就會(huì)返回給用戶程序說你按下了鍵A。那么如果有了input子系統(tǒng)的話,我們的用戶空間的應(yīng)用程序就不是直接打開和訪問鍵盤的設(shè)備驅(qū)動(dòng)文件了,而是訪問由鍵盤驅(qū)動(dòng)在input子系統(tǒng)中注冊(cè)的event事件文件,例如/dev/input/event3,而對(duì)于鍵盤驅(qū)動(dòng)來說,它也是實(shí)現(xiàn)由input子系統(tǒng)提供的接口就可以了。按下鍵了,就發(fā)送給input子系統(tǒng)。不再直接與用戶空間的應(yīng)用程序直接面對(duì)面了。這樣,就很方便的對(duì)驅(qū)動(dòng)和應(yīng)用程序都統(tǒng)一了接口,而且同一種接口還適合管理多種硬件。好像很簡單的問題給我啰嗦化了,不知道有沒有說錯(cuò),呵呵。

       這個(gè)input子系統(tǒng)可以很容易地讓我們?cè)谟脩艨臻g模擬鼠標(biāo)和鍵盤事件。例如,你可以寫一個(gè)應(yīng)用程序,往input子系統(tǒng)的/dev/input/event3設(shè)備文件(假設(shè)這個(gè)是鍵盤設(shè)備文件)寫入A,這樣就相當(dāng)于你通過鍵盤按下了A,而這個(gè)A對(duì)系統(tǒng)任意的一個(gè)當(dāng)前活動(dòng)窗口有效(捕捉)。

 

要實(shí)現(xiàn)這個(gè)功能,我們需要回答一下幾個(gè)問題:

1、往什么設(shè)備文件寫?

        也就是如何查看哪些設(shè)備文件是鍵盤的,哪些是鼠標(biāo)的,找到這些設(shè)備文件,我們才可以通過應(yīng)用程序來打開和寫入鍵值(或者鼠標(biāo)的控制信息)。

      通過 #cat /proc/bus/input/devices可以查看到當(dāng)前input子系統(tǒng)下面的所有event設(shè)備,我們找到鼠標(biāo)和鍵盤的即可。

例如:

I: Bus=0003 Vendor=046d Product=c018 Version=0111

N: Name=" USB Optical Mouse"

P: Phys=usb-0000:00:1d.1-2/input0

S: Sysfs=/class/input/input24

U: Uniq=

H: Handlers=mouse1 event2

B: EV=7

B: KEY=70000 0 0 0 0 0 0 0 0

B: REL=103

      上面Name處可以看到這個(gè)鼠標(biāo)設(shè)備,然后對(duì)應(yīng)的句柄Handlersevent2;

2、怎么寫入:

      大家都知道,Linux下萬物皆文件,所以對(duì)于文件操作我們只需要:open()write()就可以了。

3、要寫入什么東西(鍵值的編碼):

      在/usr/include/linux/input.h中有定義,這個(gè)文件定義了event事件的結(jié)構(gòu)體,API和標(biāo)準(zhǔn)按鍵的編碼等;我們需要將要寫入的按鍵編碼填充到結(jié)構(gòu)體中,然后寫入鍵盤或者鼠標(biāo)的事件設(shè)備驅(qū)動(dòng)文件中。

 

輸入事件的結(jié)構(gòu)體:

struct input_event {

    struct timeval time;  //按鍵時(shí)間

    __u16 type;  //事件的類型

    __u16 code;  //要模擬成什么按鍵

    __s32 value;  //是按下1還是釋放0

};

 

標(biāo)準(zhǔn)按鍵的編碼:(只列舉部分)

type:

事件的類型:

EV_KEY, 按鍵事件,如鍵盤的按鍵(按下哪個(gè)鍵),鼠標(biāo)的左鍵右鍵(是非擊下)等;

EV_REL, 相對(duì)坐標(biāo),主要是指鼠標(biāo)的移動(dòng)事件(相對(duì)位移);

EV_ABS, 絕對(duì)坐標(biāo),主要指觸摸屏的移動(dòng)事件,但好像這個(gè)不能用在鼠標(biāo)上面,也就是說無法通過這個(gè)來獲取鼠標(biāo)的絕對(duì)坐標(biāo)(鼠標(biāo)是一個(gè)相對(duì)位移的設(shè)備)。

 

code

事件的代碼:

       如果事件的類型代碼是EV_KEY,該代碼code為設(shè)備鍵盤代碼。代碼植0~127為鍵盤上的按鍵代碼,0x110~0x116 為鼠標(biāo)上按鍵代碼,其中0x110(BTN_ LEFT)為鼠標(biāo)左鍵,0x111(BTN_RIGHT)為鼠標(biāo)右鍵,0x112(BTN_ MIDDLE)為鼠標(biāo)中鍵。其它代碼含義請(qǐng)參看include/linux /input.h文件。該文件中會(huì)定義相應(yīng)的宏來代表不同的按鍵。

       如果事件的類型代碼是EV_REL,code值表示軌跡的類型。如指示鼠標(biāo)的X軸方向 REL_X (代碼為0x00),指示鼠標(biāo)的Y軸方向REL_Y,指示鼠標(biāo)中輪子方向REL_WHEEL。

 

value

事件的值:

       如果事件的類型代碼是EV_KEY,當(dāng)按鍵按下時(shí)值為1,松開時(shí)值為0

       如果事件的類型代碼是EV_ REL,value的正數(shù)值和負(fù)數(shù)值分別代表兩個(gè)不同方向的值。例如:如果codeREL_Xvalue10的話,就表示鼠標(biāo)相對(duì)于上一次的坐標(biāo),往x軸向右移動(dòng)10個(gè)像素點(diǎn)。

 

Linux下寫的簡單的模擬鼠標(biāo)和鍵盤事件的程序:

#include <stdio.h>

#include <linux/input.h>

#include <fcntl.h>

#include <sys/time.h>

#include <unistd.h>

 

//按鍵模擬,按鍵包含按下和松開兩個(gè)環(huán)節(jié)

void simulate_key(int fd, int kval)

{

         struct input_event event;

        gettimeofday(&event.time, 0);

       //按下kval

         event.type = EV_KEY;

         event.value = 1;

         event.code = kval;

         write(fd, &event, sizeof(event));

       //同步,也就是把它報(bào)告給系統(tǒng)

         event.type = EV_SYN;

         event.value = 0;

         event.code = SYN_REPORT;

         write(fd, &event, sizeof(event));

 

         memset(&event, 0, sizeof(event));

         gettimeofday(&event.time, 0);

         //松開kval

        event.type = EV_KEY;

         event.value = 0;

         event.code = kval;

         write(fd, &event, sizeof(event));

       //同步,也就是把它報(bào)告給系統(tǒng)

       event.type = EV_SYN;

       event.value = 0;

       event.code = SYN_REPORT;

       write(fd, &event, sizeof(event));

}

 

//鼠標(biāo)移動(dòng)模擬

void simulate_mouse(int fd, int rel_x, int rel_y)

{

    struct input_event event;

    gettimeofday(&event.time, 0);

    //x軸坐標(biāo)的相對(duì)位移

    event.type = EV_REL;

    event.value = rel_x;

    event.code = REL_X;

    write(fd, &event, sizeof(event));

    //y軸坐標(biāo)的相對(duì)位移

    event.type = EV_REL;

    event.value = rel_y;

    event.code = REL_Y;

    write(fd, &event, sizeof(event));

    //同步

    event.type = EV_SYN;

    event.value = 0;

    event.code = SYN_REPORT;

    write(fd, &event, sizeof(event));

}

 

int main(int argc, char **argv)

{

         int fd_mouse = -1;

         int fd_kbd = -1;

         int i = 0;

 

         fd_kbd = open("/dev/input/event3", O_RDWR);

         if(fd_kbd <= 0)

         {

                   printf("Can not open keyboard input file\n");

                   return -1;

         }

 

         fd_mouse = open("/dev/input/event2", O_RDWR);

        if(fd_mouse <= 0)

        {

                printf("Can not open mouse input file\n");

                return -1;

        }

        

         for (i = 0; i < 50; i++)

         {

                   simulate_key(fd_mouse, BTN_LEFT);  //模擬按下鼠標(biāo)左鍵

                   //if (i % 3 == 0)

                   //      simulate_key(fd_kbd, KEY_A);  //模擬按下鍵盤A

                  //模擬鼠標(biāo)相對(duì)上次xy軸相應(yīng)移動(dòng)10個(gè)像素

                   //simulate_mouse(fd_mouse, 10, 10);                  

                   sleep(3);

         }

         close(fd_kbd);

         close(fd_mouse);

}

 

       那么如何模擬組合鍵呢?其實(shí)和大家平時(shí)按鍵盤的過程是一樣的,我們用程序按照這個(gè)過程來模擬就可以了。以CTRL + SPACE為例:

//先發(fā)送一個(gè) CTRL 按下去的事件

//再發(fā)送一個(gè) SPACE 按下去的事件

//然后發(fā)送一個(gè)釋放 SPACE 的事件

//再發(fā)送一個(gè)釋放 CTRL 的事件

得注意每步的發(fā)送都需要同步一次。

 

二、整合到交互系統(tǒng)(先以TLD為地基)中去

       這個(gè)因?yàn)椴挥蒙婕邦~外鏈接一些庫,所以整合就變得很簡單了。只需要修改run_tld.cpp:

1、添加run_tld.cpp中沒有的,但模擬按鍵卻需要的頭文件:


#include <linux/input.h>

2、把simulate_key()simulate_mouse()兩個(gè)函數(shù)的實(shí)現(xiàn)復(fù)制到run_tld.cppmain函數(shù)的前面。然后在tld.init(last_gray, box, bb_file); 后面添加:

    //xiaoyi added here

    int fd_kbd = -1;

    int fd_mouse = -1;

    int open_success = 1;

    fd_kbd = open("/dev/input/event3", O_RDWR);

    if(fd_kbd <= 0)

    {

        printf("Can not open keyboard input file\n");

        open_success = 0;

    }

    fd_mouse = open("/dev/input/event2", O_RDWR);

    if(fd_mouse <= 0)

    {

        printf("Can not open mouse input file\n");

        open_success = 0;

    }

3、在TLD跟蹤到box后,獲取本幀跟蹤的box和上一幀box的位移,如果位移大于2個(gè)像素(避免抖動(dòng)),鼠標(biāo)就移動(dòng)8倍像素距離。

       pbox是當(dāng)前幀跟蹤到的目標(biāo)boxtbox是我自己定義的,用來存放上一幀跟蹤到的目標(biāo)box的。

        tld.processFrame(last_gray,current_gray,pts1,pts2,pbox,status,tl,bb_file);

        //Draw Points

        if (status) {

            drawPoints(frame,pts1);

            drawPoints(frame,pts2,Scalar(0,255,0));

            drawBox(frame,pbox);

            detections++;

 

            //xiaoyi added here

            x_pixel_move =(int)( (tbox.x + tbox.width)/2 - (pbox.x + pbox.width)/2);

            y_pixel_move =(int)( (pbox.y + pbox.height)/2 - (tbox.y + tbox.height)/2);

 

            if (norm(x_pixel_move) > 2 || norm(y_pixel_move) > 2 )

                simulate_mouse(fd_mouse, 8 * x_pixel_move, 8 * y_pixel_move);

            tbox = pbox;

            //下面這部分是用來測試當(dāng)手快速左右上下移動(dòng)時(shí),向系統(tǒng)發(fā)送左右上下的模擬按鍵事件

             /*

            if (open_success && (x_pixel_move > 8 || x_pixel_move < -8 || y_pixel_move > 8 || y_pixel_move < -8))

            {

                     if (x_pixel_move < -8)

                               simulate_key(fd_kbd, KEY_RIGHT);

                     else if (x_pixel_move > 8)

                               simulate_key(fd_kbd, KEY_LEFT);

                     else if (y_pixel_move < -8)

                                simulate_key(fd_kbd, KEY_UP);

                     else if (y_pixel_move > 8)

                                simulate_key(fd_kbd, KEY_DOWN);

 

                     tbox = pbox;

                     x_pixel_move = 0;

                     y_pixel_move = 0;

            }

            */

}

 

三、存在的問題和解決思路:
1、鼠標(biāo)絕對(duì)坐標(biāo)的獲取:據(jù)我的了解,好像Linux或者c并不提供直接獲取鼠標(biāo)絕對(duì)坐標(biāo)的API,而需要通過第三方的API來獲取。另外,也許也不需要獲取絕對(duì)坐標(biāo),所以暫時(shí)擱置;

2、手掌控制鼠標(biāo)不穩(wěn)定(漂移)與范圍控制沒處理好:可能通過卡爾曼濾波和速度映射等方法來做改進(jìn),后面再處理;

3、代碼結(jié)構(gòu)亂:一旦自己后面加入了很多模塊,這樣代碼就會(huì)比較混亂,所以需要后期進(jìn)行各模塊代碼的整理,已達(dá)到內(nèi)聚性強(qiáng)點(diǎn),而且代碼容易管理。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多