diff options
Diffstat (limited to 'java')
5 files changed, 169 insertions, 120 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index cb80d052e..1398bae2a 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -216,37 +216,53 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, return null; } - // Implements {@link KeyboardState.SwitchActions}. - @Override - public void setShifted(int shiftMode) { + /** + * Update keyboard shift state triggered by connected EditText status change. + */ + public void updateShiftState() { + mState.onUpdateShiftState(mInputMethodService.getCurrentAutoCapsState()); + } + + public void onPressKey(int code) { + mState.onPressKey(code); + } + + public void onReleaseKey(int code, boolean withSliding) { + mState.onReleaseKey(code, withSliding); + } + + public void onCancelInput() { + mState.onCancelInput(isSinglePointer()); + } + + // TODO: Remove these constants. + private static final int ALPHABET_UNSHIFTED = 0; + private static final int ALPHABET_MANUAL_SHIFTED = 1; + private static final int ALPHABET_AUTOMATIC_SHIFTED = 2; + private static final int ALPHABET_SHIFT_LOCKED = 3; + + // TODO: Remove this method. + private void updateAlphabetKeyboardShiftState(int shiftMode) { mInputMethodService.mHandler.cancelUpdateShiftState(); Keyboard keyboard = getKeyboard(); if (keyboard == null) return; switch (shiftMode) { - case AUTOMATIC_SHIFT: - keyboard.setAutomaticTemporaryUpperCase(); + case ALPHABET_UNSHIFTED: + keyboard.setShifted(false); break; - case MANUAL_SHIFT: + case ALPHABET_MANUAL_SHIFTED: keyboard.setShifted(true); break; - case UNSHIFT: - keyboard.setShifted(false); + case ALPHABET_AUTOMATIC_SHIFTED: + keyboard.setAutomaticTemporaryUpperCase(); + break; + case ALPHABET_SHIFT_LOCKED: + keyboard.setShiftLocked(true); break; } mKeyboardView.invalidateAllKeys(); - } - - // Implements {@link KeyboardState.SwitchActions}. - @Override - public void setShiftLocked(boolean shiftLocked) { - mInputMethodService.mHandler.cancelUpdateShiftState(); - Keyboard keyboard = getKeyboard(); - if (keyboard == null) - return; - keyboard.setShiftLocked(shiftLocked); - mKeyboardView.invalidateAllKeys(); - if (!shiftLocked) { + if (shiftMode != ALPHABET_SHIFT_LOCKED) { // 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. @@ -254,35 +270,38 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, } } - /** - * Update keyboard shift state triggered by connected EditText status change. - */ - public void updateShiftState() { - mState.onUpdateShiftState(mInputMethodService.getCurrentAutoCapsState()); - } - - public void onPressKey(int code) { - mState.onPressKey(code); + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void setAlphabetKeyboard() { + setKeyboard(mKeyboardSet.getMainKeyboard()); + updateAlphabetKeyboardShiftState(ALPHABET_UNSHIFTED); } - public void onReleaseKey(int code, boolean withSliding) { - mState.onReleaseKey(code, withSliding); + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void setAlphabetManualShiftedKeyboard() { + setKeyboard(mKeyboardSet.getMainKeyboard()); + updateAlphabetKeyboardShiftState(ALPHABET_MANUAL_SHIFTED); } - public void onCancelInput() { - mState.onCancelInput(isSinglePointer()); + // Implements {@link KeyboardState.SwitchActions}. + @Override + public void setAlphabetAutomaticShiftedKeyboard() { + setKeyboard(mKeyboardSet.getMainKeyboard()); + updateAlphabetKeyboardShiftState(ALPHABET_AUTOMATIC_SHIFTED); } // Implements {@link KeyboardState.SwitchActions}. @Override - public void setSymbolsKeyboard() { - setKeyboard(mKeyboardSet.getSymbolsKeyboard()); + public void setAlphabetShiftLockedKeyboard() { + setKeyboard(mKeyboardSet.getMainKeyboard()); + updateAlphabetKeyboardShiftState(ALPHABET_SHIFT_LOCKED); } // Implements {@link KeyboardState.SwitchActions}. @Override - public void setAlphabetKeyboard() { - setKeyboard(mKeyboardSet.getMainKeyboard()); + public void setSymbolsKeyboard() { + setKeyboard(mKeyboardSet.getSymbolsKeyboard()); } // Implements {@link KeyboardState.SwitchActions}. diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java index babf600a6..bc8b7e3f7 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -40,16 +40,10 @@ public class KeyboardState { public interface SwitchActions { public void setAlphabetKeyboard(); - - public static final int UNSHIFT = 0; - public static final int MANUAL_SHIFT = 1; - public static final int AUTOMATIC_SHIFT = 2; - public void setShifted(int shiftMode); - - public void setShiftLocked(boolean shiftLocked); - + public void setAlphabetManualShiftedKeyboard(); + public void setAlphabetAutomaticShiftedKeyboard(); + public void setAlphabetShiftLockedKeyboard(); public void setSymbolsKeyboard(); - public void setSymbolsShiftedKeyboard(); /** @@ -63,14 +57,14 @@ public class KeyboardState { private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift"); private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol"); + // TODO: Merge {@link #mSwitchState}, {@link #mIsAlphabetMode}, {@link #mAlphabetShiftState}, + // {@link #mIsSymbolShifted}, {@link #mPrevMainKeyboardWasShiftLocked}, and + // {@link #mPrevSymbolsKeyboardWasShifted} into single state variable. 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 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; private String mLayoutSwitchBackSymbols; @@ -88,6 +82,7 @@ public class KeyboardState { public boolean mIsShiftLocked; public boolean mIsShifted; + @Override public String toString() { if (!mIsValid) return "INVALID"; if (mIsAlphabetMode) { @@ -155,7 +150,7 @@ public class KeyboardState { if (state.mIsAlphabetMode) { setShiftLocked(state.mIsShiftLocked); if (!state.mIsShiftLocked) { - setShifted(state.mIsShifted ? SwitchActions.MANUAL_SHIFT : SwitchActions.UNSHIFT); + setShifted(state.mIsShifted ? MANUAL_SHIFT : UNSHIFT); } } } @@ -165,30 +160,58 @@ public class KeyboardState { return mAlphabetShiftState.isShiftLocked(); } + private static final int UNSHIFT = 0; + private static final int MANUAL_SHIFT = 1; + private static final int AUTOMATIC_SHIFT = 2; + private void setShifted(int shiftMode) { if (DEBUG_ACTION) { - Log.d(TAG, "setShifted: shiftMode=" + shiftModeToString(shiftMode)); + Log.d(TAG, "setShifted: shiftMode=" + shiftModeToString(shiftMode) + " " + this); + } + if (!mIsAlphabetMode) return; + final int prevShiftMode; + if (mAlphabetShiftState.isAutomaticTemporaryUpperCase()) { + prevShiftMode = AUTOMATIC_SHIFT; + } else if (mAlphabetShiftState.isManualTemporaryUpperCase()) { + prevShiftMode = MANUAL_SHIFT; + } else { + prevShiftMode = UNSHIFT; } switch (shiftMode) { - case SwitchActions.AUTOMATIC_SHIFT: + case AUTOMATIC_SHIFT: mAlphabetShiftState.setAutomaticTemporaryUpperCase(); + if (shiftMode != prevShiftMode) { + mSwitchActions.setAlphabetAutomaticShiftedKeyboard(); + } break; - case SwitchActions.MANUAL_SHIFT: + case MANUAL_SHIFT: mAlphabetShiftState.setShifted(true); + if (shiftMode != prevShiftMode) { + mSwitchActions.setAlphabetManualShiftedKeyboard(); + } break; - case SwitchActions.UNSHIFT: + case UNSHIFT: mAlphabetShiftState.setShifted(false); + if (shiftMode != prevShiftMode) { + mSwitchActions.setAlphabetKeyboard(); + } break; } - mSwitchActions.setShifted(shiftMode); } private void setShiftLocked(boolean shiftLocked) { if (DEBUG_ACTION) { - Log.d(TAG, "setShiftLocked: shiftLocked=" + shiftLocked); + Log.d(TAG, "setShiftLocked: shiftLocked=" + shiftLocked + " " + this); + } + if (!mIsAlphabetMode) return; + if (shiftLocked && (!mAlphabetShiftState.isShiftLocked() + || mAlphabetShiftState.isShiftLockShifted())) { + mSwitchActions.setAlphabetShiftLockedKeyboard(); + } + if (!shiftLocked && mAlphabetShiftState.isShiftLocked()) { + mSwitchActions.setAlphabetKeyboard(); } mAlphabetShiftState.setShiftLocked(shiftLocked); - mSwitchActions.setShiftLocked(shiftLocked); } private void toggleAlphabetAndSymbols() { @@ -276,8 +299,7 @@ public class KeyboardState { if (code == Keyboard.CODE_SHIFT) { onReleaseShift(withSliding); } else if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { - // TODO: Make use of withSliding instead of relying on mSwitchState. - onReleaseSymbol(); + onReleaseSymbol(withSliding); } } @@ -287,11 +309,16 @@ public class KeyboardState { mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL; } - private void onReleaseSymbol() { - // Switch back to the previous keyboard mode if the user chords the mode change key and - // another key, then releases the mode change key. - if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) { + private void onReleaseSymbol(boolean withSliding) { + if (mSymbolKeyState.isChording()) { + // Switch back to the previous keyboard mode if the user chords the mode change key and + // another key, then releases the mode change key. toggleAlphabetAndSymbols(); + } else if (!withSliding) { + // If the mode change key is being released without sliding, we should forget the + // previous symbols keyboard shift state and simply switch back to symbols layout + // (never symbols shifted) next time the mode gets changed to symbols layout. + mPrevSymbolsKeyboardWasShifted = false; } mSymbolKeyState.onRelease(); } @@ -300,24 +327,18 @@ public class KeyboardState { if (DEBUG_EVENT) { Log.d(TAG, "onUpdateShiftState: autoCaps=" + autoCaps + " " + this); } - onUpdateShiftStateInternal(autoCaps); + updateAlphabetShiftState(autoCaps); } - private void onUpdateShiftStateInternal(boolean autoCaps) { - if (mIsAlphabetMode) { - if (!mAlphabetShiftState.isShiftLocked() && !mShiftKeyState.isIgnoring()) { - if (mShiftKeyState.isReleasing() && autoCaps) { - // Only when shift key is releasing, automatic temporary upper case will be set. - setShifted(SwitchActions.AUTOMATIC_SHIFT); - } else { - setShifted(mShiftKeyState.isMomentary() - ? SwitchActions.MANUAL_SHIFT : SwitchActions.UNSHIFT); - } + private void updateAlphabetShiftState(boolean autoCaps) { + if (!mIsAlphabetMode) return; + if (!mAlphabetShiftState.isShiftLocked() && !mShiftKeyState.isIgnoring()) { + if (mShiftKeyState.isReleasing() && autoCaps) { + // Only when shift key is releasing, automatic temporary upper case will be set. + setShifted(AUTOMATIC_SHIFT); + } else { + setShifted(mShiftKeyState.isChording() ? MANUAL_SHIFT : UNSHIFT); } - } else { - // In symbol keyboard mode, we should clear shift key state because only alphabet - // keyboard has shift key. - mSymbolKeyState.onRelease(); } } @@ -326,12 +347,12 @@ public class KeyboardState { if (mAlphabetShiftState.isShiftLocked()) { // Shift key is pressed while caps lock state, we will treat this state as shifted // caps lock state and mark as if shift key pressed while normal state. - setShifted(SwitchActions.MANUAL_SHIFT); + setShifted(MANUAL_SHIFT); mShiftKeyState.onPress(); } else if (mAlphabetShiftState.isAutomaticTemporaryUpperCase()) { // Shift key is pressed while automatic temporary upper case, we have to move to // manual temporary upper case. - setShifted(SwitchActions.MANUAL_SHIFT); + setShifted(MANUAL_SHIFT); mShiftKeyState.onPress(); } else if (mAlphabetShiftState.isShiftedOrShiftLocked()) { // In manual upper case state, we just record shift key has been pressing while @@ -339,7 +360,7 @@ public class KeyboardState { mShiftKeyState.onPressOnShifted(); } else { // In base layout, chording or manual temporary upper case mode is started. - setShifted(SwitchActions.MANUAL_SHIFT); + setShifted(MANUAL_SHIFT); mShiftKeyState.onPress(); } } else { @@ -353,13 +374,17 @@ public class KeyboardState { private void onReleaseShift(boolean withSliding) { if (mIsAlphabetMode) { final boolean isShiftLocked = mAlphabetShiftState.isShiftLocked(); - if (mShiftKeyState.isMomentary()) { - // After chording input while normal state. + if (mShiftKeyState.isChording()) { if (mAlphabetShiftState.isShiftLockShifted()) { + // After chording input while caps lock state. setShiftLocked(true); } else { - setShifted(SwitchActions.UNSHIFT); + // After chording input while normal state. + setShifted(UNSHIFT); } + } else if (mAlphabetShiftState.isShiftLockShifted() && withSliding) { + // In caps lock state, shift has been pressed and slid out to other key. + setShiftLocked(true); } else if (isShiftLocked && !mAlphabetShiftState.isShiftLockShifted() && (mShiftKeyState.isPressing() || mShiftKeyState.isPressingOnShifted()) && !withSliding) { @@ -370,17 +395,17 @@ public class KeyboardState { } else if (mAlphabetShiftState.isShiftedOrShiftLocked() && mShiftKeyState.isPressingOnShifted() && !withSliding) { // Shift has been pressed without chording while shifted state. - setShifted(SwitchActions.UNSHIFT); + setShifted(UNSHIFT); } else if (mAlphabetShiftState.isManualTemporaryUpperCaseFromAuto() && mShiftKeyState.isPressing() && !withSliding) { // Shift has been pressed without chording while manual temporary upper case // transited from automatic temporary upper case. - setShifted(SwitchActions.UNSHIFT); + setShifted(UNSHIFT); } } else { // In symbol mode, switch 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) { + if (mShiftKeyState.isChording()) { toggleShiftInSymbols(); } } @@ -436,12 +461,6 @@ public class KeyboardState { 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 #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 (mIsAlphabetMode) { @@ -455,10 +474,6 @@ public class KeyboardState { // If the user cancels the sliding input, switching back to the previous keyboard // mode is handled by {@link #onCancelInput}. toggleAlphabetAndSymbols(); - } else { - // Chording input is being started. The keyboard mode will be switched back to the - // previous mode in {@link onReleaseSymbol} when the mode change key is released. - mSwitchState = SWITCH_STATE_CHORDING_ALPHA; } break; case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE: @@ -470,10 +485,6 @@ public class KeyboardState { // symbol mode and slid to other key, then released the finger. toggleShiftInSymbols(); mSwitchState = SWITCH_STATE_SYMBOL; - } else { - // Chording input is being started. The keyboard mode will be switched back to the - // previous mode in {@link onReleaseShift} when the shift key is released. - mSwitchState = SWITCH_STATE_CHORDING_SYMBOL; } break; case SWITCH_STATE_SYMBOL_BEGIN: @@ -487,7 +498,6 @@ public class KeyboardState { } break; case SWITCH_STATE_SYMBOL: - case SWITCH_STATE_CHORDING_SYMBOL: // Switch back to alpha keyboard mode if user types one or more non-space/enter // characters followed by a space/enter or a quote character. if (isSpaceCharacter(code) || isLayoutSwitchBackCharacter(code)) { @@ -498,15 +508,15 @@ public class KeyboardState { // If the code is a letter, update keyboard shift state. if (Keyboard.isLetterCode(code)) { - onUpdateShiftStateInternal(autoCaps); + updateAlphabetShiftState(autoCaps); } } private static String shiftModeToString(int shiftMode) { switch (shiftMode) { - case SwitchActions.UNSHIFT: return "UNSHIFT"; - case SwitchActions.MANUAL_SHIFT: return "MANUAL"; - case SwitchActions.AUTOMATIC_SHIFT: return "AUTOMATIC"; + case UNSHIFT: return "UNSHIFT"; + case MANUAL_SHIFT: return "MANUAL"; + case AUTOMATIC_SHIFT: return "AUTOMATIC"; default: return null; } } @@ -518,8 +528,6 @@ public class KeyboardState { case SWITCH_STATE_SYMBOL: return "SYMBOL"; case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: return "MOMENTARY-ALPHA-SYMBOL"; case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE: return "MOMENTARY-SYMBOL-MORE"; - case SWITCH_STATE_CHORDING_ALPHA: return "CHORDING-ALPHA"; - case SWITCH_STATE_CHORDING_SYMBOL: return "CHORDING-SYMBOL"; default: return null; } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java b/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java index f95c91636..b39b97720 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java @@ -19,12 +19,12 @@ package com.android.inputmethod.keyboard.internal; import android.util.Log; /* package */ class ModifierKeyState { - protected static final String TAG = "ModifierKeyState"; + protected static final String TAG = ModifierKeyState.class.getSimpleName(); protected static final boolean DEBUG = false; protected static final int RELEASING = 0; protected static final int PRESSING = 1; - protected static final int MOMENTARY = 2; + protected static final int CHORDING = 2; protected final String mName; protected int mState = RELEASING; @@ -50,7 +50,7 @@ import android.util.Log; public void onOtherKeyPressed() { final int oldState = mState; if (oldState == PRESSING) - mState = MOMENTARY; + mState = CHORDING; if (DEBUG) Log.d(TAG, mName + ".onOtherKeyPressed: " + toString(oldState) + " > " + this); } @@ -63,8 +63,8 @@ import android.util.Log; return mState == RELEASING; } - public boolean isMomentary() { - return mState == MOMENTARY; + public boolean isChording() { + return mState == CHORDING; } @Override @@ -76,7 +76,7 @@ import android.util.Log; switch (state) { case RELEASING: return "RELEASING"; case PRESSING: return "PRESSING"; - case MOMENTARY: return "MOMENTARY"; + case CHORDING: return "CHORDING"; default: return "UNKNOWN"; } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/ShiftKeyState.java b/java/src/com/android/inputmethod/keyboard/internal/ShiftKeyState.java index 6f54b4f23..edb40c8e7 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/ShiftKeyState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/ShiftKeyState.java @@ -30,7 +30,7 @@ import android.util.Log; public void onOtherKeyPressed() { int oldState = mState; if (oldState == PRESSING) { - mState = MOMENTARY; + mState = CHORDING; } else if (oldState == PRESSING_ON_SHIFTED) { mState = IGNORING; } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index a053b9bbb..31cbc4ee3 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -203,9 +203,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private WordComposer mWordComposer = new WordComposer(); private int mCorrectionMode; + // Keep track of the last selection range to decide if we need to show word alternatives - private int mLastSelectionStart; - private int mLastSelectionEnd; + private static final int NOT_A_CURSOR_POSITION = -1; + private int mLastSelectionStart = NOT_A_CURSOR_POSITION; + private int mLastSelectionEnd = NOT_A_CURSOR_POSITION; // Whether we are expecting an onUpdateSelection event to fire. If it does when we don't // "expect" it, it means the user actually moved the cursor. @@ -1401,9 +1403,29 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // inconsistent with backspacing after selecting other suggestions. restartSuggestionsOnManuallyPickedTypedWord(ic); } else { - ic.deleteSurroundingText(1, 0); - if (mDeleteCount > DELETE_ACCELERATE_AT) { - ic.deleteSurroundingText(1, 0); + // Here we must check whether there is a selection. If so we should remove the + // selected text, otherwise we should just delete the character before the cursor. + if (mLastSelectionStart != mLastSelectionEnd) { + final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart; + ic.setSelection(mLastSelectionEnd, mLastSelectionEnd); + ic.deleteSurroundingText(lengthToDelete, 0); + } else { + if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) { + // We don't know whether there is a selection or not. We just send a false + // hardware key event and let TextView sort it out for us. The problem + // here is, this is asynchronous with respect to the input connection + // batch edit, so it may flicker. But this only ever happens if backspace + // is pressed just after the IME is invoked, and then again only once. + // TODO: add an API call that gets the selection indices. This is available + // to the IME in the general case via onUpdateSelection anyway, and would + // allow us to remove this race condition. + sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); + } else { + ic.deleteSurroundingText(1, 0); + } + if (mDeleteCount > DELETE_ACCELERATE_AT) { + ic.deleteSurroundingText(1, 0); + } } if (isSuggestionsRequested()) { restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(ic); |