歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android平台開發-Android keypad map-Android按鍵識別及映射過程

一、Android底層按鍵事件處理過程    在系統啟動後,在文件。。。中,android 會通過    static const char *device_path = "/dev/input";
    bool EventHub::penPlatformInput(void)
    res = scan_dir(device_path);    通過下面的函數打開設備。
    int EventHub::pen_device(const char *deviceName)
    {
      ...
      fd = open(deviceName, O_RDWR);
      ... 
      mFDs[mFDCount].fd = fd;
      mFDs[mFDCount].events = POLLIN;
      ...
      ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname);
      ...
      const char* root = getenv("ANDROID_ROOT");
      snprintf(keylayoutFilename, sizeof(keylayoutFilename),
                 "%s/usr/keylayout/%s.kl", root, tmpfn);
      ...
      device->layoutMap->load(keylayoutFilename);
      ...
  }  打開設備的時候,如果 device->classes&CLASS_KEYBOARD 不等於 0 表明是鍵盤。
  常用輸入設備的定義有:
  enum {
        CLASS_KEYBOARD      = 0x00000001, //鍵盤
        CLASS_ALPHAKEY      = 0x00000002, //
        CLASS_TOUCHSCREEN   = 0x00000004, //觸摸屏
        CLASS_TRACKBALL     = 0x00000008  //軌跡球
  };  打開鍵盤設備的時候通過上面的 ioctl 獲得設備名稱,命令字 EVIOCGNAME 的定義在文件:    kernel/include/linux/input.h 中。
  對於按鍵事件,調用mDevices->layoutMap->map進行映射,調用的是文件 KeyLayoutMap.cpp  (frameworks\base\libs\ui)中的函數:
  status_t KeyLayoutMap::load(const char* filename)通過解析 <Driver name>.kl 把按鍵的  映射關系保存在 :KeyedVector<int32_t,Key> m_keys; 中。  當獲得按鍵事件以後調用: status_t KeyLayoutMap::map(int32_t scancode, int32_t  *keycode, uint32_t *flags)
  由映射關系 KeyedVector<int32_t,Key> m_keys 把掃描碼轉換成andorid上層可以識別的按鍵。

二、按鍵映射   Key layout maps的路徑是 /system/usr/keylayout,第一個查找的名字是按鍵驅動的名字,例如  mxckpd.kl。如果沒有的話,默認為qwerty.kl。
  Key character maps的路徑是 /system/usr/keychars,第一個查找的名字是按鍵驅動的名字,例如  mxckpd.kcm。如果沒有的話,默認為qwerty.kl。
 
  qwerty.kl是 UTF-8類型的,格式為:key SCANCODE KEYCODE [FLAGS...]。
 
  SCANCODE表示按鍵掃描碼;
  KEYCODE表示鍵值,例如HOME,BACK,1,2,3...
  FLAGS有如下定義:
    SHIFT: While pressed, the shift key modifier is set
    ALT: While pressed, the alt key modifier is set
    CAPS: While pressed, the caps lock key modifier is set
    WAKE: When this key is pressed while the device is asleep, the device will                  wake up and the key event gets sent to the app.
    WAKE_DROPPED: When this key is pressed while the device is asleep, the device                  will wake up and the key event does not get sent to the app
 
  qwerty.kcm文件為了節省空間,在編譯過程中會用工具makekcharmap轉化為二進制文件qwerty.bin。三、按鍵分發   1、輸入事件分發線程
 
    在frameworks/base/services/java/com/android/server/WindowManagerService.java裡創    建了一個輸入事件分發線程,它負責把事件分發到相應的窗口上去。
   
    在WindowManagerService類的構造函數WindowManagerService()中:
        mQueue = new KeyQ(); //讀取按鍵
        mInputThread = new InputDispatcherThread();  //創建分發線程    
        ...    
        mInputThread.start();
     
    在啟動的線程InputDispatcherThread中:
        run()
        process();
        QueuedEvent ev = mQueue.getEvent(...)
     
      在process() 方法中進行處理事件:
        switch (ev.classType)
          case RawInputEvent.CLASS_KEYBOARD:
             ...
             dispatchKey((KeyEvent)ev.event, 0, 0);
             mQueue.recycleEvent(ev);
             break;
          case RawInputEvent.CLASS_TOUCHSCREEN:
             //Log.i(TAG, "Read next event " + ev);
             dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
             break;
         case RawInputEvent.CLASS_TRACKBALL:
             dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
             break;
            
  2、上層讀取按鍵的流程     WindowManagerService()  //(frameworks\base\services\java\com\android\server                                                    \WindowManagerService.java)
      |
    KeyQ()  //KeyQ 是抽象類 KeyInputQueue 的實現
      |
    InputDeviceReader //在 KeyInputQueue 類中創建的線程
     |
    readEvent()  //
     |
    android_server_KeyInputQueue_readEvent() //frameworks\base\services\jni\                                              com_android_server_KeyInputQueue.cpp
     |
    hub->getEvent()
     |
    EventHub::getEvent() //frameworks\base\libs\ui\EventHub.cpp
     |

    res = read(mFDs.fd, &iev, sizeof(iev)); //

 

     Android的應用不僅僅是平板電腦,MID,phone,還可以放到STB機頂盒,智能家庭終端上面去,所以按鍵的映射是一定要自定義的,不管按鍵是固定在設備上,還是通過無線設備還是藍牙遙控,都需要鍵的映射。
       Android也是基於Linux的核心,大部分時候都是操作系統在調度任務,執行任務。相應的,Android輸入系統也是遵循LINUX的input輸入輸出子系統,關於這部分的分析可以Google,有許多原理方面的分析。Android使用標准的Linux輸入事件設備(/dev/event0),驅動描述可以查看內核樹頭文件include/linux/input.h。如果想深入學習Linux input subsystem,可以訪問:http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.24.y.git;a=blob;f=Documentation/input/input.txt

注:event0是您的keypad/gpio-key注冊到內核的節點號,如果有其他的輸入設備注冊進內核,也可以是event1。

Copyright © Linux教程網 All Rights Reserved