你好,游客 登录 注册 搜索
背景:
阅读新闻

Android 2.1 架构解析

触摸屏

[日期:2014-03-16] 来源:Linux社区  作者:skdev [字体: ]

8 触摸屏

8.1 分类输入事件

文件:frameworks/base/libs/ui/EventHub.cpp

int EventHub::open_device(const char *deviceName)

{

...

uint8_t key_bitmask[(KEY_MAX+1)/8];

memset(key_bitmask, 0, sizeof(key_bitmask));

LOGV("Getting keys...");

if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {

//LOGI("MAP/n");

//for (int i=0; i<((KEY_MAX+1)/8); i++) {

//LOGI("%d: 0x%02x/n", i, key_bitmask[i]);

//}

for (int i=0; i<((BTN_MISC+7)/8); i++) {

if (key_bitmask[i] != 0) {

device->classes |= CLASS_KEYBOARD;

break;

}

}

if ((device->classes & CLASS_KEYBOARD) != 0) {

device->keyBitmask = new uint8_t[sizeof(key_bitmask)];

if (device->keyBitmask != NULL) {

memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));

} else {

delete device;

LOGE("out of memory allocating key bitmask");

return -1;

}

}

}

 

// See if this is a trackball.

if (test_bit(BTN_MOUSE, key_bitmask)) {

uint8_t rel_bitmask[(REL_MAX+1)/8];

memset(rel_bitmask, 0, sizeof(rel_bitmask));

LOGV("Getting relative controllers...");

if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0)

{

if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {

device->classes |= CLASS_TRACKBALL;

}

}

}

 

uint8_t abs_bitmask[(ABS_MAX+1)/8];

memset(abs_bitmask, 0, sizeof(abs_bitmask));

LOGV("Getting absolute controllers...");

ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);

 

// Is this a new modern multi-touch driver?

if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)

&& test_bit(ABS_MT_POSITION_X, abs_bitmask)

&& test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {

device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT;

 

// Is this an old style single-touch driver?

} else if (test_bit(BTN_TOUCH, key_bitmask)

&& test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {

device->classes |= CLASS_TOUCHSCREEN;

}

...

}

输入事件有:键盘、轨迹球、单点触摸、多点触摸

8.2 输入事件服务

文件:frameworks/base/services/java/com/Android/server/KeyInputQueue.java

8.2.1 获取事件

