Chinaunix首页 | 论坛 | 博客
  • 博客访问: 181210
  • 博文数量: 63
  • 博客积分: 725
  • 博客等级: 军士长
  • 技术积分: 375
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-12 19:55
文章分类

全部博文(63)

文章存档

2012年(35)

2011年(28)

分类:

2012-02-21 23:39:06

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)通过解析 .kl 把按键的
  映射关系保存在 :KeyedVector m_keys; 中。
  当获得按键事件以后调用: status_t KeyLayoutMap::map(int32_t scancode, int32_t
  *keycode, uint32_t *flags)
  由映射关系 KeyedVector 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)); //
    

 
阅读(600) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~