From 6e5a3986854549a45c95770b5a88ae5577e93299 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Fri, 24 Sep 2010 20:45:24 +0900 Subject: [PATCH] Fixed key code and key coordinates when move debounce has been in action This change refactors a key index and pointer position variables into a separate static inner class KeyState . This change also disables time debouncing. Bug: 3033737 Change-Id: Ie4fc37316c260330d8f0861e0771ea903a99cfce --- .../inputmethod/latin/PointerTracker.java | 248 +++++++++--------- 1 file changed, 129 insertions(+), 119 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/PointerTracker.java b/java/src/com/android/inputmethod/latin/PointerTracker.java index cb717cbe7..b56974ccf 100644 --- a/java/src/com/android/inputmethod/latin/PointerTracker.java +++ b/java/src/com/android/inputmethod/latin/PointerTracker.java @@ -42,7 +42,6 @@ public class PointerTracker { /* package */ static final int REPEAT_INTERVAL = 50; // ~20 keys per second private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); private static final int MULTITAP_INTERVAL = 800; // milliseconds - private static final int KEY_DEBOUNCE_TIME = 70; // Miscellaneous constants private static final int NOT_A_KEY = LatinKeyboardBaseView.NOT_A_KEY; @@ -57,10 +56,7 @@ public class PointerTracker { private Key[] mKeys; private int mKeyHysteresisDistanceSquared = -1; - private int mCurrentKey = NOT_A_KEY; - private int mStartX; - private int mStartY; - private long mDownTime; + private final KeyState mKeyState; // true if event is already translated to a key action (long press or mini-keyboard) private boolean mKeyAlreadyProcessed; @@ -68,18 +64,6 @@ public class PointerTracker { // true if this pointer is repeatable key private boolean mIsRepeatableKey; - // for move de-bouncing - private int mLastCodeX; - private int mLastCodeY; - private int mLastX; - private int mLastY; - - // for time de-bouncing - private int mLastKey; - private long mLastKeyTime; - private long mLastMoveTime; - private long mCurrentKeyTime; - // For multi-tap private int mLastSentIndex; private int mTapCount; @@ -90,6 +74,95 @@ public class PointerTracker { // pressed key private int mPreviousKey = NOT_A_KEY; + // This class keeps track of a key index and a position where this pointer is. + private static class KeyState { + private final KeyDetector mKeyDetector; + + // The position and time at which first down event occurred. + private int mStartX; + private int mStartY; + private long mDownTime; + + // The current key index where this pointer is. + private int mKeyIndex = NOT_A_KEY; + // The position where mKeyIndex was recognized for the first time. + private int mKeyX; + private int mKeyY; + + // Last pointer position. + private int mLastX; + private int mLastY; + + public KeyState(KeyDetector keyDetecor) { + mKeyDetector = keyDetecor; + } + + public int getKeyIndex() { + return mKeyIndex; + } + + public int getKeyX() { + return mKeyX; + } + + public int getKeyY() { + return mKeyY; + } + + public int getStartX() { + return mStartX; + } + + public int getStartY() { + return mStartY; + } + + public long getDownTime() { + return mDownTime; + } + + public int getLastX() { + return mLastX; + } + + public int getLastY() { + return mLastY; + } + + public int onDownKey(int x, int y, long eventTime) { + mStartX = x; + mStartY = y; + mDownTime = eventTime; + + return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); + } + + private int onMoveKeyInternal(int x, int y) { + mLastX = x; + mLastY = y; + return mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); + } + + public int onMoveKey(int x, int y) { + return onMoveKeyInternal(x, y); + } + + public int onMoveToNewKey(int keyIndex, int x, int y) { + mKeyIndex = keyIndex; + mKeyX = x; + mKeyY = y; + return keyIndex; + } + + public int onUpKey(int x, int y) { + return onMoveKeyInternal(x, y); + } + + public void onSetKeyboard() { + mKeyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(mKeyX, mKeyY, null); + } + } + public PointerTracker(int id, UIHandler handler, KeyDetector keyDetector, UIProxy proxy, boolean hasDistinctMultitouch) { if (proxy == null || handler == null || keyDetector == null) @@ -98,6 +171,7 @@ public class PointerTracker { mProxy = proxy; mHandler = handler; mKeyDetector = keyDetector; + mKeyState = new KeyState(keyDetector); mHasDistinctMultitouch = hasDistinctMultitouch; resetMultiTap(); } @@ -112,7 +186,7 @@ public class PointerTracker { mKeys = keys; mKeyHysteresisDistanceSquared = (int)(keyHysteresisDistance * keyHysteresisDistance); // Update current key index because keyboard layout has been changed. - mCurrentKey = mKeyDetector.getKeyIndexAndNearbyCodes(mStartX, mStartY, null); + mKeyState.onSetKeyboard(); } private boolean isValidKeyIndex(int keyIndex) { @@ -133,7 +207,7 @@ public class PointerTracker { } public boolean isModifier() { - return isModifierInternal(mCurrentKey); + return isModifierInternal(mKeyState.getKeyIndex()); } public boolean isOnModifierKey(int x, int y) { @@ -190,21 +264,16 @@ public class PointerTracker { public void onDownEvent(int x, int y, long eventTime) { if (DEBUG) debugLog("onDownEvent:", x, y); - int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); - mCurrentKey = keyIndex; - mStartX = x; - mStartY = y; - mDownTime = eventTime; + int keyIndex = mKeyState.onDownKey(x, y, eventTime); mKeyAlreadyProcessed = false; mIsRepeatableKey = false; - startMoveDebouncing(x, y); - startTimeDebouncing(eventTime); checkMultiTap(eventTime, keyIndex); if (mListener != null) { int primaryCode = isValidKeyIndex(keyIndex) ? mKeys[keyIndex].codes[0] : 0; mListener.onPress(primaryCode); - // This onPress call may have changed keyboard layout and have updated mCurrentKey - keyIndex = mCurrentKey; + // This onPress call may have changed keyboard layout and have updated mKeyIndex. + // If that's the case, mKeyIndex has been updated in setKeyboard(). + keyIndex = mKeyState.getKeyIndex(); } if (isValidKeyIndex(keyIndex)) { if (mKeys[keyIndex].repeatable) { @@ -215,7 +284,6 @@ public class PointerTracker { mHandler.startLongPressTimer(LONGPRESS_TIMEOUT, keyIndex, this); } showKeyPreviewAndUpdateKey(keyIndex); - updateMoveDebouncing(x, y); } public void onMoveEvent(int x, int y, long eventTime) { @@ -223,44 +291,28 @@ public class PointerTracker { debugLog("onMoveEvent:", x, y); if (mKeyAlreadyProcessed) return; - int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); + KeyState keyState = mKeyState; + int keyIndex = keyState.onMoveKey(x, y); if (isValidKeyIndex(keyIndex)) { - if (mCurrentKey == NOT_A_KEY) { - updateTimeDebouncing(eventTime); - mCurrentKey = keyIndex; + if (keyState.getKeyIndex() == NOT_A_KEY) { + keyState.onMoveToNewKey(keyIndex, x, y); mHandler.startLongPressTimer(LONGPRESS_TIMEOUT, keyIndex, this); - } else if (isMinorMoveBounce(x, y, keyIndex, mCurrentKey)) { - updateTimeDebouncing(eventTime); - } else { + } else if (!isMinorMoveBounce(x, y, keyIndex)) { resetMultiTap(); - resetTimeDebouncing(eventTime, mCurrentKey); - resetMoveDebouncing(); - mCurrentKey = keyIndex; + keyState.onMoveToNewKey(keyIndex, x, y); mHandler.startLongPressTimer(LONGPRESS_TIMEOUT, keyIndex, this); } } else { - if (mCurrentKey != NOT_A_KEY) { - updateTimeDebouncing(eventTime); - mCurrentKey = keyIndex; + if (keyState.getKeyIndex() != NOT_A_KEY) { + keyState.onMoveToNewKey(keyIndex, x ,y); mHandler.cancelLongPressTimer(); - } else if (isMinorMoveBounce(x, y, keyIndex, mCurrentKey)) { - updateTimeDebouncing(eventTime); - } else { + } else if (!isMinorMoveBounce(x, y, keyIndex)) { resetMultiTap(); - resetTimeDebouncing(eventTime, mCurrentKey); - resetMoveDebouncing(); - mCurrentKey = keyIndex; + keyState.onMoveToNewKey(keyIndex, x ,y); mHandler.cancelLongPressTimer(); } } - /* - * While time debouncing is in effect, mCurrentKey holds the new key and this tracker - * holds the last key. At ACTION_UP event if time debouncing will be in effect - * eventually, the last key should be sent as the result. In such case mCurrentKey - * should not be showed as popup preview. - */ - showKeyPreviewAndUpdateKey(isMinorTimeBounce() ? mLastKey : mCurrentKey); - updateMoveDebouncing(x, y); + showKeyPreviewAndUpdateKey(mKeyState.getKeyIndex()); } public void onUpEvent(int x, int y, long eventTime) { @@ -270,23 +322,18 @@ public class PointerTracker { return; mHandler.cancelKeyTimers(); mHandler.cancelPopupPreview(); - int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); - if (isMinorMoveBounce(x, y, keyIndex, mCurrentKey)) { - updateTimeDebouncing(eventTime); - } else { - resetMultiTap(); - resetTimeDebouncing(eventTime, mCurrentKey); - mCurrentKey = keyIndex; - } - if (isMinorTimeBounce()) { - mCurrentKey = mLastKey; - x = mLastCodeX; - y = mLastCodeY; + int keyIndex = mKeyState.onUpKey(x, y); + if (isMinorMoveBounce(x, y, keyIndex)) { + // Use previous fixed key index and coordinates. + keyIndex = mKeyState.getKeyIndex(); + x = mKeyState.getKeyX(); + y = mKeyState.getKeyY(); } showKeyPreviewAndUpdateKey(NOT_A_KEY); if (!mIsRepeatableKey) { - detectAndSendKey(mCurrentKey, x, y, eventTime); + detectAndSendKey(keyIndex, x, y, eventTime); } + if (isValidKeyIndex(keyIndex)) mProxy.invalidateKey(mKeys[keyIndex]); } @@ -297,7 +344,7 @@ public class PointerTracker { mHandler.cancelKeyTimers(); mHandler.cancelPopupPreview(); showKeyPreviewAndUpdateKey(NOT_A_KEY); - int keyIndex = mCurrentKey; + int keyIndex = mKeyState.getKeyIndex(); if (isValidKeyIndex(keyIndex)) mProxy.invalidateKey(mKeys[keyIndex]); } @@ -312,44 +359,30 @@ public class PointerTracker { } public int getLastX() { - return mLastX; + return mKeyState.getLastX(); } public int getLastY() { - return mLastY; + return mKeyState.getLastY(); } public long getDownTime() { - return mDownTime; + return mKeyState.getDownTime(); } // These package scope methods are only for debugging purpose. /* package */ int getStartX() { - return mStartX; + return mKeyState.getStartX(); } /* package */ int getStartY() { - return mStartY; + return mKeyState.getStartY(); } - private void startMoveDebouncing(int x, int y) { - mLastCodeX = x; - mLastCodeY = y; - } - - private void updateMoveDebouncing(int x, int y) { - mLastX = x; - mLastY = y; - } - - private void resetMoveDebouncing() { - mLastCodeX = mLastX; - mLastCodeY = mLastY; - } - - private boolean isMinorMoveBounce(int x, int y, int newKey, int curKey) { + private boolean isMinorMoveBounce(int x, int y, int newKey) { if (mKeys == null || mKeyHysteresisDistanceSquared < 0) throw new IllegalStateException("keyboard and/or hysteresis not set"); + int curKey = mKeyState.getKeyIndex(); if (newKey == curKey) { return true; } else if (isValidKeyIndex(curKey)) { @@ -371,30 +404,6 @@ public class PointerTracker { return dx * dx + dy * dy; } - private void startTimeDebouncing(long eventTime) { - mLastKey = NOT_A_KEY; - mLastKeyTime = 0; - mCurrentKeyTime = 0; - mLastMoveTime = eventTime; - } - - private void updateTimeDebouncing(long eventTime) { - mCurrentKeyTime += eventTime - mLastMoveTime; - mLastMoveTime = eventTime; - } - - private void resetTimeDebouncing(long eventTime, int currentKey) { - mLastKey = currentKey; - mLastKeyTime = mCurrentKeyTime + eventTime - mLastMoveTime; - mCurrentKeyTime = 0; - mLastMoveTime = eventTime; - } - - private boolean isMinorTimeBounce() { - return mCurrentKeyTime < mLastKeyTime && mCurrentKeyTime < KEY_DEBOUNCE_TIME - && mLastKey != NOT_A_KEY; - } - private void showKeyPreviewAndUpdateKey(int keyIndex) { updateKey(keyIndex); // The modifier key, such as shift key, should not be shown as preview when multi-touch is @@ -497,7 +506,8 @@ public class PointerTracker { } private void debugLog(String title, int x, int y) { - Key key = getKey(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null)); + int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); + Key key = getKey(keyIndex); final String code; if (key == null) { code = "----"; @@ -505,7 +515,7 @@ public class PointerTracker { int primaryCode = key.codes[0]; code = String.format((primaryCode < 0) ? "%4d" : "0x%02x", primaryCode); } - Log.d(TAG, String.format("%s [%d] %3d,%3d %s %s", title, mPointerId, x, y, code, - isModifier() ? "modifier" : "")); + Log.d(TAG, String.format("%s [%d] %3d,%3d %3d(%s) %s", title, mPointerId, x, y, keyIndex, + code, isModifier() ? "modifier" : "")); } -} \ No newline at end of file +}