原文地址:http://blog.csdn.net/skdev/archive/2010/03/08/5357358.aspx 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类,即RawInputEvent的变量里,readEvent对应jni的android_server_KeyInputQueue_readEvent readEvent(ev); ... 8.2.2 获取触摸点数据 // 多点触摸和单点触摸的处理:保存多点或单点触摸的数据。 // 从多点触摸协议中获取位置事件 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; }