input事件获取到就该处理了。
case EventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent->when); break;
void InputReader::handleConfigurationChangedLocked(nsecs_t when) { // Reset global meta state because it depends on the list of all configured devices. updateGlobalMetaStateLocked(); // Enqueue configuration changed. NotifyConfigurationChangedArgs args(when); mQueuedListener->notifyConfigurationChanged(&args); }
void InputReader::updateGlobalMetaStateLocked() { mGlobalMetaState = 0; for (size_t i = 0; i < mDevices.size(); i++) { InputDevice* device = mDevices.valueAt(i); mGlobalMetaState |= device->getMetaState(); } }
int32_t InputDevice::getMetaState() { int32_t result = 0; size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; result |= mapper->getMetaState(); } return result; }mMappers[]是什么?
case EventHubInterface::DEVICE_ADDED: addDeviceLocked(rawEvent->when, rawEvent->deviceId); break;InputReader::addDeviceLocked()->createDeviceLocked()
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, const InputDeviceIdentifier& identifier, uint32_t classes) { InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), identifier, classes); // External devices. if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { device->setExternal(true); } // Switch-like devices. if (classes & INPUT_DEVICE_CLASS_SWITCH) { device->addMapper(new SwitchInputMapper(device)); } // Vibrator-like devices. if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { device->addMapper(new VibratorInputMapper(device)); } // Keyboard-like devices. uint32_t keyboardSource = 0; int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { keyboardSource |= AINPUT_SOURCE_KEYBOARD; } if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; } if (classes & INPUT_DEVICE_CLASS_DPAD) { keyboardSource |= AINPUT_SOURCE_DPAD; } if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { keyboardSource |= AINPUT_SOURCE_GAMEPAD; } if (keyboardSource != 0) { device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); } // Cursor-like devices. if (classes & INPUT_DEVICE_CLASS_CURSOR) { device->addMapper(new CursorInputMapper(device)); } // Touchscreens and touchpad devices. if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { device->addMapper(new MultiTouchInputMapper(device)); } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { device->addMapper(new SingleTouchInputMapper(device)); } // Joystick-like devices. if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { device->addMapper(new JoystickInputMapper(device)); } return device; }很明显是根据input device->classes来添加映射的。mMappers是一个<InputMapper*>类型的Vector,如果是INPUT_DEVICE_CLASS_SWITCH开关就添加一个device->addMapper(new SwitchInputMapper(device));如果是触摸屏或者触摸板:
// Touchscreens and touchpad devices. if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { device->addMapper(new MultiTouchInputMapper(device)); } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { device->addMapper(new SingleTouchInputMapper(device)); }每种InputMapper都有自己的init、reset、process函数。addDeviceLocked()之前我们用的device都是通用Device对象,通过createDeviceLocked()实现了Device到InputDevice的转变。看最后有个mDevices.add(deviceId, device)。好熟悉啊,openDeviceLocked()->addDeviceLocked(device)里也有mDevices.add(device->id, device),长得真像,这个是add通用Device,class EventHub的 mDevices是这个摸样的:
int32_t InputMapper::getMetaState() { return 0; }看来对于 INPUT_DEVICE_CLASS_TOUCH_MT,mGlobalMetaState一直为0。mMetaState是指什么状态?只有KeyboardInputMapper设置getMetaState()函数。
int32_t KeyboardInputMapper::getMetaState() { return mMetaState; }mMetaState是meta key的一些状态,如果此时是keyboard的话mGlobalMetaState就可能记录了一些按键的dow和up。
// Enqueue configuration changed. NotifyConfigurationChangedArgs args(when); mQueuedListener->notifyConfigurationChanged(&args); mQueuedListener是一个class QueuedInputListener的强指针。 void QueuedInputListener::notifyConfigurationChanged( const NotifyConfigurationChangedArgs* args) { mArgsQueue.push(new NotifyConfigurationChangedArgs(*args)); }mArgsQueue是class QueuedInputListener中的一个Vector。这样一push就把NotifyConfigurationChangedArgs类型的实例push到Vector mArgsQueue中。这种push就是在Vector 中创建一个NotifyConfigurationChangedArgs对象的副本;这样就实现了将NotifyConfigurationChangedArgs事件推送到InputReader的队列中等候处理。其实是push到InputDispatch中,为什么这样说呢?再看下:
InputManager::InputManager( const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(eventHub, readerPolicy, mDispatcher); initialize(); }
InputReader::InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, const sp<InputListenerInterface>& listener) : mContext(this), mEventHub(eventHub), mPolicy(policy), mGlobalMetaState(0), mGeneration(1), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), mConfigurationChangesToRefresh(0) { mQueuedListener = new QueuedInputListener(listener); { // acquire lock AutoMutex _l(mLock); refreshConfigurationLocked(0); updateGlobalMetaStateLocked(); } // release lock }InputReader的mQueuedListener就是用mDispatcher构建的,这就是InputReader和InputDispatch通信的方式,现在又event了,就要通知InputDispatch。
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++) { #if DEBUG_RAW_EVENTS ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld", rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, rawEvent->when); #endif if (mDropUntilNextSync) { if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { mDropUntilNextSync = false; #if DEBUG_RAW_EVENTS ALOGD("Recovered from input event buffer overrun."); #endif } else { #if DEBUG_RAW_EVENTS ALOGD("Dropped input event while waiting for next input sync."); #endif } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { ALOGI("Detected input event buffer overrun for device %s.", getName().string()); mDropUntilNextSync = true; reset(rawEvent->when); } else { for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->process(rawEvent); } } } }for循环依次处理count个rawEvents。
} else { for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->process(rawEvent); } }假设过我们的mapper多点上报的触摸屏,所以mapper是MultiTouchInputMapper。
void InputReader::requestRefreshConfiguration(uint32_t changes) { AutoMutex _l(mLock); if (changes) { bool needWake = !mConfigurationChangesToRefresh; mConfigurationChangesToRefresh |= changes; if (needWake) { mEventHub->wake(); } } }InputReader::loopOnce()一开始
if (changes) { mConfigurationChangesToRefresh = 0; timeoutMillis = 0; refreshConfigurationLocked(changes); }
void InputReader::refreshConfigurationLocked(uint32_t changes) { mPolicy->getReaderConfiguration(&mConfig); mEventHub->setExcludedDevices(mConfig.excludedDeviceNames); if (changes) { ALOGI("Reconfiguring input devices. changes=0x%08x", changes); nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) { mEventHub->requestReopenDevices(); } else { for (size_t i = 0; i < mDevices.size(); i++) { InputDevice* device = mDevices.valueAt(i); device->configure(now, &mConfig, changes); } } } }
void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { mSources = 0; if (!isIgnored()) { if (!changes) { // first time only mContext->getEventHub()->getConfiguration(mId, &mConfiguration); } if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { sp<KeyCharacterMap> keyboardLayout = mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier.descriptor); if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { bumpGeneration(); } } } if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) { if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { String8 alias = mContext->getPolicy()->getDeviceAlias(mIdentifier); if (mAlias != alias) { mAlias = alias; bumpGeneration(); } } } size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->configure(when, config, changes); mSources |= mapper->getSources(); } } }MultiTouchInputMapper没有实现config()函数,继承了爸爸的。
void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { InputMapper::configure(when, config, changes); mConfig = *config; if (!changes) { // first time only // Configure basic parameters. configureParameters(); // Configure common accumulators. mCursorScrollAccumulator.configure(getDevice()); mTouchButtonAccumulator.configure(getDevice()); // Configure absolute axis information. configureRawPointerAxes(); // Prepare input device calibration. parseCalibration(); resolveCalibration(); } if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { // Update pointer speed. mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters); mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); } bool resetNeeded = false; if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) { // Configure device sources, surface dimensions, orientation and // scaling factors. configureSurface(when, &resetNeeded); } if (changes && resetNeeded) { // Send reset, unless this is the first time the device has been configured, // in which case the reader will call reset itself after all mappers are ready. getDevice()->notifyReset(when); } }configureParameters()获取不可变的配置参数。
void MultiTouchInputMapper::configureRawPointerAxes() { TouchInputMapper::configureRawPointerAxes(); getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x); getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y); getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor); getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor); getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor); getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor); getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation); getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure); getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance); getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId); getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot); if (mRawPointerAxes.trackingId.valid && mRawPointerAxes.slot.valid && mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) { size_t slotCount = mRawPointerAxes.slot.maxValue + 1; if (slotCount > MAX_SLOTS) { ALOGW("MultiTouch Device %s reported %d slots but the framework " "only supports a maximum of %d slots at this time.", getDeviceName().string(), slotCount, MAX_SLOTS); slotCount = MAX_SLOTS; } mMultiTouchMotionAccumulator.configure(getDevice(), slotCount, true /*usingSlotsProtocol*/); } else { mMultiTouchMotionAccumulator.configure(getDevice(), MAX_POINTERS, false /*usingSlotsProtocol*/); } }前面一堆,设置一下code事件编码是哪些。
void MultiTouchMotionAccumulator::configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol) { mSlotCount = slotCount; mUsingSlotsProtocol = usingSlotsProtocol; mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE); delete[] mSlots; mSlots = new Slot[slotCount]; }mSlots是用来保存一个mt sync(SYN_MT_REPORT)或者mt slot(ABS_MT_SLOT)事件,对应一个点。mSlotCount说明一次最多能保存多少mt sync事件。对于type B mSlotCount最大值是32, mUsingSlotsProtocol = true。
if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN && mParameters.hasAssociatedDisplay) { mSource = AINPUT_SOURCE_TOUCHSCREEN; mDeviceMode = DEVICE_MODE_DIRECT; if (hasStylus()) { mSource |= AINPUT_SOURCE_STYLUS; } }(2) configureRawPointerAxes()中获取的mRawPointerAxes.x和mRawPointerAxes.y确定width and height。触摸屏需要显示,mParameters.hasAssociatedDisplay = true;而且不是外部设备。 mHWRotation表示旋转方向。如果touch分辨率的尺寸和显示的尺寸不一致,需要调整系数mXScale和mYScale。还有其他的参数调整,用到再说。
void MultiTouchInputMapper::process(const RawEvent* rawEvent) { TouchInputMapper::process(rawEvent); mMultiTouchMotionAccumulator.process(rawEvent); }
void TouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); mTouchButtonAccumulator.process(rawEvent); if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { sync(rawEvent->when); } }光标按钮作为设备键盘的处理,比如鼠标光标的左右中键、前进后退等等。
void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_ABS) { bool newSlot = false; /*addDeviceLocked()中device->reset(when)->mapper->reset(when)->MultiTouchInputMapper::reset()->mMultiTouchMotionAccumulator.reset(getDevice())->clearSlots(),无论A类、B类mCurrentSlot都为-1。 MultiTouchInputMapper::syncTouch()的最后mMultiTouchMotionAccumulator.finishSync()只是type A的mCurrentSlot设为-1,B的呢?if (mUsingSlotsProtocol) mCurrentSlot = rawEvent->value; */ if (mUsingSlotsProtocol) { if (rawEvent->code == ABS_MT_SLOT) { mCurrentSlot = rawEvent->value;//B类,是ID newSlot = true;//貌似只为了打印一个warnning } } else if (mCurrentSlot < 0) {//A类 mCurrentSlot = 0; } if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { #if DEBUG_POINTERS if (newSlot) { ALOGW("MultiTouch device emitted invalid slot index %d but it " "should be between 0 and %d; ignoring this slot.", mCurrentSlot, mSlotCount - 1); } #endif } else { Slot* slot = &mSlots[mCurrentSlot]; switch (rawEvent->code) { case ABS_MT_POSITION_X: slot->mInUse = true;//mInUse标志其所在的slot是否使用 slot->mAbsMTPositionX = rawEvent->value; break; case ABS_MT_POSITION_Y: slot->mInUse = true; slot->mAbsMTPositionY = rawEvent->value; break; case ABS_MT_TOUCH_MAJOR: slot->mInUse = true; slot->mAbsMTTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: slot->mInUse = true; slot->mAbsMTTouchMinor = rawEvent->value; slot->mHaveAbsMTTouchMinor = true; break; case ABS_MT_WIDTH_MAJOR: slot->mInUse = true; slot->mAbsMTWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: slot->mInUse = true; slot->mAbsMTWidthMinor = rawEvent->value; slot->mHaveAbsMTWidthMinor = true; break; case ABS_MT_ORIENTATION: slot->mInUse = true; slot->mAbsMTOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: if (mUsingSlotsProtocol && rawEvent->value < 0) { // The slot is no longer in use but it retains its previous contents, // which may be reused for subsequent touches. /*type B不会上报SYN_MT_REPORT,是以ID为负来判断抬起的,此时标记mInUse为 false,就是标记up了,有up说明之前是down的状态,如果不是down过的,那底层driver就出问题了,没有按下就抬起的事件能存在就有点奇迹了。我们虽然标记了up,但是并没有清除slot中的其他内容,这些内容可能会被重用,所以id为-1时,需要有sync事件发出来去处理这个up,不然以后再次按下的时候,这个up事件就消失了。这样一说按下的时候也要及时发sync处理,不然就被up覆盖了。所以底层每当有点按下或抬起都会上报sync事件*/ slot->mInUse = false; } else { slot->mInUse = true; slot->mAbsMTTrackingId = rawEvent->value; } break; case ABS_MT_PRESSURE: slot->mInUse = true; slot->mAbsMTPressure = rawEvent->value; break; case ABS_MT_DISTANCE: slot->mInUse = true; slot->mAbsMTDistance = rawEvent->value; break; case ABS_MT_TOOL_TYPE: slot->mInUse = true; slot->mAbsMTToolType = rawEvent->value; slot->mHaveAbsMTToolType = true; break; } } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { // MultiTouch Sync: The driver has returned all data for *one* of the pointers. mCurrentSlot += 1; /*对于type A只有收到mt sync的时候mCurrentSlot才加1,mt sync之前的code底层只会上报一次,上报多次就保留一次的,可见type A会把mt sync事件按照上报顺序存储在mSlots里。type B并不会上报SYN_MT_REPORT,mCurrentSlot = rawEvent->value,mCurrentSlot的取值就是上报ABS_MT_SLOT的ID,不一定顺序存储,是根据ID编号存储的,如果某个ID没有上报,对应的slot就空着。 */ } }如果事件不出意外,总会收到sync事件的。总能回到:
如果事件不出意外,总会收到sync事件的。总能回到: if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { sync(rawEvent->when); }它很长很长。
void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();//type B=32,type A=16 size_t outCount = 0; BitSet32 newPointerIdBits; for (size_t inIndex = 0; inIndex < inCount; inIndex++) { const MultiTouchMotionAccumulator::Slot* inSlot =//一个点 mMultiTouchMotionAccumulator.getSlot(inIndex); if (!inSlot->isInUse()) {//对应点已up continue; } if (outCount >= MAX_POINTERS) {//最大支持16点,但是type B的slot是32? #if DEBUG_POINTERS ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; " "ignoring the rest.", getDeviceName().string(), MAX_POINTERS); #endif break; // too many fingers! } RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount]; outPointer.x = inSlot->getX();//一个点的信息 outPointer.y = inSlot->getY(); outPointer.pressure = inSlot->getPressure(); outPointer.touchMajor = inSlot->getTouchMajor(); outPointer.touchMinor = inSlot->getTouchMinor(); outPointer.toolMajor = inSlot->getToolMajor(); outPointer.toolMinor = inSlot->getToolMinor(); outPointer.orientation = inSlot->getOrientation(); outPointer.distance = inSlot->getDistance(); outPointer.tiltX = 0; outPointer.tiltY = 0; outPointer.toolType = inSlot->getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = mTouchButtonAccumulator.getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; } } /*判断工具的,是手指或者笔。如果有上报ABS_MT_TOOL_TYPE,并且上报了合法的工具,那ok。否则mTouchButtonAccumulator.getToolType()来判断,判断不出来就是手指,默认的也是手指。 */ bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && (mTouchButtonAccumulator.isHovering() || (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0)); /*神奇的hover事件来了。hover是光标模仿悬停事件,移动到一个对象上以及移除这个对象。产生hover的条件: (1) 非AMOTION_EVENT_TOOL_TYPE_MOUSE工具; (2) 设置上报BTN_TOUCH,但上报的值mBtnTouch是0;或者上报了pressure,其值<=0。 */ outPointer.isHovering = isHovering; // Assign pointer id using tracking id if available. if (*outHavePointerIds) {//如果id有效,第一次为true int32_t trackingId = inSlot->getTrackingId(); int32_t id = -1; if (trackingId >= 0) {//上报id,有点按下的情况 for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { uint32_t n = idBits.clearFirstMarkedBit(); /*从idBits(idBits = mPointerIdBits)中找出第一个被标记的bit,并清除该bit,返回该bit的索引。如果所有bit都没有被标记,结果是未定义的;所以idBits.isEmpty()时for退出。*/ if (mPointerTrackingIdMap[n] == trackingId) { id = n; } /*mPointerIdBits表示点的标识符,如果mPointerTrackingIdMap[n]中有标记过trackingId的值,通过for循环能找到这个n,如果找不到id就为-1,就走下面的标记流程。 */ } if (id < 0 && !mPointerIdBits.isFull()) { id = mPointerIdBits.markFirstUnmarkedBit(); /*从mPointerIdBits中找出第一个未标记的bit,并标记该bit,返回该bit的索引。如果所有bit都被标记,结果是未定义的。mPointerIdBits.isFull()时,就没有地方标记了。 */ mPointerTrackingIdMap[id] = trackingId; } } /*mPointerIdBits的bit为1标记的是有一个点按下;32bit系统,可以标记32点。mPointerTrackingIdMap[]与mPointerIdBits对应,设置mPointerIdBits的第id(从0开始)个bit的同时,要设置mPointerTrackingIdMap[id] = trackingId。mPointerTrackingIdMap[id]的值存储的是点的ID,通过id可以找到ID。 */ if (id < 0) { /*不上报ID(只有type A会不上报)会走到这里一次,或者上报ID -1时也到这里,都会有清除动作。只要是type A总会设置*outHavePointerIds = false的。 (1) type A不上报ID的按下,在syncTouch()中hover、touch、pointer的标识符都是0,所以判断按下抬起的状态不在这个函数里。 (2) type A不上报ID的抬起,如果上报mt synch和sync之外还报了别的input event,slot->mInUse = true,会记录最后一次outPointer,只是坐标为0。还可能遗留一个hover,因为outPointer.isHovering = isHovering,如果条件满足最后的isHovering被设置,以后可用。 (3) type A上报id(抬起时为-1)的抬起,也会记录最后一次outPointer和保留isHovering状态。 (4) 上报id,typeB的抬起会设置slot->mInUse = false,不会走到这里,就不会记录最后一次outPointer,也不会将之前记录的hover、touch、pointer的标识符都清0。 */ *outHavePointerIds = false; mCurrentRawPointerData.clearIdBits();//清hover和touch表示符 newPointerIdBits.clear();//清点数表示符 } else { outPointer.id = id; /*此id表示mPointerIdBits的第id个bit,通过mPointerTrackingIdMap[id]可以找到点上报来的ID*/ mCurrentRawPointerData.idToIndex[id] = outCount;//标记点来的顺序 mCurrentRawPointerData.markIdBit(id, isHovering);//设hover或touch标识 newPointerIdBits.markBit(id);//设置点的标识 } } outCount += 1; } mCurrentRawPointerData.pointerCount = outCount;//总点数 mPointerIdBits = newPointerIdBits;//设置点的标识符 mMultiTouchMotionAccumulator.finishSync(); /*type A清slot,B不需要清,MultiTouchMotionAccumulator::process()中会处理*/ }syncTouch()执行后点的信息就存到了mCurrentRawPointerData中。
void TouchInputMapper::assignPointerIds() { uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; uint32_t lastPointerCount = mLastRawPointerData.pointerCount; mCurrentRawPointerData.clearIdBits();//清hover、touch标识bit,用自己的方法从新判断 if (currentPointerCount == 0) {//总点数为0 // No pointers to assign. return; } if (lastPointerCount == 0) {//上一点数为0,所有点都是新点 // All pointers are new. for (uint32_t i = 0; i < currentPointerCount; i++) { uint32_t id = i; mCurrentRawPointerData.pointers[i].id = id; /*type A是按点顺序存储的,type B的在上面,根据id能找到点的ID,这个不能*/ mCurrentRawPointerData.idToIndex[id] = i; mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(i)); /*标记一下touch或hover事件*/ } return; } if (currentPointerCount == 1 && lastPointerCount == 1 && mCurrentRawPointerData.pointers[0].toolType == mLastRawPointerData.pointers[0].toolType) { uint32_t id; if (!mCurrentRawPointerData.isHovering(0) && !mLastRawPointerData.hoveringIdBits.isEmpty()) { // 1 finger released and touching again. Should be safe to // reset to id 0. /*上一次产生了hover,那是一个上报了BTN或者pressure的up;现在没有hover了,说明有手指按下了,也是一个新点*/ id = 0; } else { // Only one pointer and no change in count so it must have the same id as before. //一直是一个点 id = mLastRawPointerData.pointers[0].id; } mCurrentRawPointerData.pointers[0].id = id; mCurrentRawPointerData.idToIndex[id] = 0; mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(0)); return; } // General case. // We build a heap of squared euclidean distances between current and last pointers // associated with the current and last pointer indices. Then, we find the best // match (by distance) for each current pointer. // The pointers must have the same tool type but it is possible for them to // transition from hovering to touching or vice-versa while retaining the same id. PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; /*通常情况 我们构造一个存储当前点和上一个点(与当前点和上一个点索引相关的)之间euclidean距离平方值的heap,我们就可以根据距离为当前点找到最好的匹配。 这些点必须使用同一种tool type,保持同一个id时,该tool可能使这些点从hovering转到touching,反之亦然。 */ uint32_t heapSize = 0; for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; currentPointerIndex++) { for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; lastPointerIndex++) { const RawPointerData::Pointer& currentPointer = mCurrentRawPointerData.pointers[currentPointerIndex]; const RawPointerData::Pointer& lastPointer = mLastRawPointerData.pointers[lastPointerIndex]; if (currentPointer.toolType == lastPointer.toolType) { int64_t deltaX = currentPointer.x - lastPointer.x; int64_t deltaY = currentPointer.y - lastPointer.y; uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); // Insert new element into the heap (sift up). heap[heapSize].currentPointerIndex = currentPointerIndex; heap[heapSize].lastPointerIndex = lastPointerIndex; heap[heapSize].distance = distance; heapSize += 1; } } } /*两次for循环结束后,heap中存储了每个当前点与上一次所有点的euclidean距离。 */ // Heapify for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) { startIndex -= 1; for (uint32_t parentIndex = startIndex; ;) { uint32_t childIndex = parentIndex * 2 + 1; if (childIndex >= heapSize) { break; } if (childIndex + 1 < heapSize && heap[childIndex + 1].distance < heap[childIndex].distance) { childIndex += 1; } if (heap[parentIndex].distance <= heap[childIndex].distance) { break; } swap(heap[parentIndex], heap[childIndex]); parentIndex = childIndex; } } /*这是个堆排序的过程,堆本身是一个二叉树,类似于 0 / \ 1 2 / \ / \ 3 4 5 6 / \ / \ 7 8 code中需要的是最小堆的性质,如果不满足就调整。从最后一个可以作为根的结点开始。例如heapSize 为9,先把heap[3]结点为根的分支,调整为最小堆;然后调整heap[2]结点为根的分支;最后调整以heap[0]结点为根的分支,就是整个树,先将heap[0]与heap[1]、heap[2]中值小的比较,如果heap[0]最小,那相安无事;如果heap[0]不最小,那就调整为最小堆;假设heap[0]与heap[2]swap了,那需要重新调整heap[2]的分支了。最后形成的树是根结点值最小,左右结点不确定。 */ #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize); for (size_t i = 0; i < heapSize; i++) { ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance); } #endif // Pull matches out by increasing order of distance. // To avoid reassigning pointers that have already been matched, the loop keeps track // of which last and current pointers have been matched using the matchedXXXBits variables. // It also tracks the used pointer id bits. /*按照距离增加的顺序取出匹配项。为了避免重新分配已经匹配的指针,循环保持跟踪表示上一个和当前点已经匹配的matchedXXXBits变量,还跟踪已经使用点id的对应bit位。 */ BitSet32 matchedLastBits(0); BitSet32 matchedCurrentBits(0); BitSet32 usedIdBits(0); bool first = true; for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) { while (heapSize > 0) { if (first) { // The first time through the loop, we just consume the root element of // the heap (the one with smallest distance). /*通过第一次循环,我们要消耗掉heap的根结点,因为这颗树中唯一可以判断大小的就是它,它是距离最小的一个结点。 */ first = false; } else { // Previous iterations consumed the root element of the heap. // Pop root element off of the heap (sift down). /*之前的迭代消耗了heap的根结点,弹出heap的根结点,进行sift down(向下筛选调整),每次取堆顶端的数,然后重新构造堆,如此迭代,直到所有的数据都取出。 */ heap[0] = heap[heapSize];//填充被取走后的heap[0] //重新构造堆 for (uint32_t parentIndex = 0; ;) { uint32_t childIndex = parentIndex * 2 + 1; if (childIndex >= heapSize) { break; } if (childIndex + 1 < heapSize && heap[childIndex + 1].distance < heap[childIndex].distance) { childIndex += 1; } if (heap[parentIndex].distance <= heap[childIndex].distance) { break; } swap(heap[parentIndex], heap[childIndex]); parentIndex = childIndex; } #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize); for (size_t i = 0; i < heapSize; i++) { ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance); } #endif } heapSize -= 1; /*每次都取堆顶的最小值*/ uint32_t currentPointerIndex = heap[0].currentPointerIndex; if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched uint32_t lastPointerIndex = heap[0].lastPointerIndex; if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched matchedCurrentBits.markBit(currentPointerIndex); matchedLastBits.markBit(lastPointerIndex); uint32_t id = mLastRawPointerData.pointers[lastPointerIndex].id; mCurrentRawPointerData.pointers[currentPointerIndex].id = id; /*last点和current点匹配上了,current点的ID就找到了*/ mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; /*idToIndex[id]里的值就是标记点来的顺序*/ mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(currentPointerIndex)); usedIdBits.markBit(id);//标记已经使用点id的对应bit位 #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld", lastPointerIndex, currentPointerIndex, id, heap[0].distance); #endif break; } } /*内存while就是控制sift down(向下筛选调整),每次取堆顶端的数,然后重新构造堆;外层for就是控制迭代次数,直到所有的数据都取出。 */ // Assign fresh ids to pointers that were not matched in the process. /*如果last点数多,那么至此所有点都匹配上了;但是如果last点少,current中还有未匹配的点呢,需要为这些新点分配一下ids */ for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) { uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); uint32_t id = usedIdBits.markFirstUnmarkedBit(); mCurrentRawPointerData.pointers[currentPointerIndex].id = id; mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(currentPointerIndex)); #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - assigned: cur=%d, id=%d", currentPointerIndex, id); #endif } }能进入这个函数,说明没有上报ID,是type A;如果上报ID,在syncTouch()中就把这些工作做了,就可以用上报的ID标识各个点了,很容易判断down和up。没有上报ID,就需要用一些算法来匹配当前点与上一点,从而找到软件上的id,最终判断出down和up。
mCurrentCookedPointerData.hoveringIdBits = mCurrentRawPointerData.hoveringIdBits; mCurrentCookedPointerData.touchingIdBits = mCurrentRawPointerData.touchingIdBits;7 分发
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits; BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits; int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mCurrentButtonState; if (currentIdBits == lastIdBits) { if (!currentIdBits.isEmpty()) { // No pointer id changes so this is a move event. // The listener takes care of batching moves so we don't have to deal with that here. /*没有指针id改变,所以这是一个移动事件。监视器负责批处理移动事件,我们不需要处理*/ dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.idToIndex, currentIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } else { // There may be pointers going up and pointers going down and pointers moving // all at the same time. BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value); BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value); BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); BitSet32 dispatchedIdBits(lastIdBits.value); // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. bool moveNeeded = updateMovedPointers( mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.idToIndex, mLastCookedPointerData.pointerProperties, mLastCookedPointerData.pointerCoords, mLastCookedPointerData.idToIndex, moveIdBits); if (buttonState != mLastButtonState) { moveNeeded = true; } // Dispatch pointer up events. while (!upIdBits.isEmpty()) { uint32_t upId = upIdBits.clearFirstMarkedBit(); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0, mLastCookedPointerData.pointerProperties, mLastCookedPointerData.pointerCoords, mLastCookedPointerData.idToIndex, dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); dispatchedIdBits.clearBit(upId); } // Dispatch move events if any of the remaining pointers moved from their old locations. // Although applications receive new locations as part of individual pointer up // events, they do not generally handle them except when presented in a move event. if (moveNeeded) { ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.idToIndex, dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } // Dispatch pointer down events using the new pointer locations. while (!downIdBits.isEmpty()) { uint32_t downId = downIdBits.clearFirstMarkedBit(); dispatchedIdBits.markBit(downId); if (dispatchedIdBits.count() == 1) { // First pointer is going down. Set down time. mDownTime = when; } dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.idToIndex, dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } }dispatchTouches()分出来move、down和up事件,调用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; while (!idBits.isEmpty()) { uint32_t id = idBits.clearFirstMarkedBit(); uint32_t index = idToIndex[id]; pointerProperties[pointerCount].copyFrom(properties[index]);//id信息 pointerCoords[pointerCount].copyFrom(coords[index]);//值信息 if (changedId >= 0 && id == uint32_t(changedId)) { action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } /*action中的bits代表一个down或者up的指针索引,我们把实际的指针索引就存在<< AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT的位置,后面用的时候>>AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT就取出了这个索引*/ pointerCount += 1; } ALOG_ASSERT(pointerCount != 0); if (changedId >= 0 && pointerCount == 1) { // Replace initial down and final up action. // We can compare the action without masking off the changed pointer index // because we know the index is 0. /*替换最初的down和最终的up。 我们可以比较没有屏蔽掉改变指针索引的action,因为我们知道index是0(id不一定是0)。 */ if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) { action = AMOTION_EVENT_ACTION_DOWN; } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { action = AMOTION_EVENT_ACTION_UP; } else { // Can't happen. ALOG_ASSERT(false); } } NotifyMotionArgs args(when, getDeviceId(), source, policyFlags, action, flags, metaState, buttonState, edgeFlags, mViewport.displayId, pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime); // resize touch coords for (dual_display && freescale_disabled) // rw.vout.scale: off/freescale_disabled, on/freescale_enabled char prop_dual[PROPERTY_VALUE_MAX]; if (!mPadmouseStatus && property_get("ro.vout.dualdisplay2", prop_dual, "false") && (strcmp(prop_dual, "true") == 0) && (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_MOVE)) { bool resize_touch = false; if (strncmp(g_dmode_str, "panel", 5) != 0) { char prop[PROPERTY_VALUE_MAX]; if (property_get("rw.vout.scale", prop, "on") && strcmp(prop, "off") == 0) { resize_touch = true; } } if (resize_touch) { int x = 0, y = 0, w = 0, h = 0; if(sscanf(g_daxis_str, "%d %d %d %d", &x,&y,&w,&h) > 0) { int ww = w, hh = h; if (strncmp(g_dmode_str, "1080p", 5) == 0) { ww = 1920; hh = 1080; } else if (strncmp(g_dmode_str, "720p", 4) == 0) { ww = 1280; hh = 720; } else if (strncmp(g_dmode_str, "480p", 4) == 0) { ww = 720; hh = 480; } if (ww >= w) x = (ww - w) / 2; if (hh >= h) y = (hh - h) / 2; for (uint32_t i = 0; i < args.pointerCount; i++) { float coords_x = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X); float coords_y = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y); if (ww >= w && hh >= h) { //1024*600 < 1280*720 coords_x = coords_x*(w + 2*x)/w; coords_y = coords_y*(h + 2*y)/h; coords_x = (coords_x - x)*(w + 2*x)/w; coords_y = (coords_y - y)*(h + 2*y)/h; coords_x = coords_x*w/(w + 2*x); coords_y = coords_y*h/(h + 2*y); } else if (ww >= w && hh < h) { //1024*768 > 1280*720 coords_x = coords_x*(w + 2*x)/w; coords_y = coords_y*hh/h; coords_x = (coords_x - x)*(w + 2*x)/w; coords_y = (coords_y - 0)*hh/h; coords_x = coords_x*w/(w + 2*x); coords_y = coords_y*h/hh; } else { //1024*600 > 720*480 coords_x = coords_x*ww/w; coords_y = coords_y*hh/h; coords_x = (coords_x - 0)*ww/w; coords_y = (coords_y - 0)*hh/h; coords_x = coords_x*w/ww; coords_y = coords_y*h/hh; } args.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, coords_x); args.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, coords_y); } } } } getListener()->notifyMotion(&args); //至此各event已经分发,并且通知inputDispatch。 }