diff options
Diffstat (limited to 'java/src')
5 files changed, 127 insertions, 40 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 8627508e5..55041154d 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -57,6 +57,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private LatinKeyboardView mInputView; private LatinIME mInputMethodService; + // TODO: Combine these key state objects with auto mode switch state. private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift"); private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol"); @@ -75,13 +76,17 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private boolean mVoiceKeyEnabled; private boolean mVoiceButtonOnPrimary; - private static final int AUTO_MODE_SWITCH_STATE_ALPHA = 0; - private static final int AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN = 1; - private static final int AUTO_MODE_SWITCH_STATE_SYMBOL = 2; + // TODO: Encapsulate these state handling to separate class and combine with ShiftKeyState + // and ModifierKeyState. + private static final int SWITCH_STATE_ALPHA = 0; + private static final int SWITCH_STATE_SYMBOL_BEGIN = 1; + private static final int SWITCH_STATE_SYMBOL = 2; // The following states are used only on the distinct multi-touch panel devices. - private static final int AUTO_MODE_SWITCH_STATE_MOMENTARY = 3; - private static final int AUTO_MODE_SWITCH_STATE_CHORDING = 4; - private int mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; + private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3; + private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4; + private static final int SWITCH_STATE_CHORDING_ALPHA = 5; + private static final int SWITCH_STATE_CHORDING_SYMBOL = 6; + private int mSwitchState = SWITCH_STATE_ALPHA; // Indicates whether or not we have the settings key in option of settings private boolean mSettingsKeyEnabledInSettings; @@ -124,7 +129,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha public void loadKeyboard(EditorInfo attribute, boolean voiceKeyEnabled, boolean voiceButtonOnPrimary) { - mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; + mSwitchState = SWITCH_STATE_ALPHA; try { loadKeyboardInternal(attribute, voiceKeyEnabled, voiceButtonOnPrimary, false); } catch (RuntimeException e) { @@ -466,6 +471,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha // In symbol mode, just toggle symbol and symbol more keyboard. shiftKeyState.onPress(); toggleShift(); + mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE; } } @@ -487,6 +493,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } else if (isShiftLocked() && !shiftKeyState.isIgnoring() && !withSliding) { // Shift has been pressed without chording while caps lock state. toggleCapsLock(); + // To be able to turn off caps lock by "double tap" on shift key, we should ignore + // the second tap of the "double tap" from now for a while because we just have + // already turned off caps lock above. + mInputView.startIgnoringDoubleTap(); } else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted() && !withSliding) { // Shift has been pressed without chording while shifted state. @@ -497,6 +507,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha // transited from automatic temporary upper case. toggleShift(); } + } else { + // In symbol mode, snap back to the previous keyboard mode if the user chords the shift + // key and another key, then releases the shift key. + if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) { + toggleShift(); + } } shiftKeyState.onRelease(); } @@ -511,7 +527,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha + " symbolKeyState=" + mSymbolKeyState); changeKeyboardMode(); mSymbolKeyState.onPress(); - mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_MOMENTARY; + mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL; } public void onReleaseSymbol() { @@ -523,9 +539,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() + " symbolKeyState=" + mSymbolKeyState); // Snap back to the previous keyboard mode if the user chords the mode change key and - // other key, then released the mode change key. - if (mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_CHORDING) + // another key, then releases the mode change key. + if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) { changeKeyboardMode(); + } mSymbolKeyState.onRelease(); } @@ -544,8 +561,13 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha public void onCancelInput() { // Snap back to the previous keyboard mode if the user cancels sliding input. - if (mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY && getPointerCount() == 1) - changeKeyboardMode(); + if (getPointerCount() == 1) { + if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) { + changeKeyboardMode(); + } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) { + toggleShift(); + } + } } private void toggleShiftInSymbol() { @@ -568,8 +590,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha setKeyboard(keyboard); } - public boolean isInMomentaryAutoModeSwitchState() { - return mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY; + public boolean isInMomentarySwitchState() { + return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL + || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE; } public boolean isVibrateAndSoundFeedbackRequired() { @@ -583,9 +606,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private void toggleKeyboardMode() { loadKeyboardInternal(mAttribute, mVoiceKeyEnabled, mVoiceButtonOnPrimary, !mIsSymbols); if (mIsSymbols) { - mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN; + mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; } else { - mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; + mSwitchState = SWITCH_STATE_ALPHA; } } @@ -597,28 +620,52 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha return mInputView != null && mInputView.hasDistinctMultitouch(); } + private static boolean isSpaceCharacter(int c) { + return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER; + } + + private static boolean isQuoteCharacter(int c) { + // Apostrophe, quotation mark. + if (c == '\'' || c == '"') + return true; + // \u2018: Left single quotation mark + // \u2019: Right single quotation mark + // \u201a: Single low-9 quotation mark + // \u201b: Single high-reversed-9 quotation mark + // \u201c: Left double quotation mark + // \u201d: Right double quotation mark + // \u201e: Double low-9 quotation mark + // \u201f: Double high-reversed-9 quotation mark + if (c >= '\u2018' && c <= '\u201f') + return true; + // \u00ab: Left-pointing double angle quotation mark + // \u00bb: Right-pointing double angle quotation mark + if (c == '\u00ab' || c == '\u00bb') + return true; + return false; + } + /** * Updates state machine to figure out when to automatically snap back to the previous mode. */ - public void onKey(int key) { + public void onKey(int code) { if (DEBUG_STATE) - Log.d(TAG, "onKey: code=" + key + " autoModeSwitchState=" + mAutoModeSwitchState + Log.d(TAG, "onKey: code=" + code + " switchState=" + mSwitchState + " pointers=" + getPointerCount()); - switch (mAutoModeSwitchState) { - case AUTO_MODE_SWITCH_STATE_MOMENTARY: + switch (mSwitchState) { + case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: // Only distinct multi touch devices can be in this state. // On non-distinct multi touch devices, mode change key is handled by // {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and - // {@link LatinIME#onRelease}. So, on such devices, {@link #mAutoModeSwitchState} starts - // from {@link #AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN}, or - // {@link #AUTO_MODE_SWITCH_STATE_ALPHA}, not from - // {@link #AUTO_MODE_SWITCH_STATE_MOMENTARY}. - if (key == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { + // {@link LatinIME#onRelease}. So, on such devices, {@link #mSwitchState} starts + // from {@link #SWITCH_STATE_SYMBOL_BEGIN}, or {@link #SWITCH_STATE_ALPHA}, not from + // {@link #SWITCH_STATE_MOMENTARY}. + if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { // Detected only the mode change key has been pressed, and then released. if (mIsSymbols) { - mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN; + mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; } else { - mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; + mSwitchState = SWITCH_STATE_ALPHA; } } else if (getPointerCount() == 1) { // Snap back to the previous keyboard mode if the user pressed the mode change key @@ -629,18 +676,34 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } else { // Chording input is being started. The keyboard mode will be snapped back to the // previous mode in {@link onReleaseSymbol} when the mode change key is released. - mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_CHORDING; + mSwitchState = SWITCH_STATE_CHORDING_ALPHA; + } + break; + case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE: + if (code == Keyboard.CODE_SHIFT) { + // Detected only the shift key has been pressed on symbol layout, and then released. + mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; + } else if (getPointerCount() == 1) { + // Snap back to the previous keyboard mode if the user pressed the shift key on + // symbol mode and slid to other key, then released the finger. + toggleShift(); + mSwitchState = SWITCH_STATE_SYMBOL; + } else { + // Chording input is being started. The keyboard mode will be snapped back to the + // previous mode in {@link onReleaseShift} when the shift key is released. + mSwitchState = SWITCH_STATE_CHORDING_SYMBOL; } break; - case AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN: - if (key != Keyboard.CODE_SPACE && key != Keyboard.CODE_ENTER && key >= 0) { - mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL; + case SWITCH_STATE_SYMBOL_BEGIN: + if (!isSpaceCharacter(code) && code >= 0) { + mSwitchState = SWITCH_STATE_SYMBOL; } break; - case AUTO_MODE_SWITCH_STATE_SYMBOL: + case SWITCH_STATE_SYMBOL: + case SWITCH_STATE_CHORDING_SYMBOL: // Snap back to alpha keyboard mode if user types one or more non-space/enter - // characters followed by a space/enter. - if (key == Keyboard.CODE_ENTER || key == Keyboard.CODE_SPACE) { + // characters followed by a space/enter or quotation mark. + if (isSpaceCharacter(code) || isQuoteCharacter(code)) { changeKeyboardMode(); } break; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index c36895258..11476e069 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -44,6 +44,7 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.LinearLayout; @@ -73,7 +74,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { private static final boolean DEBUG_SHOW_ALIGN = false; private static final boolean DEBUG_KEYBOARD_GRID = false; - private static final boolean ENABLE_CAPSLOCK_BY_LONGPRESS = false; + private static final boolean ENABLE_CAPSLOCK_BY_LONGPRESS = true; private static final boolean ENABLE_CAPSLOCK_BY_DOUBLETAP = true; public static final int COLOR_SCHEME_WHITE = 0; @@ -189,6 +190,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { private static final int MSG_REPEAT_KEY = 3; private static final int MSG_LONGPRESS_KEY = 4; private static final int MSG_LONGPRESS_SHIFT_KEY = 5; + private static final int MSG_IGNORE_DOUBLE_TAP = 6; private boolean mInKeyRepeat; @@ -286,6 +288,16 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { public void cancelKeyTimers() { cancelKeyRepeatTimer(); cancelLongPressTimers(); + removeMessages(MSG_IGNORE_DOUBLE_TAP); + } + + public void startIgnoringDoubleTap() { + sendMessageDelayed(obtainMessage(MSG_IGNORE_DOUBLE_TAP), + ViewConfiguration.getDoubleTapTimeout()); + } + + public boolean isIgnoringDoubleTap() { + return hasMessages(MSG_IGNORE_DOUBLE_TAP); } public void cancelAllMessages() { @@ -449,7 +461,12 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { final PointerTracker tracker = getPointerTracker(id); // If the second down event is also on shift key. if (tracker.isOnShiftKey((int)secondDown.getX(), (int)secondDown.getY())) { - onDoubleTapShiftKey(tracker); + // Detected a double tap on shift key. If we are in the ignoring double tap + // mode, it means we have already turned off caps lock in + // {@link KeyboardSwitcher#onReleaseShift} . + final boolean ignoringDoubleTap = mHandler.isIgnoringDoubleTap(); + if (!ignoringDoubleTap) + onDoubleTapShiftKey(tracker); return true; } // Otherwise these events should not be handled as double tap. @@ -468,6 +485,11 @@ public class KeyboardView extends View implements PointerTracker.UIProxy { mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval); } + public void startIgnoringDoubleTap() { + if (ENABLE_CAPSLOCK_BY_DOUBLETAP) + mHandler.startIgnoringDoubleTap(); + } + public void setOnKeyboardActionListener(KeyboardActionListener listener) { mKeyboardActionListener = listener; for (PointerTracker tracker : mPointerTrackers) { diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index e3161f610..abd1ef286 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -662,7 +662,7 @@ public class PointerTracker { // We need not start long press timer on the key which has manual temporary upper case // code defined and the keyboard is in manual temporary upper case mode. return; - } else if (mKeyboardSwitcher.isInMomentaryAutoModeSwitchState()) { + } else if (mKeyboardSwitcher.isInMomentarySwitchState()) { // We use longer timeout for sliding finger input started from the symbols mode key. mHandler.startLongPressTimer(mLongPressKeyTimeout * 3, keyIndex, this); } else { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 175467fcb..39bc78e20 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -112,7 +112,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private static final int DELAY_UPDATE_SUGGESTIONS = 180; private static final int DELAY_UPDATE_OLD_SUGGESTIONS = 300; - private static final int DELAY_UPDATE_SHIFT_STATE = 300; + private static final int DELAY_UPDATE_SHIFT_STATE = 100; private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100; // How many continuous deletes at which to start deleting at a higher speed. diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 9d7b98410..d165de32d 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -50,6 +50,7 @@ public class Utils { private static final String TAG = Utils.class.getSimpleName(); private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4; private static boolean DBG = LatinImeLogger.sDBG; + private static boolean DBG_EDIT_DISTANCE = false; private Utils() { // Intentional empty constructor for utility class. @@ -291,7 +292,7 @@ public class Utils { } } } - if (LatinImeLogger.sDBG) { + if (DBG_EDIT_DISTANCE) { Log.d(TAG, "editDistance:" + s + "," + t); for (int i = 0; i < dp.length; ++i) { StringBuffer sb = new StringBuffer(); @@ -340,6 +341,7 @@ public class Utils { private static final int MAX_INITIAL_SCORE = 255; private static final int TYPED_LETTER_MULTIPLIER = 2; private static final int FULL_WORD_MULTIPLIER = 2; + private static final int S_INT_MAX = 2147483647; public static double calcNormalizedScore(CharSequence before, CharSequence after, int score) { final int beforeLength = before.length(); final int afterLength = after.length(); @@ -354,7 +356,7 @@ public class Utils { } } if (spaceCount == afterLength) return 0; - final double maximumScore = MAX_INITIAL_SCORE + final double maximumScore = score == S_INT_MAX ? S_INT_MAX : MAX_INITIAL_SCORE * Math.pow( TYPED_LETTER_MULTIPLIER, Math.min(beforeLength, afterLength - spaceCount)) * FULL_WORD_MULTIPLIER; |