接上文对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;
}
}
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的分析在下篇开始。