android键盘映射之二

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

输入事件分发线程
在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程序的处理。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值