Android输入法之输入系统
来源:互联网 发布:淘宝网动漫口罩 编辑:程序博客网 时间:2024/04/29 10:35
Android通过 KeyInputQ在WindowMangerService中建立一个独立的线程InputDeviceReader,使用Native函数readEvent来读取Linux Driver的数据构建RawEvent,并放入到KeyQ消息队列中。
KeyInputQueue.java
- 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 {
- InputDevice di;
- // block, doesn't release the monitor
- readEvent(ev);
- boolean send = false;
- boolean configChanged = false;
- if (false) {
- Log.i(TAG, "Input event: dev=0x"
- + Integer.toHexString(ev.deviceId)
- + " type=0x" + Integer.toHexString(ev.type)
- + " scancode=" + ev.scancode
- + " keycode=" + ev.keycode
- + " value=" + ev.value);
- }
- if (ev.type == RawInputEvent.EV_DEVICE_ADDED) {
- synchronized (mFirst) {
- di = newInputDevice(ev.deviceId);
- if (di.classes != 0) {
- // If this device is some kind of input class,
- // we care about it.
- mDevices.put(ev.deviceId, di);
- if ((di.classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
- readVirtualKeys(di.name);
- }
- // The configuration may have changed because
- // of this device.
- configChanged = true;
- } else {
- // We won't do anything with this device.
- mIgnoredDevices.put(ev.deviceId, di);
- Log.i(TAG, "Ignoring non-input device: id=0x"
- + Integer.toHexString(di.id)
- + ", name=" + di.name);
- }
- }
- } else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) {
- synchronized (mFirst) {
- if (false) {
- Log.i(TAG, "Device removed: id=0x"
- + Integer.toHexString(ev.deviceId));
- }
- di = mDevices.get(ev.deviceId);
- if (di != null) {
- mDevices.delete(ev.deviceId);
- // The configuration may have changed because
- // of this device.
- configChanged = true;
- } else if ((di=mIgnoredDevices.get(ev.deviceId)) != null) {
- mIgnoredDevices.remove(ev.deviceId);
- } else {
- Log.w(TAG, "Removing bad device id: "
- + Integer.toHexString(ev.deviceId));
- continue;
- }
- }
- } else {
- di = getInputDevice(ev.deviceId);
- if (di == null) {
- // This may be some junk from an ignored device.
- continue;
- }
- // 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 (configChanged) {
- synchronized (mFirst) {
- addLocked(di, System.nanoTime(), 0,
- RawInputEvent.CLASS_CONFIGURATION_CHANGED,
- null);
- }
- }
- if (!send) {
- continue;
- }
- synchronized (mFirst) {
- // NOTE: The event timebase absolutely must be the same
- // timebase as SystemClock.uptimeMillis().
- //curTime = gotOne ? ev.when : SystemClock.uptimeMillis();
- final long curTime = SystemClock.uptimeMillis();
- final long curTimeNano = System.nanoTime();
- //Log.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis());
- final int classes = di.classes;
- final int type = ev.type;
- final int scancode = ev.scancode;
- send = false;
- // Is it a key event?
- if (type == RawInputEvent.EV_KEY &&
- (classes&RawInputEvent.CLASS_KEYBOARD) != 0 &&
- (scancode < RawInputEvent.BTN_FIRST ||
- scancode > RawInputEvent.BTN_LAST)) {
- boolean down;
- if (ev.value != 0) {
- down = true;
- di.mKeyDownTime = curTime;
- } else {
- down = false;
- }
- int keycode = rotateKeyCodeLocked(ev.keycode);
- addLocked(di, curTimeNano, ev.flags,
- RawInputEvent.CLASS_KEYBOARD,
- newKeyEvent(di, di.mKeyDownTime, curTime, down,
- keycode, 0, scancode,
- ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
- ? KeyEvent.FLAG_WOKE_HERE : 0));
- } else if (ev.type == RawInputEvent.EV_KEY) {
- // Single touch protocol: touch going down or up.
- if (ev.scancode == RawInputEvent.BTN_TOUCH &&
- (classes&(RawInputEvent.CLASS_TOUCHSCREEN
- |RawInputEvent.CLASS_TOUCHSCREEN_MT))
- == RawInputEvent.CLASS_TOUCHSCREEN) {
- di.mAbs.changed = true;
- di.mAbs.mDown[0] = ev.value != 0;
- // Trackball (mouse) protocol: press down or up.
- } else if (ev.scancode == RawInputEvent.BTN_MOUSE &&
- (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
- di.mRel.changed = true;
- di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0;
- send = true;
- }
- // 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;
- }
- // Process movement events from trackball (mouse) protocol.
- } else if (ev.type == RawInputEvent.EV_REL &&
- (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
- // Add this relative movement into our totals.
- if (ev.scancode == RawInputEvent.REL_X) {
- di.mRel.changed = true;
- di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value;
- } else if (ev.scancode == RawInputEvent.REL_Y) {
- di.mRel.changed = true;
- di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value;
- }
- }
- // Handle multitouch protocol sync: tells us that the
- // driver has returned all data for -one- of the pointers
- // that is currently down.
- if (ev.type == RawInputEvent.EV_SYN
- && ev.scancode == RawInputEvent.SYN_MT_REPORT
- && di.mAbs != null) {
- di.mAbs.changed = true;
- if (di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] > 0) {
- // If the value is <= 0, the pointer is not
- // down, so keep it in the count.
- if (di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
- + MotionEvent.SAMPLE_PRESSURE] != 0) {
- final int num = di.mAbs.mNextNumPointers+1;
- di.mAbs.mNextNumPointers = num;
- if (DEBUG_POINTERS) Log.v(TAG,
- "MT_REPORT: now have " + num + " pointers");
- 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 (DEBUG_POINTERS) Log.v(TAG, "MT_REPORT: no pointer");
- }
- }
- // Handle general event sync: all data for the current
- // event update has been delivered.
- } else if (send || (ev.type == RawInputEvent.EV_SYN
- && ev.scancode == RawInputEvent.SYN_REPORT)) {
- if (mDisplay != null) {
- if (!mHaveGlobalMetaState) {
- computeGlobalMetaStateLocked();
- }
- MotionEvent me;
- InputDevice.MotionState ms = di.mAbs;
- if (ms.changed) {
- ms.changed = false;
- if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN
- |RawInputEvent.CLASS_TOUCHSCREEN_MT))
- == RawInputEvent.CLASS_TOUCHSCREEN) {
- ms.mNextNumPointers = 0;
- if (ms.mDown[0]) {
- System.arraycopy(di.curTouchVals, 0,
- ms.mNextData, 0,
- MotionEvent.NUM_SAMPLE_DATA);
- ms.mNextNumPointers++;
- }
- }
- if (BAD_TOUCH_HACK) {
- ms.dropBadPoint(di);
- }
- boolean doMotion = !monitorVirtualKey(di,
- ev, curTime, curTimeNano);
- if (doMotion && ms.mNextNumPointers > 0
- && (ms.mLastNumPointers == 0
- || ms.mSkipLastPointers)) {
- doMotion = !generateVirtualKeyDown(di,
- ev, curTime, curTimeNano);
- }
- 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());
- } else {
- // We are consuming movement in the
- // virtual key area... but still
- // propagate this to the previous
- // data for comparisons.
- int num = ms.mNextNumPointers;
- if (num > InputDevice.MAX_POINTERS) {
- num = InputDevice.MAX_POINTERS;
- }
- System.arraycopy(ms.mNextData, 0,
- ms.mLastData, 0,
- num * MotionEvent.NUM_SAMPLE_DATA);
- ms.mLastNumPointers = num;
- ms.mSkipLastPointers = true;
- }
- ms.finish();
- }
- ms = di.mRel;
- if (ms.changed) {
- ms.changed = false;
- me = ms.generateRelMotion(di, curTime,
- curTimeNano,
- mOrientation, mGlobalMetaState);
- if (false) Log.v(TAG, "Relative: x="
- + di.mRel.mNextData[MotionEvent.SAMPLE_X]
- + " y="
- + di.mRel.mNextData[MotionEvent.SAMPLE_Y]
- + " ev=" + me);
- if (me != null) {
- addLocked(di, curTimeNano, ev.flags,
- RawInputEvent.CLASS_TRACKBALL, me);
- }
- ms.finish();
- }
- }
- }
- }
- } catch (RuntimeException exc) {
- Log.e(TAG, "InputReaderThread uncaught exception", exc);
- }
- }
- }
- };
- private static native boolean readEvent(RawInputEvent outEvent);
framworks.base.server.jni
- static jboolean
- android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,
- jobject event)
- {
- gLock.lock();
- sp<EventHub> hub = gHub;
- if (hub == NULL) {
- hub = new EventHub;
- gHub = hub;
- }
- gLock.unlock();
- int32_t deviceId;
- int32_t type;
- int32_t scancode, keycode;
- uint32_t flags;
- int32_t value;
- nsecs_t when;
- bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,
- &flags, &value, &when);
- env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);
- env->SetIntField(event, gInputOffsets.mType, (jint)type);
- env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);
- env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);
- env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);
- env->SetIntField(event, gInputOffsets.mValue, value);
- env->SetLongField(event, gInputOffsets.mWhen,
- (jlong)(nanoseconds_to_milliseconds(when)));
- return res;
- }
InputDispatcherThread从KeyQ中读取Events,找到Window Manager中的Focus Window,通过Focus Window记录的mClient接口,将Events专递到Client端。Client端在根据自己的Focus Path传递事件,直到事件被处理。
- private final class InputDispatcherThread extends Thread {
- // Time to wait when there is nothing to do: 9999 seconds.
- static final int LONG_WAIT=9999*1000;
- public InputDispatcherThread() {
- super("InputDispatcher");
- }
- @Override
- public void run() {
- while (true) {
- try {
- process();
- } catch (Exception e) {
- Log.e(TAG, "Exception in input dispatcher", e);
- }
- }
- }
- private void process() {
- android.os.Process.setThreadPriority(
- android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
- // The last key event we saw
- KeyEvent lastKey = null;
- // Last keydown time for auto-repeating keys
- long lastKeyTime = SystemClock.uptimeMillis();
- long nextKeyTime = lastKeyTime+LONG_WAIT;
- long downTime = 0;
- // How many successive repeats we generated
- int keyRepeatCount = 0;
- // Need to report that configuration has changed?
- boolean configChanged = false;
- while (true) {
- long curTime = SystemClock.uptimeMillis();
- if (DEBUG_INPUT) Log.v(
- TAG, "Waiting for next key: now=" + curTime
- + ", repeat @ " + nextKeyTime);
- // Retrieve next event, waiting only as long as the next
- // repeat timeout. If the configuration has changed, then
- // don't wait at all -- we'll report the change as soon as
- // we have processed all events.
- QueuedEvent ev = mQueue.getEvent(
- (int)((!configChanged && curTime < nextKeyTime)
- ? (nextKeyTime-curTime) : 0));
- if (DEBUG_INPUT && ev != null) Log.v(
- TAG, "Event: type=" + ev.classType + " data=" + ev.event);
- if (MEASURE_LATENCY) {
- lt.sample("2 got event ", System.nanoTime() - ev.whenNano);
- }
- if (lastKey != null && !mPolicy.allowKeyRepeat()) {
- // cancel key repeat at the request of the policy.
- lastKey = null;
- downTime = 0;
- lastKeyTime = curTime;
- nextKeyTime = curTime + LONG_WAIT;
- }
- try {
- if (ev != null) {
- curTime = SystemClock.uptimeMillis();
- int eventType;
- if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
- eventType = eventType((MotionEvent)ev.event);
- } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
- ev.classType == RawInputEvent.CLASS_TRACKBALL) {
- eventType = LocalPowerManager.BUTTON_EVENT;
- } else {
- eventType = LocalPowerManager.OTHER_EVENT;
- }
- try {
- if ((curTime - mLastBatteryStatsCallTime)
- >= MIN_TIME_BETWEEN_USERACTIVITIES) {
- mLastBatteryStatsCallTime = curTime;
- mBatteryStats.noteInputEvent();
- }
- } catch (RemoteException e) {
- // Ignore
- }
- if (eventType != TOUCH_EVENT
- && eventType != LONG_TOUCH_EVENT
- && eventType != CHEEK_EVENT) {
- mPowerManager.userActivity(curTime, false,
- eventType, false);
- } else if (mLastTouchEventType != eventType
- || (curTime - mLastUserActivityCallTime)
- >= MIN_TIME_BETWEEN_USERACTIVITIES) {
- mLastUserActivityCallTime = curTime;
- mLastTouchEventType = eventType;
- mPowerManager.userActivity(curTime, false,
- eventType, false);
- }
- switch (ev.classType) {
- case RawInputEvent.CLASS_KEYBOARD:
- KeyEvent ke = (KeyEvent)ev.event;
- if (ke.isDown()) {
- lastKey = ke;
- downTime = curTime;
- keyRepeatCount = 0;
- lastKeyTime = curTime;
- nextKeyTime = lastKeyTime
- + ViewConfiguration.getLongPressTimeout();
- //a21966,Creekside: if it is a SLIDER close event do not wait the key up event
- if (ke.getScanCode() == 254){
- lastKey = null;
- downTime = 0;
- lastKeyTime = curTime;
- nextKeyTime = curTime + LONG_WAIT;
- }
- if (DEBUG_INPUT) Log.v(
- TAG, "Received key down: first repeat @ "
- + nextKeyTime);
- } else {
- lastKey = null;
- downTime = 0;
- // Arbitrary long timeout.
- lastKeyTime = curTime;
- nextKeyTime = curTime + LONG_WAIT;
- if (DEBUG_INPUT) Log.v(
- TAG, "Received key up: ignore repeat @ "
- + nextKeyTime);
- }
- dispatchKey((KeyEvent)ev.event, 0, 0);
- mQueue.recycleEvent(ev);
- break;
- case RawInputEvent.CLASS_TOUCHSCREEN:
- //Log.i(TAG, "Read next event " + ev);
- dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
- break;
- case RawInputEvent.CLASS_TRACKBALL:
- dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
- break;
- case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
- configChanged = true;
- break;
- default:
- mQueue.recycleEvent(ev);
- break;
- }
- } else if (configChanged) {
- configChanged = false;
- sendNewConfiguration();
- } else if (lastKey != null) {
- curTime = SystemClock.uptimeMillis();
- // Timeout occurred while key was down. If it is at or
- // past the key repeat time, dispatch the repeat.
- if (DEBUG_INPUT) Log.v(
- TAG, "Key timeout: repeat=" + nextKeyTime
- + ", now=" + curTime);
- if (curTime < nextKeyTime) {
- continue;
- }
- lastKeyTime = nextKeyTime;
- nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
- keyRepeatCount++;
- if (DEBUG_INPUT) Log.v(
- TAG, "Key repeat: count=" + keyRepeatCount
- + ", next @ " + nextKeyTime);
- KeyEvent newEvent;
- if (downTime != 0 && (downTime
- + ViewConfiguration.getLongPressTimeout())
- <= curTime) {
- newEvent = KeyEvent.changeTimeRepeat(lastKey,
- curTime, keyRepeatCount,
- lastKey.getFlags() | KeyEvent.FLAG_LONG_PRESS);
- downTime = 0;
- } else {
- newEvent = KeyEvent.changeTimeRepeat(lastKey,
- curTime, keyRepeatCount);
- }
- dispatchKey(newEvent, 0, 0);
- } else {
- curTime = SystemClock.uptimeMillis();
- lastKeyTime = curTime;
- nextKeyTime = curTime + LONG_WAIT;
- }
- } catch (Exception e) {
- Log.e(TAG,
- "Input thread received uncaught exception: " + e, e);
- }
- }
- }
- }
http://waterlife.javaeye.com/blog/709885
- Android输入法之输入系统
- Android初学------系统设置之设置输入法
- Android输入系统之输入路径详解
- Android输入系统之输入路径详解
- Android输入法扩展之外接键盘中文输入
- Android输入系统之InputChannel
- Android调用系统输入法
- Android调用系统输入法
- Android输入系统之App跟输入系统建立联系
- Android输入系统之InputChannel(上)
- Android输入系统之InputChannel(下)
- Android输入系统之InputChannel(上)
- Android输入系统之InputChannel(下)
- Android 输入系统之EventHub篇
- Android 输入系统之InputReader篇
- Android 输入系统之InputDispatcher篇
- Android 输入系统之InputDispatcher2ViewRootImpl篇----终
- Android输入系统之activity_window_decor_view关系
- 苏州工业园区公积金政策滋生的黑色产业链
- [转]VC中进度条实时刷新办法
- Java 注解
- Linux内核NAPI机制分析
- 如何改变对话框的背景颜色
- Android输入法之输入系统
- android拨号器的实现
- 关于DLL函数名导出名字命名规则的转帖
- 纪念一下我的flex环境搭建历程
- Latex相关资源汇总
- android生命周期
- android的Activity转换
- 深入JVM——栈和局部变量
- androidUI第六部分---其他常用控件举例