注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

东月之神

在单纯的观念里面,生命就容易变得比较深刻!

 
 
 

日志

 
 
关于我

别驻足,梦想要不停追逐,别认输,熬过黑暗才有日出,要记住,成功就在下一步,路很苦,汗水是最美的书!

网易考拉推荐

(转)Android 4.0 事件输入(Event Input)系统 (下)  

2012-03-31 12:47:25|  分类: Android |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
4.3.1.1.2 事件驱动设备事件处理processEventsForDeviceLocked

   下面的分析处理以单点触摸为例,对于单点触摸Touch Down时,它将报告以下事件:

    代码:

    input_report_abs(myInputDev, ABS_X, event->x);
    input_report_abs(myInputDev, ABS_Y, event->y);

    产生的事件:*type, code, value
                          EV_ABS,ABS_X,event->x
                          EV_ABS,ABS_Y,event->y     

    代码: 

    input_report_key(myInputDev, BTN_TOUCH,  1);
    产生的事件:*type, code, value
                          EV_KEY, BTN_TOUCH, 1

     代码:

      input_sync(myInputDev);
        它调用input_event(dev, EV_SYN, SYN_REPORT, 0);
     产生的事件:*type, code, value
                           EV_SYN, SYN_REPORT, 0

      

     它负责处理来自于同一个设备且在mEventBuffer中连续的多个事件,其函数原型如下:

  1. void InputReader::processEventsForDeviceLocked(int32_t deviceId,  
  2.         const RawEvent* rawEvents, size_t count) {  
  3.     ssize_t deviceIndex = mDevices.indexOfKey(deviceId);  
  4.     if (deviceIndex < 0) {  
  5.         LOGW("Discarding event for unknown deviceId %d.", deviceId);  
  6.         return;  
  7.     }  
  8.   
  9.     InputDevice* device = mDevices.valueAt(deviceIndex);  
  10.     if (device->isIgnored()) {  
  11.         //LOGD("Discarding event for ignored deviceId %d.", deviceId);  
  12.         return;  
  13.     }  
  14.   
  15.     device->process(rawEvents, count);  
  16. }  

void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex < 0) { LOGW("Discarding event for unknown deviceId %d.", deviceId); return; } InputDevice* device = mDevices.valueAt(deviceIndex); if (device->isIgnored()) { //LOGD("Discarding event for ignored deviceId %d.", deviceId); return; } device->process(rawEvents, count); }

它其实很简单,根据输入的deviceId找到对应的InputDevice,然后调用InputDevice::process以对设备输入事件进行处理。InputDevice::process主要源码如下:

 

  1. void InputDevice::process(const RawEvent* rawEvents, size_t count) {  
  2.     // Process all of the events in order for each mapper.  
  3.     // We cannot simply ask each mapper to process them in bulk because mappers may  
  4.     // have side-effects that must be interleaved.  For example, joystick movement events and  
  5.     // gamepad button presses are handled by different mappers but they should be dispatched  
  6.     // in the order received.  
  7.   
  8.     size_t numMappers = mMappers.size();  
  9.     for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++)   
  10.     {  
  11.         for (size_t i = 0; i < numMappers; i++) {  
  12.             InputMapper* mapper = mMappers[i];  
  13.             mapper->process(rawEvent);  
  14.         }  
  15.     }  
  16. }  

void InputDevice::process(const RawEvent* rawEvents, size_t count) { // Process all of the events in order for each mapper. // We cannot simply ask each mapper to process them in bulk because mappers may // have side-effects that must be interleaved. For example, joystick movement events and // gamepad button presses are handled by different mappers but they should be dispatched // in the order received. size_t numMappers = mMappers.size(); for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->process(rawEvent); } } }

       从上面的代码中可以看出,在InputDevice::process中,对于传入的每一个RawEvent,依次调用InputDevice中的每一个InputMapper来进行处理。前面提到过,InputDevice包含一组处理对应设备事件InputMapper,现在这些InputMapper开始干活了。
      下面以处理一个单点触摸事件设备的事件为例,进行分析,其它的处理流程类似。对于mapper->process需要查看InputReader::createDeviceLocked中创建的具体的InputMapper的process函数。下面就看看SingleTouchInputMapper的process是如何处理的,其代码如下:

  1. void SingleTouchInputMapper::process(const RawEvent* rawEvent) {  
  2.     TouchInputMapper::process(rawEvent);  
  3.   
  4.     mSingleTouchMotionAccumulator.process(rawEvent);  
  5. }  

void SingleTouchInputMapper::process(const RawEvent* rawEvent) { TouchInputMapper::process(rawEvent); mSingleTouchMotionAccumulator.process(rawEvent); }

1)TouchInputMapper::process

       由此可见,它将首先调用TouchInputMaaper::process处理此事件,其处理代码如下:

  1. void TouchInputMapper::process(const RawEvent* rawEvent) {  
  2.     mCursorButtonAccumulator.process(rawEvent);  
  3.     mCursorScrollAccumulator.process(rawEvent);  
  4.     mTouchButtonAccumulator.process(rawEvent);  
  5.   
  6.     if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) {  
  7.         sync(rawEvent->when);  
  8.     }  
  9. }  

void TouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); mTouchButtonAccumulator.process(rawEvent); if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) { sync(rawEvent->when); } }


1.1) mCursorButtonAccumulator.process(rawEvent)

     记录mouse或touch pad按键状态,记录rawEvent->type为EV_KEY,且rawEvent->scanCode为BTN_LEFT、BTN_RIGHT、BTN_MIDDLE、BTN_BACK、BTN_SIDE、BTN_FORWARD、BTN_EXTRA、BTN_TASK的事件。

1.2) mCursorScrollAccumulator.process(rawEvent)

     记录cursor scrolling motions,记录rawEvent->type为EV_REL,且rawEvent->scanCode为REL_WHEEL、REL_HWHEEL的事件。

1.3) mTouchButtonAccumulator.process(rawEvent)

     记录touch, stylus and tool buttons状态,记录rawEvent->type为EV_KEY,且rawEvent->scanCode为BTN_TOUCH、BTN_STYLUS、BTN_STYLUS2、BTN_TOOL_FINGER、BTN_TOOL_PEN、BTN_TOOL_RUBBER、BTN_TOOL_BRUSH、BTN_TOOL_PENCIL、BTN_TOOL_AIRBRUSH、BTN_TOOL_MOUSE、BTN_TOOL_LENS、BTN_TOOL_DOUBLETAP、BTN_TOOL_TRIPLETAP、BTN_TOOL_QUADTAP的事件。

     看到了吧,我们的BTN_TOUCH在这儿被处理了,且其value被保存在mBtnTouch成员变量中。

1.4) sync(rawEvent->when)

      处理EV_SYN:SYN_REPORT,我们的EV_SYN就在这儿被处理了,当然它是Touch Down时,所发事件的最后一个事件。这儿才是处理的重点。

      TouchInputMapper::sync将调用SingleTouchInputMapper::syncTouch函数。

      a)SingleTouchInputMapper::syncTouch

      把mCurrentRawPointerData中的ABS_X和ABS_Y的值保存在TouchInputMapper::mCurrentRawPointerData->pointers中。

          单点触摸的syncTouch一次处理一个RawEvent,在pointers中只有一个值;而多点触摸的syncTouch一次处理多个RawEvent,在pointers中有多个值,最多16个。

      b)TouchInputMapper::cookPointerData

      根据TouchInputMapper::mCurrentRawPointerData->pointers中的数据,通过计算,最后生成TouchInputMapper::mCurrentCookedPointerData.pointerCoords,mCurrentCookedPointerData.pointerProperties和mCurrentCookedPointerData.idToIndex的数据。把Raw进行cook,之后生成了cooked数据。

      c)TouchInputMapper::dispatchHoverExit

 

      d)TouchInputMapper::dispatchTouches

      d.a)它调用dispatchMotion

      d.b)在dispatchMotion中,根据cooked数据创建NotifyMotionArg对象,它描述了一个移动事件

      d.c)调用TouchInputMapper::getListener()->notifyMotion(&args)

              TouchInputMapper::getListener()调用mContext->getListener(),此mContext为InputReader::mContext,所以其getListener()返回的则为InputReader::mQueuedListener,则最后调用QueuedInputListener::notifyMotion

       补充1) InputReader::mContext在构造时用自己的指针初始化了mContext,从而mContext::mReader则为此InputReader实例。
       补充2) 在InputReader::createDeviceLocked中创建InputDevice时,把自己的mContext作为参数传入,从而把它保存在InputDevice::mContext中;在创建InputMapper时,以InputDevice作为参数,且InputMapper把它保存在mDevice中,然后从把InputDevice中的mContext也保存在InputMapper的mContext中。

      d.d)把传递过来的NotifyMotionArg参数复制一份,然后加入QueuedInputListener::mArgsQueue例表中。

 

      e)TouchInputMapper::dispatchHoverEnterAndMove

          

         

 

2)mSingleTouchMotionAccumulator.process 


     记录ABS相关的值,记录rawEvent->type为EV_ABS,且rawEvent->scanCode为ABS_X、ABS_Y、ABS_PRESSURE、ABS_TOOL_WIDTH、ABS_DISTANCE、ABS_TILT_X、ABS_TILT_Y的事件。我们发的ABS_X和ABS_Y在这儿被处理了。

 

     事件处理相关数据结构如下图所示:     

 

 

4.3.1.2 InputReader::mQueuedListener->flush()

      先温习一下,至此的消息结构变化流程:

     

      processEventsLocked已经把来自于事件设备的事件煮熟之后放入到各种NotifyArgs(如NotifyMotionArgs)之中,然后把这些各种NotifyArgs加入InputReader::mQueuedListener::mArgsQueue链表中。本Flush函数就是要把mArgsQueue中的所有NotifyArgs进行处理。为描述方便,先看看其代码:

 

  1. void QueuedInputListener::flush() {  
  2.     size_t count = mArgsQueue.size();  
  3.     for (size_t i = 0; i < count; i++) {  
  4.         NotifyArgs* args = mArgsQueue[i];  
  5.         args->notify(mInnerListener);  
  6.         delete args;  
  7.     }  
  8.     mArgsQueue.clear();  
  9. }  

