乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

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

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

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

      zouxy09@qq.com

             交互系統(tǒng)的構建之(一)http://blog.csdn.net/zouxy09/article/details/7919618 中提到我的整個交互系統(tǒng)包含以下部分: TLD系統(tǒng)、TTS語音合成、語音識別、手勢和語音控制鼠標和鍵盤、運行前加入手掌的檢測(這樣就不用鼠標畫目標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下鼠標和鍵盤的模擬控制,也就是為手勢和語音控制鼠標和鍵盤部分服務的。

       

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

       

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

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

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

             這個input子系統(tǒng)可以很容易地讓我們在用戶空間模擬鼠標和鍵盤事件。例如,你可以寫一個應用程序,往input子系統(tǒng)的/dev/input/event3設備文件(假設這個是鍵盤設備文件)寫入A,這樣就相當于你通過鍵盤按下了A,而這個A對系統(tǒng)任意的一個當前活動窗口有效(捕捉)。

       

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

      1、往什么設備文件寫?

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

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

      例如:

      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處可以看到這個鼠標設備,然后對應的句柄Handlersevent2;

      2、怎么寫入:

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

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

            在/usr/include/linux/input.h中有定義,這個文件定義了event事件的結構體,API和標準按鍵的編碼等;我們需要將要寫入的按鍵編碼填充到結構體中,然后寫入鍵盤或者鼠標的事件設備驅(qū)動文件中。

       

      輸入事件的結構體:

      struct input_event {

          struct timeval time;  //按鍵時間

          __u16 type;  //事件的類型

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

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

      };

       

      標準按鍵的編碼:(只列舉部分)

      type:

      事件的類型:

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

      EV_REL, 相對坐標,主要是指鼠標的移動事件(相對位移);

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

       

      code

      事件的代碼:

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

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

       

      value

      事件的值:

             如果事件的類型代碼是EV_KEY,當按鍵按下時值為1,松開時值為0;

             如果事件的類型代碼是EV_ REL,value的正數(shù)值和負數(shù)值分別代表兩個不同方向的值。例如:如果codeREL_X,value10的話,就表示鼠標相對于上一次的坐標,往x軸向右移動10個像素點。

       

      Linux下寫的簡單的模擬鼠標和鍵盤事件的程序:

      #include <stdio.h>

      #include <linux/input.h>

      #include <fcntl.h>

      #include <sys/time.h>

      #include <unistd.h>

       

      //按鍵模擬,按鍵包含按下和松開兩個環(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));

             //同步,也就是把它報告給系統(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));

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

             event.type = EV_SYN;

             event.value = 0;

             event.code = SYN_REPORT;

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

      }

       

      //鼠標移動模擬

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

      {

          struct input_event event;

          gettimeofday(&event.time, 0);

          //x軸坐標的相對位移

          event.type = EV_REL;

          event.value = rel_x;

          event.code = REL_X;

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

          //y軸坐標的相對位移

          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);  //模擬按下鼠標左鍵

                         //if (i % 3 == 0)

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

                        //模擬鼠標相對上次xy軸相應移動10個像素

                         //simulate_mouse(fd_mouse, 10, 10);                  

                         sleep(3);

               }

               close(fd_kbd);

               close(fd_mouse);

      }

       

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

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

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

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

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

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

       

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

             這個因為不用涉及額外鏈接一些庫,所以整合就變得很簡單了。只需要修改run_tld.cpp:

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


      #include <linux/input.h>

      2、把simulate_key()simulate_mouse()兩個函數(shù)的實現(xiàn)復制到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個像素(避免抖動),鼠標就移動8倍像素距離。

             pbox是當前幀跟蹤到的目標box,tbox是我自己定義的,用來存放上一幀跟蹤到的目標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;

                  //下面這部分是用來測試當手快速左右上下移動時,向系統(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、鼠標絕對坐標的獲取:據(jù)我的了解,好像Linux或者c并不提供直接獲取鼠標絕對坐標的API,而需要通過第三方的API來獲取。另外,也許也不需要獲取絕對坐標,所以暫時擱置;

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

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


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

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多