Linux/Android——Input系统之InputMapper 处理 (八)
前文Linux/Android——Input系统之InputReader (七)介绍到了inputreader的运作流程,如何获取events到初步的分发,依次分析到InputMapper做第一步的处理.
前文有解析Mapper类型的依赖规则,不做重述.,这里单以触摸屏input_device 对应的SingleTouchInputMapper 为例。
撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/43561773本博文来自【 jscese 】的博客!
SingleTouchInputMapper:
原型定义在InputReader.h 中:
class SingleTouchInputMapper : public TouchInputMapper {public: SingleTouchInputMapper(InputDevice* device); virtual ~SingleTouchInputMapper(); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent);protected: virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); virtual void configureRawPointerAxes(); virtual bool hasStylus() const;private: SingleTouchMotionAccumulator mSingleTouchMotionAccumulator;};
继承自TouchInputMapper,函数实现全部放在InputReader.cpp中,先看首先调用进的process:
void SingleTouchInputMapper::process(const RawEvent* rawEvent) { TouchInputMapper::process(rawEvent); //调用父类的process mSingleTouchMotionAccumulator.process(rawEvent); //数据的同步}
继续跟:
void TouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); mTouchButtonAccumulator.process(rawEvent); //这三个Accumulator 进一步处理rawEvent ,原型都在InputReader.cpp中,根据rawEvent->code 取出对应信息 ALOGW("jscese dsp TouchInputMapper::process event type==0x%x, code==0x%x, valude ==0x%x \n",rawEvent->type,rawEvent->code,rawEvent->value); if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { sync(rawEvent->when); //同步 }}
上面的几个process 有兴趣可以看下,会依次根据code type抽取对应的信息保存,比如CursorMotionAccumulator 中的 mRelX ,mRelY 代表相对坐标值
作为我调试的触摸框来说这里只在TouchButtonAccumulator中抽取了 BTN_TOUCH 一个按下或者抬起的事件值. ABS_X. ABS_Y 并没有在这里读取。而是在后面的SingleTouchMotionAccumulator::process中.
其它的input 设备就需要看驱动具体上报的code type了.
TouchInputMapper::sync:
从上面分析可以看到。一个rawEvent过来的时候 都会先经过三个process去抽取信息,然后才会检测是否是一个同步sync的rawEent事件,
这也就是为什么 在驱动中 一次完整的事件上报,总是先report一些button res abs之类的,最后来一个sync!
这个同步函数比较长只留意几个地方就可以了:
void TouchInputMapper::sync(nsecs_t when) { ALOGW("TouchInputMapper::sync"); // Sync button state. mCurrentButtonState = mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); // Sync scroll state.... // Sync touch state. bool havePointerIds = true; mCurrentRawPointerData.clear(); syncTouch(when, &havePointerIds);//调用子类的syncTouch,这里自然调用的是我 触摸框的 SingleTouchMotionAccumulator的syncTouch,更新ABS 坐标值,我这里是把数据存入到mCurrentRawPointerData中供下面cook... // Reset state that we will compute below. mCurrentFingerIdBits.clear(); mCurrentStylusIdBits.clear(); mCurrentMouseIdBits.clear(); mCurrentCookedPointerData.clear(); // 先清掉... // Cook pointer data. This call populates the mCurrentCookedPointerData structure // with cooked pointer data that has the same ids and indices as the raw data. // The following code can use either the raw or cooked data, as needed. cookPointerData(); //这个函数不跟进去了,太庞大,cook数据,主要是生成 mCurrentCookedPointerData.pointerCoords,mCurrentCookedPointerData.pointerProperties和mCurrentCookedPointerData.idToIndex... dispatchTouches(when, policyFlags); //又进行分发...//一些数据保存之类的操作}
这里正常的处理是调用dispatchTouches 函数 ,往里走是dispatchMotion:
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) { PointerCoords pointerCoords[MAX_POINTERS]; PointerProperties pointerProperties[MAX_POINTERS]; uint32_t pointerCount = 0;... getListener()->notifyMotion(&args); //回调}
这里是走的signeltouch的所以最终会调用getListener()->notifyMotion(&args),如果是Keydown事件。根据上面的逻辑会在cookPointerData 之前调用synthesizeButtonKeys 依次会调用到context->getListener()->notifyKey(&args);
QueuedInputListener:
上面分析到的notifyMotion最后会调用到这个类中,这个作为inputreader环节的最后交接维护类,回顾一下InputRead的构建,可以看下:
// --- InputReader ---InputReader::InputReader(const sp& eventHub, const sp& policy, const sp& listener) //这里注意最后一个参数~...{ mQueuedListener = new QueuedInputListener(listener); //构造了一个QueuedinputListener...}
这里又要看下最开始的构造调用了/frameworks/base/services/input/InputManager.cpp中:
InputManager::InputManager(... mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(eventHub, readerPolicy, mDispatcher); //可以看到这里传入的是InputDispatcher ,但是上面直接用的InputListenerInterface ,,直接强制转换成了 父类指针! 这里注意一下...}
所以在InputReader中构造QueuedInputListener的时候保存的是InputDispatcher的父类指针,保存在私有成员 mInnerListener
// --- QueuedInputListener ---QueuedInputListener::QueuedInputListener(const sp& innerListener) : mInnerListener(innerListener) {}
为什么这么做是应为 后续调用的纯虚函数。将会交由InputDispatcher 的函数来实现。实现了一个传递,C++ 就是这样,要整个看明白。才知道设计者写的代码到底跑到哪里去了~
往下分析流程就知道我为什么这么说了.
回到前面,调用 QueuedInputListener::notifyMotion,将这个notifyMotion push进mArgsQueue 链表队列,然后在 loopOnce() 中做完上述一次事件的获取以及分发处理之后将会调用 mQueuedListener->flush();
void QueuedInputListener::flush() { size_t count = mArgsQueue.size(); for (size_t i = 0; i < count; i++) { NotifyArgs* args = mArgsQueue[i]; args->notify(mInnerListener); //这里依次调用上面push进来的不同种类notify的notify函数,NotifyConfigurationChangedArgs / NotifyKeyArgs / NotifyMotionArgs / NotifySwitchArgs / NotifyDeviceResetArgs 这几种 delete args; } mArgsQueue.clear();}
这里还是单以我做的notifyMotion为例:
void NotifyMotionArgs::notify(const sp& listener) const { listener->notifyMotion(this);}
就是这里。又来了一个 notifyMotion调用,这个纯虚函数 ,两个子类QueuedInputListener InputDispatcher 中都有实现,就像上面分析到的,最终是调用到 InputDispatcher 中的notifyMotion !
之后就是InputDispatcher 的处理了,这里不继续。后续再说~
更多相关文章
- 箭头函数的基础使用
- Python技巧匿名函数、回调函数和高阶函数
- 浅析android通过jni控制service服务程序的简易流程
- Android(安卓)Wifi模块分析(三)
- Android中dispatchDraw分析
- Android四大基本组件介绍与生命周期
- Android(安卓)Service AIDL
- Android(安卓)bluetooth介绍(四): a2dp connect流程分析
- Android调用天气预报的WebService简单例子