接上文对EventHub getEvent()的分析,InputReader::loopOnce()在getEvent()成功返回直接,就调用process(& rawEvent);开始分析报上来的rawEvent:
void InputReader::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EventHubInterface::DEVICE_ADDED: // 加入新设备 addDevice(rawEvent->deviceId); break; case EventHubInterface::DEVICE_REMOVED: // 移除完成 removeDevice(rawEvent->deviceId); break; case EventHubInterface::FINISHED_DEVICE_SCAN: // 扫描完成,每次增加或移除设备后都会引发此事件 handleConfigurationChanged(rawEvent->when); break; default: consumeEvent(rawEvent); // 普通event,按键触摸屏事件就在这个分支上处理 break; } }
struct RawEvent { nsecs_t when; // when this happened int32_t deviceId; // from which device int32_t type; // DEVICE_REMOVED, DEVICE_ADDED, FINISHED_DEVICE_SCAN or others int32_t scanCode; // original event code from kernel driver int32_t keyCode; // code after keycode-mapping while this is a EV_KEY event int32_t value; // event value uint32_t flags; // additional info };
void InputReader::addDevice(int32_t deviceId) { String8 name = mEventHub->getDeviceName(deviceId); // eventHub根据自己的mDevicesById返回device的name和classes uint32_t classes = mEventHub->getDeviceClasses(deviceId); // 调用createDevice建立一个与底层input device一一对应的device InputDevice* device = createDevice(deviceId, name, classes); device->configure(); ... bool added = false; // 如果此device之前不存在,则加到名为mDevices的KeyedVector中 { // acquire device registry writer lock RWLock::AutoWLock _wl(mDeviceRegistryLock); ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex < 0) { mDevices.add(deviceId, device); added = true; } } // release device registry writer lock .... }createDevice()函数中先new InputDevice创建对象,然后根据device的classes调用device->addMapper加入mapper,这些mapper对后面分析的普通event的处理有重要的作用。device->configure()函数做一些配置工作,如果device有校准数据的话会调用getInputDeviceCalibration进行校准,还会调用上述mapper的configure函数配置mapper,不过mapper的这个函数一般直接置空,只有TouchInputMapper::configure()会针对触摸屏校准做些工作:
void InputDevice::configure() { if (! isIgnored()) { mContext->getPolicy()->getInputDeviceCalibration(mName, mCalibration); } mSources = 0; // 调用mapper的configure和getSources来设置device的mSource来标示种类,但是mapper本身又是根据devices的classes来选的,很绕…… size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->configure(); mSources |= mapper->getSources(); } }
DEVICE_REMOVED事件的处理:
void InputReader::removeDevice(int32_t deviceId) { bool removed = false; InputDevice* device = NULL; { // acquire device registry writer lock RWLock::AutoWLock _wl(mDeviceRegistryLock); // 最主要的是从mDevices中将其移除 ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { device = mDevices.valueAt(deviceIndex); mDevices.removeItemsAt(deviceIndex, 1); removed = true; } } // release device registry writer lock ... device->reset(); // reset会引发devices的mapper的reset() delete device; }
void InputReader::handleConfigurationChanged(nsecs_t when) { // Reset global meta state because it depends on the list of all configured devices. updateGlobalMetaState(); // Update input configuration.更新inputReader当前的设置 updateInputConfiguration(); // Enqueue configuration changed.通知dispatcher了 mDispatcher->notifyConfigurationChanged(when); }
普通输入事件的处理:
在函数consumeEvent中会根据rawEvent的deviceId从mDevices中选择上报事件的device然后调用device->process(rawEvent)来处理,device再调用自己mapper的process来处理,因此对于不同的mapper就有了不同的process具体实现。下面选择MultiTouchInputMapper的process函数分析:
void MultiTouchInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_ABS: { uint32_t pointerIndex = mAccumulator.pointerCount; Accumulator::Pointer* pointer = & mAccumulator.pointers[pointerIndex]; switch (rawEvent->scanCode) { case ABS_MT_POSITION_X: LOGE("-MT X-"); pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_X; pointer->absMTPositionX = rawEvent->value; break; case ABS_MT_POSITION_Y: LOGE("-MT Y-"); pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_Y; pointer->absMTPositionY = rawEvent->value; break; case ABS_MT_TOUCH_MAJOR: pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MAJOR; pointer->absMTTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MINOR; pointer->absMTTouchMinor = rawEvent->value; break; case ABS_MT_WIDTH_MAJOR: pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MAJOR; pointer->absMTWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MINOR; pointer->absMTWidthMinor = rawEvent->value; break; case ABS_MT_ORIENTATION: pointer->fields |= Accumulator::FIELD_ABS_MT_ORIENTATION; pointer->absMTOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: pointer->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID; pointer->absMTTrackingId = rawEvent->value; break; case ABS_MT_PRESSURE: pointer->fields |= Accumulator::FIELD_ABS_MT_PRESSURE; pointer->absMTPressure = rawEvent->value; break; } break; } case EV_SYN: switch (rawEvent->scanCode) { // 对于多点触摸来说,一次可以向dispatcher报1~10个pointer的数据(10点是android2.3的上限) case SYN_MT_REPORT: { // 一次SYN_MT_REPORT表示一个手指的触摸数据已经接收完毕,包括X,Y,PRESSURE等 // MultiTouch Sync: The driver has returned all data for *one* of the pointers. uint32_t pointerIndex = mAccumulator.pointerCount; LOGE("-ONE-"); if (mAccumulator.pointers[pointerIndex].fields) { if (pointerIndex == MAX_POINTERS) { LOGW("MultiTouch device driver returned more than maximum of %d pointers.", MAX_POINTERS); } else { pointerIndex += 1; mAccumulator.pointerCount = pointerIndex; } } mAccumulator.pointers[pointerIndex].clear(); break; } // 当多点的数据都齐全之后会收到SYN_REPORT事件,这时可以向dispatcher发送了 case SYN_REPORT: LOGE("-SYN MT-"); sync(rawEvent->when); break; } break; } }
void MultiTouchInputMapper::sync(nsecs_t when) { static const uint32_t REQUIRED_FIELDS = Accumulator::FIELD_ABS_MT_POSITION_X | Accumulator::FIELD_ABS_MT_POSITION_Y; uint32_t inCount = mAccumulator.pointerCount; uint32_t outCount = 0; bool havePointerIds = true; mCurrentTouch.clear(); for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) { const Accumulator::Pointer& inPointer = mAccumulator.pointers[inIndex]; uint32_t fields = inPointer.fields; if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) { // Some drivers send empty MT sync packets without X / Y to indicate a pointer up. // Drop this finger. continue; } PointerData& outPointer = mCurrentTouch.pointers[outCount]; outPointer.x = inPointer.absMTPositionX; outPointer.y = inPointer.absMTPositionY; if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) { if (inPointer.absMTPressure <= 0) { // Some devices send sync packets with X / Y but with a 0 pressure to indicate // a pointer going up. Drop this finger. continue; } outPointer.pressure = inPointer.absMTPressure; } else { // Default pressure to 0 if absent. outPointer.pressure = 0; } .... // 设置FIELD_ABS_MT_WIDTH_MAJOR等等field // Assign pointer id using tracking id if available. if (havePointerIds) { if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) { uint32_t id = uint32_t(inPointer.absMTTrackingId); if (id > MAX_POINTER_ID) { // 利用id来跟踪多个手指的触摸事件 havePointerIds = false; } else { outPointer.id = id; mCurrentTouch.idToIndex[id] = outCount; mCurrentTouch.idBits.markBit(id); } } else { havePointerIds = false; } } outCount += 1; } mCurrentTouch.pointerCount = outCount; syncTouch(when, havePointerIds); mAccumulator.clear(); }贴一段kernel的触摸屏driver上报事件的代码:
for (i = 0; i < 10; i++){ if (stored_size[i]){ active_touches++; input_report_abs(mxt->input, ABS_MT_TRACKING_ID, i); input_report_abs(mxt->input, ABS_MT_TOUCH_MAJOR, stored_size[i]); input_report_abs(mxt->input, ABS_MT_POSITION_X, stored_x[i]); input_report_abs(mxt->input, ABS_MT_POSITION_Y, stored_y[i]); input_mt_sync(mxt->input); } } if (active_touches == 0) input_mt_sync(mxt->input); input_sync(mxt->input);可以看到,这个触摸屏也是最多支持10点触摸的,其中的ABS_MT_TRACKING_ID就是追踪每个手指的移动轨迹标示,具体哪个点属于哪个手指的轨迹则是由电容屏的IC确定的,怪不得电容屏成本比较高。经过sync函数的处理后,mCurrentTouch里面就带有整个多点触摸事件的所有数据,可以调用基类TouchInputMapper的syncTouch了:
void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { uint32_t policyFlags = 0; // Preprocess pointer data. if (mParameters.useBadTouchFilter) { if (applyBadTouchFilter()) { havePointerIds = false; } } if (mParameters.useJumpyTouchFilter) { if (applyJumpyTouchFilter()) { havePointerIds = false; } } if (! havePointerIds) { calculatePointerIds(); } TouchData temp; TouchData* savedTouch; if (mParameters.useAveragingTouchFilter) { temp.copyFrom(mCurrentTouch); savedTouch = & temp; applyAveragingTouchFilter(); } else { savedTouch = & mCurrentTouch; } // Process touches and virtual keys. TouchResult touchResult = consumeOffScreenTouches(when, policyFlags); if (touchResult == DISPATCH_TOUCH) { detectGestures(when); dispatchTouches(when, policyFlags); } // Copy current touch to last touch in preparation for the next cycle. if (touchResult == DROP_STROKE) { mLastTouch.clear(); } else { mLastTouch.copyFrom(*savedTouch); } }在syncTouch里,多点触摸的数据(单点触摸事件也会经过这里)还得通过applyBadTouchFilter,applyJumpyTouchFilter,applyAveragingTouchFilter(视情况)的处理才能到consumeOffScreenTouches这步,这个函数中在处理完一些policy的东西之后就会调
getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
通知dispatcher有事件来了,dispatcher的分析在下篇开始。