关闭

android键盘映射之二

755人阅读 评论(0) 收藏 举报

按键、触摸屏流、轨迹球程分析

输入事件分发线程
在frameworks/base/services/java/com/android/server/WindowManagerService.java里创建了一个输入事件分发线程,它负责把事件分发到相应的窗口上去。


按键触摸屏流程分析:

    WindowManagerService类的构造函数

    WindowManagerService()

    mQueue = new KeyQ();

因为 WindowManagerService.java (frameworks\base\services\java\com\android\server)中有:

private class KeyQ extends KeyInputQueue implements KeyInputQueue.FilterCallback

KeyQ 是抽象类 KeyInputQueue 的实现,所以 new KeyQ类的时候实际上在 KeyInputQueue 类中创建了一个线程 InputDeviceReader 专门用来从设备读取按键事件,

代码:

Thread mThread = new Thread("InputDeviceReader") {

    
public void run() {

         // 在循环中调用:
     readEvent(ev);
         ...
         send
= preprocessEvent(di, ev);
         //实际调用的是 KeyQ 类的 preprocessEvent 函数
          ...
        
int keycode = rotateKeyCodeLocked(ev.keycode);
        int[] map = mKeyRotationMap;

        
for (int i=0; i<N; i+=2) {

            
if (map == keyCode)  

            
return map[i+1];

         }
//

         addLocked(di, curTime, ev.flags,RawInputEvent.CLASS_KEYBOARD,
                   newKeyEvent(di, di.mDownTime, curTime, down,keycode,
0, scancode,...));

         QueuedEvent ev
= obtainLocked(device, when, flags, classType, event);
     }
};

readEvent() 实际上调用的是 com_android_server_KeyInputQueue.cpp (frameworks\base\services\jni)中的

static jboolean android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,jobject event) 来读取事件,

bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,&flags, &value, &when)调用的是EventHub.cpp (frameworks\base\libs\ui)中的:

    bool EventHub::getEvent (int32_t* outDeviceId, int32_t* outType,

          int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,

          int32_t* outValue, nsecs_t* outWhen)

在函数中调用了读设备操作:res = read(mFDs.fd, &iev, sizeof(iev));

在构造函数 WindowManagerService()调用 new KeyQ() 以后接着调用了:

    mInputThread = new InputDispatcherThread();       
    ...     

    mInputThread.start();

来启动一个线程 InputDispatcherThread

    run()
    process();
    QueuedEvent ev = mQueue.getEvent(...)

因为WindowManagerService类中: final KeyQ mQueue;

所以实际上 InputDispatcherThread 线程实际上从 KeyQ 的事件队列中读取按键事件,在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;

===============================================================

补充一些内容:

在写程序时,需要捕获KEYCODE_HOME、KEYCODE_ENDCALL、KEYCODE_POWER这几个按键,但是这几个按键系统做了特殊处理,

在进行dispatch之前做了一些操作,HOME除了Keygaurd之外,不分发给任何其他APP,ENDCALL和POWER也类似,所以需要我们系统

处理之前进行处理。

我的做法是自己定义一个FLAG,在自己的程序中添加此FLAG,然后在WindowManagerServices.java中获取当前窗口的FLAG属性,如果是我

们自己设置的那个FLAG,则不进行特殊处理,直接分发按键消息到我们的APP当中,由APP自己处理。

这部分代码最好添加在

@Override
boolean preprocessEvent(InputDevice device, RawInputEvent event)

方法中,这个方法是KeyInputQueue中的一个虚函数,在处理按键事件之前的一个“预处理”。

PS:对HOME键的处理好像必需要修改PhoneWindowManager.java中的interceptKeyTi方法,具体可以参考对KeyGuard程序的处理。


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:300934次
    • 积分:3196
    • 等级:
    • 排名:第11180名
    • 原创:13篇
    • 转载:147篇
    • 译文:0篇
    • 评论:9条
    最新评论