void QueuedInputListener::flush() { size_t count = mArgsQueue.size(); for (size_t i = 0; i < count; i++) { NotifyArgs* args = mArgsQueue[i]; args->notify(mInnerListener); delete args; } mArgsQueue.clear(); }


       看到了吧,确实很简单,调用链表中每个NotifyArgs的notify函数,且有一个有意思的参数 mInnerListener,这个参数在前面多次提到过,它是在创建mQueuedListener时提供的,它其实就是InputManager中的mDispatcher,前面一直在InputReader中打转转,现在终于看到InputDispatcher登场了,说明事件很快就可以谢幕了。

       再向下看一下吧,这么多类NotifyArgs,为描述方便,下面以NotifyMotionArgs为例,其代码为: 

  

  1. void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {  
  2.     listener->notifyMotion(this);  
  3. }  

void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const { listener->notifyMotion(this); }

      下面就看看InputDispatcher(mDispatcher)的notifyMotion函数做了些什么。这个InputDispatcher::notifyMotion(const NotifyMotionArgs* args)可就不简单了。

       在InputDispatcher::notifyMotion中,
       1)根据NotifyMotionArgs提供的信息,构造一个MotionEvent,再调用mPolicy->filterInputEvent看是否需要丢弃此事件,如果需要丢弃则马上返加。其中mPolicy为NativeInputManager实例,在构造InputDispatcher时提供的参数。

       2)对于AMOTION_EVENT_ACTION_UP或AMOTION_EVENT_ACTION_DOWN事件,则直接根据NotifyMotionArgs提供的信息,构造一个MotionEntry。

       3)调用InputDispatcher::enqueueInboundEventLocked把新构造的MotionEntry添加到InputDispatcher::mInboundQueue中,并返回是否需要唤醒mLooper<向pipe中写入数据>的标识。

      以上操作都是在InputReader线程中完成的,现在应该InputDispatcher线程开始工作了。

4. 4 分发输入事件

InputDispatcherThread主循环如下:

Thread::_threadLoop->

   InputDispatcherThread::threadLoop->

      mDispatcher->dispatchOnce(InputDispatcher::dispatchOnce)->

          dispatchOnceInnerLocked then

          mLooper->pollOnce

下面先看看简单的mLooper->pollOnce

 4.4.1 mLooper->pollOnce 

      其功能为等待超时或被pipe唤醒(InputReader线程调用InputDispatcher::notifyMotion时, InputDispatcher::notifyMotion根据情况调用mLooper->wake)。

      其调用流程如下:

      mLooper->pollOnce(int timeoutMillis)->

         Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData)->

4.4.2 dispatchOnceInnerLocked         

      1)从mInboundQueue从中依次取出EventEntry<MotionEntry的基类>

      2)调用InputDispatcher::dispatchMotionLocked处理此MotionEntry

      3)调用InputDispatcher::dispatchEventToCurrentInputTargetsLocked

            对于InputDispatcher::mCurrentInputTargets中的每一个InputTarget,并获取对应的Connection,调用InputDispatcher::prepareDispatchCycleLocked,

其相关代码如下:

 

  1.   <span style="font-size:10px;">  for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {  
  2.         const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);  
  3.   
  4.         ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);  
  5.         if (connectionIndex >= 0) {  
  6.             sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);  
  7.             prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,  
  8.                     resumeWithAppendedMotionSample);  
  9.         } else {  
  10. #if DEBUG_FOCUS   
  11.             LOGD("Dropping event delivery to target with channel '%s' because it "  
  12.                     "is no longer registered with the input dispatcher.",  
  13.                     inputTarget.inputChannel->getName().string());  
  14. #endif   
  15.         }  
  16.     }</span>  

<span style="font-size:10px;"> for (size_t i = 0; i < mCurrentInputTargets.size(); i++) { const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i); ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); if (connectionIndex >= 0) { sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex); prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget, resumeWithAppendedMotionSample); } else { #if DEBUG_FOCUS LOGD("Dropping event delivery to target with channel '%s' because it " "is no longer registered with the input dispatcher.", inputTarget.inputChannel->getName().string()); #endif } }</span>

      4)InputDispatcher::prepareDispatchCycleLocked

           4.1)调用enqueueDispatchEntryLocked创建DispatchEntry对象,并把它增加到Connection::outboundQueue队列中。

           4.2)调用activateConnectionLocked把当前Connection增加到InputDispatcher::mActiveConnections链表中

           4.3)调用InputDispatcher::startDispatchCycleLocked,接着它调用Connection::inputPublisher.publishMotionEvent来发布事件到ashmem buffer中,调用Connection::inputPublisher.sendDispatchSignal发送一个dispatch信号到InputConsumer通知它有一个新的消息到了,快来消费吧!  关于消费者如何注册和如何消息的流程在下一个专题中再写。本文到此结束!!!   

  评论这张
 
阅读(4845)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017