关于Android 5.1 LatinIME的分析

来源:互联网 发布:剖腹产 知乎 编辑:程序博客网 时间:2024/04/30 02:28

因为公司产品是一款vr,是没有触摸屏的,所有要想用蓝牙手柄操控LatinIME就得进行修改

LatinIME最主要的就是一个继承InputMethodService的服务,类名就是LatinIME.java

而MainKeyboardView.java就是画出来的那块键盘了,主要的响应触摸,传递键值都绕不过它调用的PointerTracker.java

直接看响应触摸的吧

通过onTouchEvent找到processMotionEvent(me);然后在processMotionEvent(me);看到tracker.processMotionEvent(me, mKeyDetector);

@Override    public boolean onTouchEvent(final MotionEvent me) {        if (getKeyboard() == null) {            return false;        }        if (mNonDistinctMultitouchHelper != null) {            if (me.getPointerCount() > 1 && mKeyTimerHandler.isInKeyRepeat()) {                // Key repeating timer will be canceled if 2 or more keys are in action.                mKeyTimerHandler.cancelKeyRepeatTimers();            }            // Non distinct multitouch screen support            mNonDistinctMultitouchHelper.processMotionEvent(me, mKeyDetector);            return true;        }        return processMotionEvent(me);    }    public boolean processMotionEvent(final MotionEvent me) {        final int index = me.getActionIndex();        final int id = me.getPointerId(index);        final PointerTracker tracker = PointerTracker.getPointerTracker(id);        // When a more keys panel is showing, we should ignore other fingers' single touch events        // other than the finger that is showing the more keys panel.        if (isShowingMoreKeysPanel() && !tracker.isShowingMoreKeysPanel()                && PointerTracker.getActivePointerTrackerCount() == 1) {            return true;        }        tracker.processMotionEvent(me, mKeyDetector);        return true;    }

触摸是在PointerTracker.java的processMotionEvent(me, mKeyDetector);里进行处理的

而PointerTracker.java里还有两个接口DrawingProxy和TimerProxy

public interface DrawingProxy {        public void invalidateKey(Key key);        public void showKeyPreview(Key key);        public void dismissKeyPreview(Key key);        public void showSlidingKeyInputPreview(PointerTracker tracker);        public void dismissSlidingKeyInputPreview();        public void showGestureTrail(PointerTracker tracker, boolean showsFloatingPreviewText);    }    public interface TimerProxy {        public void startTypingStateTimer(Key typedKey);        public boolean isTypingState();        public void startKeyRepeatTimerOf(PointerTracker tracker, int repeatCount, int delay);        public void startLongPressTimerOf(PointerTracker tracker, int delay);        public void cancelLongPressTimerOf(PointerTracker tracker);        public void cancelLongPressShiftKeyTimers();        public void cancelKeyTimersOf(PointerTracker tracker);        public void startDoubleTapShiftKeyTimer();        public void cancelDoubleTapShiftKeyTimer();        public boolean isInDoubleTapShiftKeyTimeout();        public void startUpdateBatchInputTimer(PointerTracker tracker);        public void cancelUpdateBatchInputTimer(PointerTracker tracker);        public void cancelAllUpdateBatchInputTimers();        public static class Adapter implements TimerProxy {            @Override            public void startTypingStateTimer(Key typedKey) {}            @Override            public boolean isTypingState() { return false; }            @Override            public void startKeyRepeatTimerOf(PointerTracker tracker, int repeatCount, int delay) {}            @Override            public void startLongPressTimerOf(PointerTracker tracker, int delay) {}            @Override            public void cancelLongPressTimerOf(PointerTracker tracker) {}            @Override            public void cancelLongPressShiftKeyTimers() {}            @Override            public void cancelKeyTimersOf(PointerTracker tracker) {}            @Override            public void startDoubleTapShiftKeyTimer() {}            @Override            public void cancelDoubleTapShiftKeyTimer() {}            @Override            public boolean isInDoubleTapShiftKeyTimeout() { return false; }            @Override            public void startUpdateBatchInputTimer(PointerTracker tracker) {}            @Override            public void cancelUpdateBatchInputTimer(PointerTracker tracker) {}            @Override            public void cancelAllUpdateBatchInputTimers() {}        }    }

TimerProxy是按下去时计时的,不用管,而DrawingProxy就是画的接口了

包括按下去时字母背景变黑和弹出pop,抬起时恢复等等

接着看processMotionEvent

public void processMotionEvent(final MotionEvent me, final KeyDetector keyDetector) {        final int action = me.getActionMasked();        final long eventTime = me.getEventTime();        if (action == MotionEvent.ACTION_MOVE) {            // When this pointer is the only active pointer and is showing a more keys panel,            // we should ignore other pointers' motion event.            final boolean shouldIgnoreOtherPointers =                    isShowingMoreKeysPanel() && getActivePointerTrackerCount() == 1;            final int pointerCount = me.getPointerCount();            for (int index = 0; index < pointerCount; index++) {                final int id = me.getPointerId(index);                if (shouldIgnoreOtherPointers && id != mPointerId) {                    continue;                }                final int x = (int)me.getX(index);                final int y = (int)me.getY(index);                final PointerTracker tracker = getPointerTracker(id);                tracker.onMoveEvent(x, y, eventTime, me);            }            return;        }        final int index = me.getActionIndex();        final int x = (int)me.getX(index);        final int y = (int)me.getY(index);        switch (action) {        case MotionEvent.ACTION_DOWN:        case MotionEvent.ACTION_POINTER_DOWN:            onDownEvent(x, y, eventTime, keyDetector);            break;        case MotionEvent.ACTION_UP:        case MotionEvent.ACTION_POINTER_UP:            onUpEvent(x, y, eventTime);            break;        case MotionEvent.ACTION_CANCEL:            onCancelEvent(x, y, eventTime);            break;        }    }

响应触摸主要是onDownEvent(x, y, eventTime, keyDetector);和onUpEvent(x, y, eventTime);两个方法

private void onDownEvent(final int x, final int y, final long eventTime,            final KeyDetector keyDetector) {        setKeyDetectorInner(keyDetector);        if (DEBUG_EVENT) {            printTouchEvent("onDownEvent:", x, y, eventTime);        }        // Naive up-to-down noise filter.        final long deltaT = eventTime - mUpTime;        if (deltaT < sParams.mTouchNoiseThresholdTime) {            final int distance = getDistance(x, y, mLastX, mLastY);            if (distance < sParams.mTouchNoiseThresholdDistance) {                if (DEBUG_MODE)                    Log.w(TAG, String.format("[%d] onDownEvent:"                            + " ignore potential noise: time=%d distance=%d",                            mPointerId, deltaT, distance));                cancelTrackingForAction();                return;            }        }        final Key key = getKeyOn(x, y);        mBogusMoveEventDetector.onActualDownEvent(x, y);        if (key != null && key.isModifier()) {            // Before processing a down event of modifier key, all pointers already being            // tracked should be released.            sPointerTrackerQueue.releaseAllPointers(eventTime);        }        sPointerTrackerQueue.add(this);        onDownEventInternal(x, y, eventTime);        if (!sGestureEnabler.shouldHandleGesture()) {            return;        }        // A gesture should start only from a non-modifier key. Note that the gesture detection is        // disabled when the key is repeating.        mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard()                && key != null && !key.isModifier();        if (mIsDetectingGesture) {            mBatchInputArbiter.addDownEventPoint(x, y, eventTime,                    sTypingTimeRecorder.getLastLetterTypingTime(), getActivePointerTrackerCount());            mGestureStrokeDrawingPoints.onDownEvent(                    x, y, mBatchInputArbiter.getElapsedTimeSinceFirstDown(eventTime));        }    }    /* package */ boolean isShowingMoreKeysPanel() {        return (mMoreKeysPanel != null);    }

private void onUpEvent(final int x, final int y, final long eventTime) {        if (DEBUG_EVENT) {            printTouchEvent("onUpEvent  :", x, y, eventTime);        }        sTimerProxy.cancelUpdateBatchInputTimer(this);        if (!sInGesture) {            if (mCurrentKey != null && mCurrentKey.isModifier()) {                // Before processing an up event of modifier key, all pointers already being                // tracked should be released.                sPointerTrackerQueue.releaseAllPointersExcept(this, eventTime);            } else {                sPointerTrackerQueue.releaseAllPointersOlderThan(this, eventTime);            }        }        onUpEventInternal(x, y, eventTime);        sPointerTrackerQueue.remove(this);    }

onDownEvent中的onDownEventInternal(final int x, final int y, final long eventTime)和onUpEvent中的onUpEventInternal(final int x, final int y, final long eventTime)方法对触摸进行了处理

private void onDownEventInternal(final int x, final int y, final long eventTime) {        Key key = onDownKey(x, y, eventTime);        // Key selection by dragging finger is allowed when 1) key selection by dragging finger is        // enabled by configuration, 2) this pointer starts dragging from modifier key, or 3) this        // pointer's KeyDetector always allows key selection by dragging finger, such as        // {@link MoreKeysKeyboard}.        mIsAllowedDraggingFinger = sParams.mKeySelectionByDraggingFinger                || (key != null && key.isModifier())                || mKeyDetector.alwaysAllowsKeySelectionByDraggingFinger();        mKeyboardLayoutHasBeenChanged = false;        mIsTrackingForActionDisabled = false;        resetKeySelectionByDraggingFinger();        if (key != null) {            // This onPress call may have changed keyboard layout. Those cases are detected at            // {@link #setKeyboard}. In those cases, we should update key according to the new            // keyboard layout.            if (callListenerOnPressAndCheckKeyboardLayoutChange(key, 0 /* repeatCount */)) {                key = onDownKey(x, y, eventTime);            }            startRepeatKey(key);            startLongPressTimer(key);            setPressedKeyGraphics(key, eventTime);        }    }

private void onUpEventInternal(final int x, final int y, final long eventTime) {        sTimerProxy.cancelKeyTimersOf(this);        final boolean isInDraggingFinger = mIsInDraggingFinger;        final boolean isInSlidingKeyInput = mIsInSlidingKeyInput;        resetKeySelectionByDraggingFinger();        mIsDetectingGesture = false;        final Key currentKey = mCurrentKey;        mCurrentKey = null;        final int currentRepeatingKeyCode = mCurrentRepeatingKeyCode;        mCurrentRepeatingKeyCode = Constants.NOT_A_CODE;        // Release the last pressed key.        setReleasedKeyGraphics(currentKey);        if (isShowingMoreKeysPanel()) {            if (!mIsTrackingForActionDisabled) {                final int translatedX = mMoreKeysPanel.translateX(x);                final int translatedY = mMoreKeysPanel.translateY(y);                mMoreKeysPanel.onUpEvent(translatedX, translatedY, mPointerId, eventTime);            }            dismissMoreKeysPanel();            return;        }        if (sInGesture) {            if (currentKey != null) {                callListenerOnRelease(currentKey, currentKey.getCode(), true /* withSliding */);            }            if (mBatchInputArbiter.mayEndBatchInput(                    eventTime, getActivePointerTrackerCount(), this)) {                sInGesture = false;            }            showGestureTrail();            return;        }        if (mIsTrackingForActionDisabled) {            return;        }        if (currentKey != null && currentKey.isRepeatable()                && (currentKey.getCode() == currentRepeatingKeyCode) && !isInDraggingFinger) {            return;        }        detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime);        if (isInSlidingKeyInput) {            callListenerOnFinishSlidingInput();        }    }

而这两个方法中分别有setPressedKeyGraphics(key, eventTime);和setReleasedKeyGraphics(currentKey);两个方法通过DrawingProxy接口传到MainKeyboardView.java,

然后由MainKeyboardView.java画出触摸按下去和释放在键盘上的显示效果

onDownEventInternal中的

if (callListenerOnPressAndCheckKeyboardLayoutChange(key, 0 /* repeatCount */)) {
                key = onDownKey(x, y, eventTime);
            }

是按下大写键后,整个键盘改变大小写状态的

而onUpEventInternal中的detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime);方法调用callListenerOnCodeInput(key, code, x, y, eventTime, false /* isKeyRepeat */);

通过KeyboardActionListener接口将key传到LatinIME.java中的onCodeInput方法中进行处理







0 0
原创粉丝点击