基于android-10.0.0_r47版本分析
上一篇讲到Touch类型事件的加工处理其实就是收集所有描述点击动作的原始输入事件所包含的各种新信息,并在EV_SYN类型事件到来时,将这些信息进行整合,在进行一些处理之后,交付给InputDispatcher进行分发
一、原始事件的加工
(一) 事件收集
// frameworks/native/services/inputflinger/InputReader.cpp
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
// 调用基类的process()。基类的process()主要处理EV_SYN事件并进行时间信息整合
TouchInputMapper::process(rawEvent);
// 进行事件收集
mMultiTouchMotionAccumulator.process(rawEvent);
}
这个主要是两个函数,分别做EV_SYNC同步消息上报和EV_ABS的事件收集整理
事件信息的收集工作由MultiTouchMotionAccumalator类的process()完成。
在多点触控的信息收集工作中,需要识别信息所属的触控点索引。如何识别触控点的索引有两种方式:
- 基于
Slot协议的显示识别方式 - 基于时间顺序的隐式识别方式
1. 基于Slot协议的显示识别方式
参考以下代码:
// frameworks/native/services/inputflinger/InputReader.cpp
void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
// ①点击原始输入事件的类型为EV_ABS
if (rawEvent->type == EV_ABS) {
bool newSlot = false;
if (mUsingSlotsProtocol) {
if (rawEvent->code == ABS_MT_SLOT) {
// ②代码为ABS_MT_SLOT的事件指明后续事件对应的触控点的索引
mCurrentSlot = rawEvent->value;
newSlot = true;
}
}
if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
// mCurrentClot越界,打印警告信息
} else {
// ③根据触控点的索引获取一个Slot对象。随后所收集的信息将放置在这个Slot对象中
Slot* slot = &mSlots[mCurrentSlot];
// ④提取事件中携带的信息,并存储在触控点所对应的SLot对象中
switch (rawEvent->code) {
case ABS_MT_POSITION_X:
// 设置mInUse为true表示这个slot中包含有效的信息
slot->mInUse = true;
// 将信息保存在Slot相应的字段里
slot->mAbsMTPositionX = rawEvent->value;
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;
}
}
MultiTouchMotionAccumulator保存了一个名为mSlots的Slot对象数组。Slot对象是收集特定触控点的 点击信息的场所,而其在数组中的索引就是触控点的Id。从这段代码中可以看到,当输入设备开始上报某一个触 控点的信息时,首先会发送一条类型为EV_ABS,代码为ABS_MT_SLOT的事件(后面以类型+代码的方式称呼这类事件),这个事件的值表明随后携带点击信息的事件属于哪一个触控点。携带信息的事件到来时,其事件代码指明了它所携带的信息类型,MultiTouchMotionAccumulator从mSlots数组中以触控点的id为索引将对应的Slot对象取出,并将信息值保存在Slot的对应字段中。 随着携带信息的事件不断到来,Slot对象中的信息也渐渐丰满起来。当设备将这个触控点的点击信息全部上报完毕后,会发送一个EV_SYN+SYN _ REPORT 事件启动TouchInputMapper的信息整合与加工工作 ,或者发送另一个事件代码为ABS_ MT _SLOT的事件,开始上报另一个触控点的信息。
由此可见,携带点击信息的原始输入事件的格式如下:
- Type,取值为
EV_ABS,表明属于点击事件 - Code,取值为
ABS_MT_XXX,其中的XXX表明了信息的类型 - Value,信息的值
而在一个点击信息收集过程中所收到的原始输入事件序列如下所示:
EV_ABS ABS_MT_SLOT 触控点1
EV_ABS 信息1 信息1的值
EV_ABS 信息2 信息2的值
EV_ABS ABS_MT_SLOT 触控点2
... // 触控点2的信息以及更多的触控点
EV_SYN SYN_REPORT
因此整个点击事件信息的收集过程从指定触控点的事件开始,以一条EV_SYN + SYN_REPORT事件结束。在这个过程后,MultiTouchMotionAccumulator便在mSlots数组中保存了一个或多个触控点的点击信息
2. 基于时间顺序的隐式识别方式
在这个方式下,代表触控点信息的事件组由EV_SYN + SYN_MT_REPORT的事件分隔。分割的第一批事件携带的信息被认为属于0号索引点的触控点,随后事件组所属的触控点索引依次增加1。最后,使用EV_SYN + SYN_REPORT事件通知开始进行信息的整个工作。以这种方式的原始输入事件序列如下:
EV_ABS 信息1 信息1的值 // 0号触控点的信息
EV_ABS 信息2 信息2的值
EV_SYN SYN_MT_REPORT
... // 1号触控点的信息
EV_SYN SYN_MT_REPORT
EV_ABS 信息1 信息1的值
EV_SYN SYN_MT_REPORT // 2号触控点的信息
(二) 点击事件信息的整合、变换与高级事件的生成
前面所述,时间信息的整合加工工作由EV_SYN + SYN_REPORT触发。这段代码在TouchInputMapper的process()中:
// frameworks/native/services/inputflinger/InputReader.cpp
void TouchInputMapper::process(const RawEvent* rawEvent) {
...
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
...
sync(rawEvent->when);
}
}
sync()中只看与触摸事件相关的代码:
// frameworks/native/services/inputflinger/InputReader.cpp
void TouchInputMapper::sync(nsecs_t when) {
const RawState* last = mRawStatesPending.empty() ?
&mCurrentRawState : &mRawStatesPending.back();
// Push a new state.向容器末尾添加一个新的元素进去
mRawStatesPending.emplace_back();
// 返回的的是最后一个元素的引用
RawState* next = &mRawStatesPending.back();
next->clear();
next->when = when;
// Sync button state.
next->buttonState = mTouchButtonAccumulator.getButtonState()
| mCursorButtonAccumulator.getButtonState();
// Sync scroll
next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
mCursorScrollAccumulator.finishSync();
// Sync touch
syncTouch(when, next);
// Assign pointer ids.
if (!mHavePointerIds) {
assignPointerIds(last, next);
}
processRawTouches(false /*timeout*/);
}
这里需要重点关注syncTouch()和processRawTouches()方法
1. syncTouch()
// frameworks/native/services/inputflinger/InputReader.cpp
void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
size_t outCount = 0;
BitSet32 newPointerIdBits;
mHavePointerIds = true;
// inCount是前面配置的MAX_POINTERS 16个,把slot一个个取出来查看是否在使用
for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
const MultiTouchMotionAccumulator::Slot* inSlot =
mMultiTouchMotionAccumulator.getSlot(inIndex);
if (!inSlot->isInUse()) {
continue;
}
// 构建新对象,并将之前上报的配置信息同步过去
RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];
outPointer.x = inSlot->getX();
outPointer.y = inSlot->getY();
...
// Assign pointer id using tracking id if available.
if (mHavePointerIds) {
...
}
}
outState->deviceTimestamp = mMultiTouchMotionAccumulator.getDeviceTimestamp();
outState->rawPointerData.pointerCount = outCount;
mPointerIdBits = newPointerIdBits;
mMultiTouchMotionAccumulator.finishSync();
}
前面对判断异常,把Slot取出来,构建RawPointerData::Pointer对象,把Slot之前赋的值同步给该对象,进入mHavePointerIds之后的操作需要解释一下,我们从一个APP重写它的onTouchEvent,做了以下步骤,打印出日志
- 依次按屏幕1,2,3个手指
- 松开1手指
- 按上1手指
- 三个手指依次松开
2023-12-30 22:47:28.555 5016-5016 MainActivity test D wylin: MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=356.0, y[0]=1530.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=886677, downTime=886677, deviceId=7, source=0x1002 }
2023-12-30 22:47:28.794 5016-5016 MainActivity test D wylin: MotionEvent { action=ACTION_POINTER_DOWN(1), actionButton=0, id[0]=0, x[0]=356.0, y[0]=1530.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=521.0, y[1]=1301.0, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=886919, downTime=886677, deviceId=7, source=0x1002 }
2023-12-30 22:47:29.148 5016-5016 MainActivity test D wylin: MotionEvent { action=ACTION_POINTER_DOWN(2), actionButton=0, id[0]=0, x[0]=358.0, y[0]=1526.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=521.0, y[1]=1299.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=802.0, y[2]=1166.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=887267, downTime=886677, deviceId=7, source=0x1002 }
2023-12-30 22:47:29.156 5016-5016 MainActivity test D wylin: MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=358.0, y[0]=1524.5432, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=521.4568, y[1]=1297.5432, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=802.0, y[2]=1166.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=1, eventTime=887279, downTime=886677, deviceId=7, source=0x1002 }
2023-12-30 22:47:30.096 5016-5016 MainActivity test D wylin: MotionEvent { action=ACTION_POINTER_UP(0), actionButton=0, id[0]=0, x[0]=359.0, y[0]=1509.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=530.0, y[1]=1287.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=807.0, y[2]=1154.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=888225, downTime=886677, deviceId=7, source=0x1002 }
2023-12-30 22:47:30.105 5016-5016 MainActivity test D wylin: MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=1, x[0]=530.0, y[0]=1287.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=2, x[1]=807.0, y[1]=1154.0, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=888225, downTime=886677, deviceId=7, source=0x1002 }
2023-12-30 22:47:30.477 5016-5016 MainActivity test D wylin: MotionEvent { action=ACTION_POINTER_DOWN(0), actionButton=0, id[0]=0, x[0]=319.0, y[0]=1493.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=546.0, y[1]=1283.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=808.0, y[2]=1153.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=888600, downTime=886677, deviceId=7, source=0x1002 }
2023-12-30 22:47:30.523 5016-5016 MainActivity test D wylin: MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=319.0, y[0]=1493.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=546.0, y[1]=1283.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=808.0, y[2]=1152.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=888634, downTime=886677, deviceId=7, source=0x1002 }
2023-12-30 22:47:31.181 5016-5016 MainActivity test D wylin: MotionEvent { action=ACTION_POINTER_UP(2), actionButton=0, id[0]=0, x[0]=319.0, y[0]=1493.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=546.0, y[1]=1283.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=808.0, y[2]=1149.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=889308, downTime=886677, deviceId=7, source=0x1002 }
2023-12-30 22:47:31.187 5016-5016 MainActivity test D wylin: MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=319.0, y[0]=1493.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=546.0, y[1]=1283.0, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=889308, downTime=886677, deviceId=7, source=0x1002 }
2023-12-30 22:47:31.190 5016-5016 MainActivity test D wylin: MotionEvent { action=ACTION_POINTER_UP(0), actionButton=0, id[0]=0, x[0]=319.0, y[0]=1493.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=546.0, y[1]=1283.0, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=889316, downTime=886677, deviceId=7, source=0x1002 }
2023-12-30 22:47:31.192 5016-5016 MainActivity test D wylin: MotionEvent { action=ACTION_UP, actionButton=0, id[0]=1, x[0]=546.0, y[0]=1283.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=889316, downTime=886677, deviceId=7, source=0x1002 }
可以看到ACTION_DOWN,ACTION_POINTER_DOWN(1),ACTION_POINTER_DOWN(2)是三个手指依次放上去的事件,它的id的index也在依次增加,三个操作完有id数组里已经有3个了
再观察ACTION_POINTER_UP(0),当时松开了第一个按下的手指,之后的id数组的index为0的对应的是id 1,说明index和id不一定相等,当手指按住松开的时候,id和index发生变化,这就是下面这段代码的处理
// frameworks/native/services/inputflinger/InputReader.cpp
if (mHavePointerIds) {
int32_t trackingId = inSlot->getTrackingId();
int32_t id = -1;
if (trackingId >= 0) {
// 第一次idBits应该是空的,跳过该循环
for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
uint32_t n = idBits.clearFirstMarkedBit();
// 如果是trakingId和之前保存的手指id一样,说明是同一个手指
if (mPointerTrackingIdMap[n] == trackingId) {
id = n;
}
}
if (id < 0 && !mPointerIdBits.isFull()) {
id = mPointerIdBits.markFirstUnmarkedBit();
mPointerTrackingIdMap[id] = trackingId;
}
}
if (id < 0) {
mHavePointerIds = false;
outState->rawPointerData.clearIdBits();
newPointerIdBits.clear();
} else {
// 这里就是log里的id[0]
outPointer.id = id;
// index
outState->rawPointerData.idToIndex[id] = outCount;
outState->rawPointerData.markIdBit(id, isHovering);
newPointerIdBits.markBit(id);
}
}
outCount += 1;
2. processRawTouches()
这里主要是在cookPointerData()中进行加工
// frameworks/native/services/inputflinger/InputReader.cpp
void TouchInputMapper::cookAndDispatch(nsecs_t when) {
// Always start with a clean state.
mCurrentCookedState.clear();
// Apply stylus buttons to current raw state.
applyExternalStylusButtonState(when);
// Handle policy on initial down or hover events. 判断是否上一次新按下
bool initialDown = mLastRawState.rawPointerData.pointerCount == 0
&& mCurrentRawState.rawPointerData.pointerCount != 0;
uint32_t policyFlags = 0;
bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;
if (initialDown || buttonsPressed) {
// If this is a touch screen, hide the pointer on an initial down.
if (mDeviceMode == DEVICE_MODE_DIRECT) {
getContext()->fadePointer();
}
if (mParameters.wake) {
policyFlags |= POLICY_FLAG_WAKE;
}
}
// Consume raw off-screen touches before cooking pointer data.
// If touches are consumed, subsequent code will not receive any pointer data.
if (consumeRawTouches(when, policyFlags)) {
mCurrentRawState.rawPointerData.clear();
}
// Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData 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();
// ...
}
再看cookPointerData()
// frameworks/native/services/inputflinger/InputReader.cpp
void TouchInputMapper::cookPointerData() {
uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;
mCurrentCookedState.cookedPointerData.clear();
mCurrentCookedState.deviceTimestamp =
mCurrentRawState.deviceTimestamp;
mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount;
mCurrentCookedState.cookedPointerData.hoveringIdBits =
mCurrentRawState.rawPointerData.hoveringIdBits;
mCurrentCookedState.cookedPointerData.touchingIdBits =
mCurrentRawState.rawPointerData.touchingIdBits;
if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
mCurrentCookedState.buttonState = 0;
} else {
mCurrentCookedState.buttonState = mCurrentRawState.buttonState;
}
// Walk through the the active pointers and map device coordinates onto
// surface coordinates and adjust for display orientation.
for (uint32_t i = 0; i < currentPointerCount; i++) {
const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];
// Size触摸区域大小校准,不太需要关注
// Size
float touchMajor, touchMinor, toolMajor, toolMinor, size;
switch (mCalibration.sizeCalibration) {
// ...
// Pressure
float pressure;
switch (mCalibration.pressureCalibration) {
// ...
// Tilt and Orientation 倾斜和旋转
float tilt;
float orientation;
if (mHaveTilt) {
float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale;
float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale;
orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle));
tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle));
} else {
tilt = 0;
switch (mCalibration.orientationCalibration) {
// ...
}
// Distance 距离校准
float distance;
switch (mCalibration.distanceCalibration) {
// ...
// Coverage 覆盖面校准
int32_t rawLeft, rawTop, rawRight, rawBottom;
switch (mCalibration.coverageCalibration) {
// ...
// Adjust X,Y coords for device calibration
// int32_t 的x,y转换成float 类似100->100.00
float xTransformed = in.x, yTransformed = in.y;
mAffineTransform.applyTo(xTransformed, yTransformed);
// Adjust X, Y, and coverage coords for surface orientation.
float x, y;
float left, top, right, bottom;
// 计算旋转方向
switch (mSurfaceOrientation) {
case DISPLAY_ORIENTATION_90:
x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;
left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
orientation -= M_PI_2;
if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) {
orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
}
break;
case DISPLAY_ORIENTATION_180:
x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale;
y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;
left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
orientation -= M_PI;
if (mOrientedRanges.haveOrientation && orientation < mOrientedRanges.orientation.min) {
orientation += (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
}
break;
case DISPLAY_ORIENTATION_270:
x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale;
y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
orientation += M_PI_2;
if (mOrientedRanges.haveOrientation && orientation > mOrientedRanges.orientation.max) {
orientation -= (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
}
break;
default:
x = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
y = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
break;
}
// Write output coords.
PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i];
out.clear();
out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);
out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);
out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor);
out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt);
out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance);
if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) {
out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left);
out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top);
out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right);
out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom);
} else {
out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);
out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
}
// Write output properties.
PointerProperties& properties =
mCurrentCookedState.cookedPointerData.pointerProperties[i];
uint32_t id = in.id;
properties.clear();
properties.id = id;
properties.toolType = in.toolType;
// Write id index.
mCurrentCookedState.cookedPointerData.idToIndex[id] = i;
}
}
这里前面主要做了
- 触摸区域,倾斜和旋转,距离,覆盖面进行了校准
- 根据旋转方向计算x,y坐标及上下左右,因为触摸屏画面有可能被用户调整,可能调屏幕密度什么的,所以这里做转换
- 将校准信息和转换后的信息输出给
PointerCoords
退出cookPointerData函数,再看cookAndDispatch函数的其余内容,cook完应该就是Dispatch了
// frameworks/native/services/inputflinger/InputReader.cpp
void TouchInputMapper::cookAndDispatch(nsecs_t when) {
// ...
cookPointerData();
// ...
// Dispatch the touches either directly or by translation through a pointer on screen.
if (mDeviceMode == DEVICE_MODE_POINTER) {
// ...
} else {
// 正常是这种触摸屏模式 mConfig.showTouches这种是开发者模式开启的触摸圆点
if (mDeviceMode == DEVICE_MODE_DIRECT
&& mConfig.showTouches && mPointerController != nullptr) {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
mPointerController->setButtonState(mCurrentRawState.buttonState);
mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
mCurrentCookedState.cookedPointerData.touchingIdBits,
mViewport.displayId);
}
if (!mCurrentMotionAborted) {
dispatchButtonRelease(when, policyFlags);
dispatchHoverExit(when, policyFlags);
// 分发触摸事件
dispatchTouches(when, policyFlags);
dispatchHoverEnterAndMove(when, policyFlags);
dispatchButtonPress(when, policyFlags);
}
// ...
}
}
有关PointerController的就是开发者模式的触摸圆点,正常不会开启。前面一直说的是触摸点的信息,但是没讨论到ACTION_DOWN,MOVE,UP之类的,所以就由dispatchTouches开始分发触摸事件
// frameworks/native/services/inputflinger/InputReader.cpp
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
// 确认你的触摸ACTION是什么,跟你的上一步有直接的关系,所以把上一次的也取出来
BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits;
int32_t metaState = getContext()->getGlobalMetaState();
int32_t buttonState = mCurrentCookedState.buttonState;
// MOVE
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.
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.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.
// 抬起的触点集合,比如做个抬起事件,3个手指松开一个,last是三个,current是两个
// 1110 0000 0000 0000 0000 0000 0000 0000 last
// 0110 0000 0000 0000 0000 0000 0000 0000 current
// 1001 1111 1111 1111 1111 1111 1111 1111 ~current
// 1000 0000 0000 0000 0000 0000 0000 0000 last & current 取出up的点
BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
// 如果是三个手指再按下第四个
// 1110 0000 0000 0000 0000 0000 0000 0000 last
// 1111 0000 0000 0000 0000 0000 0000 0000 current
// 0001 1111 1111 1111 1111 1111 1111 1111 ~last
// 0001 0000 0000 0000 0000 0000 0000 0000 current & ~last
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(
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
mLastCookedState.cookedPointerData.pointerProperties,
mLastCookedState.cookedPointerData.pointerCoords,
mLastCookedState.cookedPointerData.idToIndex,
moveIdBits);
if (buttonState != mLastCookedState.buttonState) {
moveNeeded = true;
}
// Dispatch pointer up events.
while (!upIdBits.isEmpty()) {
uint32_t upId = upIdBits.clearFirstMarkedBit();
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0,
mCurrentCookedState.deviceTimestamp,
mLastCookedState.cookedPointerData.pointerProperties,
mLastCookedState.cookedPointerData.pointerCoords,
mLastCookedState.cookedPointerData.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 && !moveIdBits.isEmpty()) {
ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0,
mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.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, 0, metaState, buttonState, 0,
mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
}
}
这里就是取出上一次和这一次的触点信息进行比较,判断他们是什么行为,计算把事件保存到BitSet32类型的upIdBits,downIdBIts,moveIdBits,dispatchedIdBits中,后面根据这些行为,都通过dispatchMotion 来进行后续的处理
终于到dispatchMotion了,有要分发出去的迹象了,
// frameworks/native/services/inputflinger/InputReader.cpp
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t actionButton, int32_t flags,
int32_t metaState, int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp,
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]);
pointerCoords[pointerCount].copyFrom(coords[index]);
if (changedId >= 0 && id == uint32_t(changedId)) {
// log中action=ACTION_DOWN 第一个手指
// action=ACTION_POINTER_DOWN(1) 第二个手指
// action=AcTION_POINTER_DOWN(2) 第三个手指
// 的处理
action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
pointerCount += 1;
}
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.
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);
}
}
const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE);
const int32_t deviceId = getDeviceId();
...
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId,
source, displayId, policyFlags,
action, actionButton, flags, metaState, buttonState, MotionClassification::NONE,
edgeFlags, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime, std::move(frames));
getListener()->notifyMotion(&args);
}
对传过来的事件处理action,再新构建对象NotifyMotionArgs,通过getListenter()的notifyMotion来进行通知,先来看一下getListener是什么
// frameworks/native/services/inputflinger/InputReader.cpp
InputListenerInterface* InputReader::ContextImpl::getListener() {
return mReader->mQueuedListener.get();
}
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mNextSequenceNum(1), mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
{
// ...
}
}
// frameworks/native/services/inputflinger/InputReader.h
sp<QueuedInputListener> mQueuedListener;
可以看到listener是InputReader的构造方法传递进来的,listener是实现InputListenerInterface的智能指针
// frameworks/native/services/inputflinger/InputListener.cpp
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
mInnerListener(innerListener) {
}
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
mArgsQueue.push_back(new NotifyMotionArgs(*args));
}
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyMotion(this);
}
QueuedInputListener::notifyMotion方法实际上是添加到mArgsQueue中,只有调用flush的时候才取出处理(在InputReader的loopOnce最后会调用该方法)
所有事件处理完毕后,调用
mQueuedListener.flush()将所有暂存的输入事件一次性地交付给InputDispatcher
四、发送事件到InputDispatcher
再回到loopOnce(),也就是第三大部分了,前面终于把从驱动取出的原始事件信息收集起来转换成需要的对象,保存到了mArgsQueue中,最后一步只需要调用flush方法
InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener) :
mListener(listener) {
// The rest of the initialization is done in onFirstRef, because we need to obtain
// an sp to 'this' in order to register for HAL death notifications
}
void InputClassifier::notifyMotion(const NotifyMotionArgs* args) {
std::scoped_lock lock(mLock);
// MotionClassifier is only used for touch events, for now
const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(*args);
if (!sendToMotionClassifier) {
mListener->notifyMotion(args);
return;
}
NotifyMotionArgs newArgs(*args);
newArgs.classification = mMotionClassifier->classify(newArgs);
mListener->notifyMotion(&newArgs);
}
可以看到listener是InputClassifier,再看InputClassifier的构造方法是把InputDispatcher作为listener参数传递,调用InputClassifier::notifyMotion其实就是mListener,即InputDispatcher的notifyMotion
五、总结
多指事件处理部分流程图
总流程:
InputReader到这里对原始事件的加工处理就结束了,实际上还有设备增删相关的没有写出来,内容还是很多的,这部分后面可能再添加进来。