赞
踩
在Android的KeyInputQueue.java中,系统创建了一个线程,然后把所有的Input事件放入一个队列:
public abstract class KeyInputQueue { …………………… Thread mThread = new Thread("InputDeviceReader") { public void run() { android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
try { RawInputEvent ev = new RawInputEvent(); while (true) { InputDevice di; // block, doesn't release the monitor readEvent(ev); if (ev.type == RawInputEvent.EV_DEVICE_ADDED) { synchronized (mFirst) { di = newInputDevice(ev.deviceId); mDevices.put(ev.deviceId, di); configChanged = true; } } else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) { synchronized (mFirst) { Log.i(TAG, "Device removed: id=0x" + Integer.toHexString(ev.deviceId)); di = mDevices.get(ev.deviceId); if (di != null) { mDevices.delete(ev.deviceId); configChanged = true; } else { Log.w(TAG, "Bad device id: " + ev.deviceId); } } } else { di = getInputDevice(ev.deviceId);
// first crack at it send = preprocessEvent(di, ev);
if (ev.type == RawInputEvent.EV_KEY) { di.mMetaKeysState = makeMetaState(ev.keycode, ev.value != 0, di.mMetaKeysState); mHaveGlobalMetaState = false; } }
if (di == null) { continue; }
if (configChanged) { synchronized (mFirst) { addLocked(di, SystemClock.uptimeMillis(), 0, RawInputEvent.CLASS_CONFIGURATION_CHANGED, null); } }
if (!send) { continue; }
synchronized (mFirst) { ………………………. if (type == RawInputEvent.EV_KEY && (classes&RawInputEvent.CLASS_KEYBOARD) != 0 && (scancode < RawInputEvent.BTN_FIRST || scancode > RawInputEvent.BTN_LAST)) { /* 键盘按键事件 */ ……………………. } else if (ev.type == RawInputEvent.EV_KEY) { /* 下面是EV_KEY事件分支,只支持单点的触摸屏有按键事件, * 而支持多点的触摸屏没有按键事件,只有绝对坐标事件 */ if (ev.scancode == RawInputEvent.BTN_TOUCH && (classes&(RawInputEvent.CLASS_TOUCHSCREEN |RawInputEvent.CLASS_TOUCHSCREEN_MT)) == RawInputEvent.CLASS_TOUCHSCREEN) { /* 只支持单点的触摸屏的按键事件 */ ………………………………… } else if (ev.scancode == RawInputEvent.BTN_MOUSE && (classes&RawInputEvent.CLASS_TRACKBALL) != 0) { /* 鼠标和轨迹球 */ ………………………. } 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; } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) { di.mAbs.changed = true; di.mAbs.mNextData[di.mAbs.mAddingPointerOffset + MotionEvent.SAMPLE_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; } /* 上面这段就是多点触摸屏要用到的事件上报部分; * 使用一个数组mNextData来保存,其中di.mAbs.mAddingPointerOffset * 是当前点的偏移量,在每个点中还在MotionEvent中定义了X,Y,PRESSURE * SIZE等偏移量,多点触摸屏的压力值由绝对坐标事件ABS_MT_TOUCH_MAJOR确定。 */ } 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; } …………………………………………….} /* 下面是关键的同步处理方法 */ if (ev.type == RawInputEvent.EV_SYN && ev.scancode == RawInputEvent.SYN_MT_REPORT && di.mAbs != null) { /* 在这里实现了对SYN_MT_REPORT事件的处理, * 改变了di.mAbs.mAddingPointerOffset的值,从而将 * 新增的点的参数保存到下一组偏移量的位置。 */ ……………………. final int newOffset = (num <= InputDevice.MAX_POINTERS) ? (num * MotionEvent.NUM_SAMPLE_DATA) : (InputDevice.MAX_POINTERS * MotionEvent.NUM_SAMPLE_DATA); di.mAbs.mAddingPointerOffset = newOffset; di.mAbs.mNextData[newOffset + MotionEvent.SAMPLE_PRESSURE] = 0; } ………………. } else if (send || (ev.type == RawInputEvent.EV_SYN && ev.scancode == RawInputEvent.SYN_REPORT)) { /* 这里实现了对SYN_REPORT事件的处理 * 如果是单点触摸屏,即使用di.curTouchVals数组保存的点 * 转化为多点触摸屏的mNextData数组保存 * 最后是调用InputDevice中的generateAbsMotion处理这个数组。这个函数 * 的具体实现方法将在后面补充 */ ………………………….. ms.finish(); //重置所有点和偏移量 …………………….. } |
由于上层的代码仍然使用ABS_X, ABS_Y这些事件,为了使多点触摸屏代码有良好的兼容性,在KeyInputQueue.java的最后,我们将多点事件类型转化为单点事件类型,返回一个新的InputDevice:
private InputDevice newInputDevice(int deviceId) { int classes = getDeviceClasses(deviceId); String name = getDeviceName(deviceId); InputDevice.AbsoluteInfo absX; InputDevice.AbsoluteInfo absY; InputDevice.AbsoluteInfo absPressure; InputDevice.AbsoluteInfo absSize; if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) { absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_X, "X"); absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_Y, "Y"); absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_TOUCH_MAJOR, "Pressure"); absSize = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_WIDTH_MAJOR, "Size"); } else if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) { absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_X, "X"); absY = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_Y, "Y"); absPressure = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_PRESSURE, "Pressure"); absSize = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_TOOL_WIDTH, "Size"); } else { absX = null; absY = null; absPressure = null; absSize = null; } return new InputDevice(deviceId, classes, name, absX, absY, absPressure, absSize); } |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。