waterlife 发表于 2013-1-15 02:24:30

Android输入法之输入系统

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 = 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 = ev.value;                            } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_X) {                              di.mAbs.changed = true;                              di.mAbs.mNextData = 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 = 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 = 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 = ev.value;                            } else if (ev.scancode == RawInputEvent.ABS_Y) {                              di.mAbs.changed = true;                              di.curTouchVals = ev.value;                            } else if (ev.scancode == RawInputEvent.ABS_PRESSURE) {                              di.mAbs.changed = true;                              di.curTouchVals = ev.value;                              di.curTouchVals = ev.value;                            } else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) {                              di.mAbs.changed = true;                              di.curTouchVals = ev.value;                              di.curTouchVals = 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 += ev.value;                            } else if (ev.scancode == RawInputEvent.REL_Y) {                              di.mRel.changed = true;                              di.mRel.mNextData += 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 > 0) {                              // If the value is <= 0, the pointer is not                              // down, so keep it in the count.                                                                if (di.mAbs.mNextData != 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 = 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) {                                          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                                                    + " y="                                                    + di.mAbs.mNextData                                                    + " 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                                          + " y="                                          + di.mRel.mNextData                                          + " 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 jbooleanandroid_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://www.devdiv.net/bbs/attachments/month_1005/1005122259d51618664e3fa5de.png
页: [1]
查看完整版本: Android输入法之输入系统