android input system(frameworks) analysis -- InputManager (2)

接上文对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;
    }
}

rawEvent的type对应着getEvent里面上报的几种类型,下面根据不同的分支看看inputReader如何处理这样事件。先看看一些关键数据结构:

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
};

DEVICE_ADD事件的处理:

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;
}

FINISHED_DEVICE_SCAN事件的处理:

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;
    }
}


MultiTouchInputMapper::sync的主要作用是,把process中接收到的多个pointer数据做审核,例如屏蔽掉不合要求的点,对缺失的参数设置成默认等。

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的分析在下篇开始。

你可能感兴趣的:(android,report,System,input,frameworks,Pointers)