Thread mThread = new Thread("InputDeviceReader") {

public void run() {

if (DEBUG) Log.v(TAG, "InputDeviceReader.run()");

android.os.Process.setThreadPriority(

android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);

 

RawInputEvent ev = new RawInputEvent();

while (true) {

try {

...

// block, doesn't release the monitor

readEvent(ev);

...

调用readEvent,将输入事件读取到ev类,即RawInputEvent的变量里,readEvent对应jniandroid_server_KeyInputQueue_readEvent

8.2.2 获取触摸点数据

// Process position events from multitouch protocol.

else if (ev.type == RawInputEvent.EV_ABS &&

(classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {

if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) {

di.mAbs.changed = true;

di.mAbs.mNextData[di.mAbs.mAddingPointerOffset

+ MotionEvent.SAMPLE_PRESSURE] = ev.value;

} else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_X) {

di.mAbs.changed = true;

di.mAbs.mNextData[di.mAbs.mAddingPointerOffset

+ MotionEvent.SAMPLE_X] = ev.value;

if (DEBUG_POINTERS) Log.v(TAG, "MT @"

+ di.mAbs.mAddingPointerOffset

+ " X:" + ev.value);

} else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) {

di.mAbs.changed = true;

di.mAbs.mNextData[di.mAbs.mAddingPointerOffset

+ MotionEvent.SAMPLE_Y] = ev.value;

if (DEBUG_POINTERS) Log.v(TAG, "MT @"

+ di.mAbs.mAddingPointerOffset

+ " Y:" + ev.value);

} else if (ev.scancode == RawInputEvent.ABS_MT_WIDTH_MAJOR) {

di.mAbs.changed = true;

di.mAbs.mNextData[di.mAbs.mAddingPointerOffset

+ MotionEvent.SAMPLE_SIZE] = ev.value;

}

 

// Process position events from single touch protocol.

} else if (ev.type == RawInputEvent.EV_ABS &&

(classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {

if (ev.scancode == RawInputEvent.ABS_X) {

di.mAbs.changed = true;

di.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;

} else if (ev.scancode == RawInputEvent.ABS_Y) {

di.mAbs.changed = true;

di.curTouchVals[MotionEvent.SAMPLE_Y] = ev.value;

} else if (ev.scancode == RawInputEvent.ABS_PRESSURE) {

di.mAbs.changed = true;

di.curTouchVals[MotionEvent.SAMPLE_PRESSURE] = ev.value;

di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA

+ MotionEvent.SAMPLE_PRESSURE] = ev.value;

} else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) {

di.mAbs.changed = true;

di.curTouchVals[MotionEvent.SAMPLE_SIZE] = ev.value;

di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA

+ MotionEvent.SAMPLE_SIZE] = ev.value;

}

 

}

多点触摸和单点触摸的处理:保存多点或单点触摸的数据。

8.2.3 获取转换后触点数据

if (doMotion) {

// XXX Need to be able to generate

// multiple events here, for example

// if two fingers change up/down state

// at the same time.

do {

me = ms.generateAbsMotion(di, curTime,

curTimeNano, mDisplay,

mOrientation, mGlobalMetaState);

if (DEBUG_POINTERS) Log.v(TAG, "Absolute: x="

+ di.mAbs.mNextData[MotionEvent.SAMPLE_X]

+ " y="

+ di.mAbs.mNextData[MotionEvent.SAMPLE_Y]

+ " ev=" + me);

if (me != null) {

if (WindowManagerPolicy.WATCH_POINTER) {

Log.i(TAG, "Enqueueing: " + me);

}

addLocked(di, curTimeNano, ev.flags,

RawInputEvent.CLASS_TOUCHSCREEN, me);

}

} while (ms.hasMore());

}

获取转换后触摸点数据并加入到输入事件队列。

8.3 读取触摸点数据的流程

文件:frameworks/base/services/java/com/android/server/KeyInputQueue.java

readEvent(ev);

di.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;

文件:frameworks/base/services/jni/com_android_server_KeyInputQueue.cpp

{ "readEvent","(Landroid/view/RawInputEvent;)Z",

(void*) android_server_KeyInputQueue_readEvent },

..

static jboolean

android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,

jobject event)

{

...

bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,

&flags, &value, &when);

...

}

文件:frameworks/base/libs/ui/EventHub.cpp

bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,

int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,

int32_t* outValue, nsecs_t* outWhen)

{

...

res = read(mFDs[i].fd, &iev, sizeof(iev));

 

...

 

*outValue = iev.value;

..

}

8.4 触点数据转换

文件:frameworks/base/services/java/com/android/server/InutDevice.java

MotionEvent generateAbsMotion(InputDevice device, long curTime,

long curTimeNano, Display display, int orientation,

int metaState) {

 

if (mSkipLastPointers) {

mSkipLastPointers = false;

mLastNumPointers = 0;

}

 

if (mNextNumPointers <= 0 && mLastNumPointers <= 0) {

return null;

}

 

final int lastNumPointers = mLastNumPointers;

final int nextNumPointers = mNextNumPointers;

if (mNextNumPointers > MAX_POINTERS) {

Log.w("InputDevice", "Number of pointers " + mNextNumPointers

+ " exceeded maximum of " + MAX_POINTERS);

mNextNumPointers = MAX_POINTERS;

}

 

int upOrDownPointer = updatePointerIdentifiers();

 

final float[] reportData = mReportData;

final int[] rawData;

if (KeyInputQueue.BAD_TOUCH_HACK) {

rawData = generateAveragedData(upOrDownPointer, lastNumPointers,

nextNumPointers);

} else {

rawData = mLastData;

}

 

final int numPointers = mLastNumPointers;

 

if (DEBUG_POINTERS) Log.v("InputDevice", "Processing "

+ numPointers + " pointers (going from " + lastNumPointers

+ " to " + nextNumPointers + ")");

 

for (int i=0; i<numPointers; i++) {

final int pos = i * MotionEvent.NUM_SAMPLE_DATA;

reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X];

reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y];

reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE];

reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE];

}

 

int action;

int edgeFlags = 0;

if (nextNumPointers != lastNumPointers) {

if (nextNumPointers > lastNumPointers) {

if (lastNumPointers == 0) {

action = MotionEvent.ACTION_DOWN;

mDownTime = curTime;

} else {

action = MotionEvent.ACTION_POINTER_DOWN

| (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);

}

} else {

if (numPointers == 1) {

action = MotionEvent.ACTION_UP;

} else {

action = MotionEvent.ACTION_POINTER_UP

| (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);

}

}

currentMove = null;

} else {

action = MotionEvent.ACTION_MOVE;

}

 

final int dispW = display.getWidth()-1;

final int dispH = display.getHeight()-1;

int w = dispW;

int h = dispH;

if (orientation == Surface.ROTATION_90

|| orientation == Surface.ROTATION_270) {

int tmp = w;

w = h;

h = tmp;

}

 

final AbsoluteInfo absX = device.absX;

final AbsoluteInfo absY = device.absY;

final AbsoluteInfo absPressure = device.absPressure;

final AbsoluteInfo absSize = device.absSize;

for (int i=0; i<numPointers; i++) {

final int j = i * MotionEvent.NUM_SAMPLE_DATA;

 

if (absX != null) {

reportData[j + MotionEvent.SAMPLE_X] =

((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)

/ absX.range) * w;

}

if (absY != null) {

reportData[j + MotionEvent.SAMPLE_Y] =

((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue)

/ absY.range) * h;

}

if (absPressure != null) {

reportData[j + MotionEvent.SAMPLE_PRESSURE] =

((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue)

/ (float)absPressure.range);

}

if (absSize != null) {

reportData[j + MotionEvent.SAMPLE_SIZE] =

((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue)

/ (float)absSize.range);

}

 

switch (orientation) {

case Surface.ROTATION_90: {

final float temp = reportData[j + MotionEvent.SAMPLE_X];

reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y];

reportData[j + MotionEvent.SAMPLE_Y] = w-temp;

break;

}

case Surface.ROTATION_180: {

reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X];

reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y];

break;

}

case Surface.ROTATION_270: {

final float temp = reportData[j + MotionEvent.SAMPLE_X];

reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y];

reportData[j + MotionEvent.SAMPLE_Y] = temp;

break;

}

}

}

 

// We only consider the first pointer when computing the edge

// flags, since they are global to the event.

if (action == MotionEvent.ACTION_DOWN) {

if (reportData[MotionEvent.SAMPLE_X] <= 0) {

edgeFlags |= MotionEvent.EDGE_LEFT;

} else if (reportData[MotionEvent.SAMPLE_X] >= dispW) {

edgeFlags |= MotionEvent.EDGE_RIGHT;

}

if (reportData[MotionEvent.SAMPLE_Y] <= 0) {

edgeFlags |= MotionEvent.EDGE_TOP;

} else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) {

edgeFlags |= MotionEvent.EDGE_BOTTOM;

}

}

 

if (currentMove != null) {

if (false) Log.i("InputDevice", "Adding batch x="

+ reportData[MotionEvent.SAMPLE_X]

+ " y=" + reportData[MotionEvent.SAMPLE_Y]

+ " to " + currentMove);

currentMove.addBatch(curTime, reportData, metaState);

if (WindowManagerPolicy.WATCH_POINTER) {

Log.i("KeyInputQueue", "Updating: " + currentMove);

}

return null;

}

 

MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,

curTimeNano, action, numPointers, mPointerIds, reportData,

metaState, xPrecision, yPrecision, device.id, edgeFlags);

if (action == MotionEvent.ACTION_MOVE) {

currentMove = me;

}

 

if (nextNumPointers < lastNumPointers) {

removeOldPointer(upOrDownPointer);

}

 

return me;

}

将原始数据点转化为显示屏对应的数据,一般触摸屏校正就在这里对数据点进行较正的。

linux
相关资讯       Android 2.1 
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款