summaryrefslogtreecommitdiff
path: root/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java')
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java259
1 files changed, 223 insertions, 36 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index e56159405..a632a27b1 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -16,24 +16,59 @@
package com.android.inputmethod.keyboard.internal;
+import android.text.TextUtils;
+
+import com.android.inputmethod.keyboard.Keyboard;
+
// TODO: Add unit tests
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 setSymbolsKeyboard();
+ public void setSymbolsShiftedKeyboard();
+ }
+
private KeyboardShiftState mKeyboardShiftState = new KeyboardShiftState();
- // TODO: Combine these key state objects with auto mode switch state.
private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift");
private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol");
- public KeyboardState() {
+ 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;
+
+ private final SwitchActions mSwitchActions;
+
+ public KeyboardState(SwitchActions switchActions) {
+ mSwitchActions = switchActions;
}
- public void onLoadKeyboard() {
+ public void onLoadKeyboard(String layoutSwitchBackSymbols) {
+ mLayoutSwitchBackSymbols = layoutSwitchBackSymbols;
mKeyboardShiftState.setShifted(false);
mKeyboardShiftState.setShiftLocked(false);
mShiftKeyState.onRelease();
mSymbolKeyState.onRelease();
}
+ // TODO: Get rid of this method
+ public void onSetKeyboard(boolean isAlphabetMode) {
+ mSwitchState = isAlphabetMode ? SWITCH_STATE_ALPHA : SWITCH_STATE_SYMBOL_BEGIN;
+ }
+
public boolean isShiftLocked() {
return mKeyboardShiftState.isShiftLocked();
}
@@ -73,40 +108,40 @@ public class KeyboardState {
mKeyboardShiftState.setAutomaticTemporaryUpperCase();
}
- // TODO: Get rid of this method
- public boolean isShiftKeyIgnoring() {
- return mShiftKeyState.isIgnoring();
- }
-
- // TODO: Get rid of this method
- public boolean isShiftKeyReleasing() {
- return mShiftKeyState.isReleasing();
- }
-
- // TODO: Get rid of this method
- public boolean isShiftKeyMomentary() {
- return mShiftKeyState.isMomentary();
- }
-
- // TODO: Get rid of this method
- public boolean isShiftKeyPressing() {
- return mShiftKeyState.isPressing();
+ private void toggleAlphabetAndSymbols(boolean isAlphabetMode) {
+ if (isAlphabetMode) {
+ mSwitchActions.setSymbolsKeyboard();
+ } else {
+ mSwitchActions.setAlphabetKeyboard();
+ }
}
- // TODO: Get rid of this method
- public boolean isShiftKeyPressingOnShifted() {
- return mShiftKeyState.isPressingOnShifted();
+ private void toggleShiftInSymbols(boolean isSymbolShifted) {
+ if (isSymbolShifted) {
+ mSwitchActions.setSymbolsKeyboard();
+ } else {
+ mSwitchActions.setSymbolsShiftedKeyboard();
+ }
}
public void onReleaseCapsLock() {
mShiftKeyState.onRelease();
}
- public void onPressSymbol() {
+ // TODO: Get rid of isAlphabetMode argument.
+ public void onPressSymbol(boolean isAlphabetMode) {
+ toggleAlphabetAndSymbols(isAlphabetMode);
mSymbolKeyState.onPress();
+ mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL;
}
- public void onReleaseSymbol() {
+ // TODO: Get rid of isAlphabetMode argument.
+ public void onReleaseSymbol(boolean isAlphabetMode) {
+ // Snap 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) {
+ toggleAlphabetAndSymbols(isAlphabetMode);
+ }
mSymbolKeyState.onRelease();
}
@@ -115,48 +150,200 @@ public class KeyboardState {
mSymbolKeyState.onOtherKeyPressed();
}
- public void onUpdateShiftState(boolean isAlphabetMode) {
- if (!isAlphabetMode) {
+ // TODO: Get rid of isAlphabetMode argument.
+ public void onUpdateShiftState(boolean isAlphabetMode, boolean autoCaps) {
+ if (isAlphabetMode) {
+ if (!isShiftLocked() && !mShiftKeyState.isIgnoring()) {
+ if (mShiftKeyState.isReleasing() && autoCaps) {
+ // Only when shift key is releasing, automatic temporary upper case will be set.
+ mSwitchActions.setShifted(SwitchActions.AUTOMATIC_SHIFT);
+ } else {
+ mSwitchActions.setShifted(mShiftKeyState.isMomentary()
+ ? SwitchActions.MANUAL_SHIFT : SwitchActions.UNSHIFT);
+ }
+ }
+ } else {
// In symbol keyboard mode, we should clear shift key state because only alphabet
// keyboard has shift key.
mSymbolKeyState.onRelease();
}
}
- // TODO: Get rid of these boolean arguments.
- public void onPressShift(boolean isAlphabetMode, boolean isShiftLocked,
- boolean isAutomaticTemporaryUpperCase, boolean isShiftedOrShiftLocked) {
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onPressShift(boolean isAlphabetMode, boolean isSymbolShifted) {
if (isAlphabetMode) {
- if (isShiftLocked) {
+ if (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.
+ mSwitchActions.setShifted(SwitchActions.MANUAL_SHIFT);
mShiftKeyState.onPress();
- } else if (isAutomaticTemporaryUpperCase) {
+ } else if (isAutomaticTemporaryUpperCase()) {
// Shift key is pressed while automatic temporary upper case, we have to move to
// manual temporary upper case.
+ mSwitchActions.setShifted(SwitchActions.MANUAL_SHIFT);
mShiftKeyState.onPress();
- } else if (isShiftedOrShiftLocked) {
+ } else if (isShiftedOrShiftLocked()) {
// In manual upper case state, we just record shift key has been pressing while
// shifted state.
mShiftKeyState.onPressOnShifted();
} else {
// In base layout, chording or manual temporary upper case mode is started.
+ mSwitchActions.setShifted(SwitchActions.MANUAL_SHIFT);
mShiftKeyState.onPress();
}
} else {
// In symbol mode, just toggle symbol and symbol more keyboard.
+ toggleShiftInSymbols(isSymbolShifted);
+ mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
mShiftKeyState.onPress();
}
}
- public void onReleaseShift() {
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onReleaseShift(boolean isAlphabetMode, boolean isSymbolShifted,
+ boolean withSliding) {
+ if (isAlphabetMode) {
+ final boolean isShiftLocked = isShiftLocked();
+ if (mShiftKeyState.isMomentary()) {
+ // After chording input while normal state.
+ mSwitchActions.setShifted(SwitchActions.UNSHIFT);
+ } else if (isShiftLocked && !isShiftLockShifted() && (mShiftKeyState.isPressing()
+ || mShiftKeyState.isPressingOnShifted()) && !withSliding) {
+ // Shift has been long pressed, ignore this release.
+ } else if (isShiftLocked && !mShiftKeyState.isIgnoring() && !withSliding) {
+ // Shift has been pressed without chording while caps lock state.
+ mSwitchActions.setShiftLocked(false);
+ } else if (isShiftedOrShiftLocked() && mShiftKeyState.isPressingOnShifted()
+ && !withSliding) {
+ // Shift has been pressed without chording while shifted state.
+ mSwitchActions.setShifted(SwitchActions.UNSHIFT);
+ } else if (isManualTemporaryUpperCaseFromAuto() && mShiftKeyState.isPressing()
+ && !withSliding) {
+ // Shift has been pressed without chording while manual temporary upper case
+ // transited from automatic temporary upper case.
+ mSwitchActions.setShifted(SwitchActions.UNSHIFT);
+ }
+ } 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) {
+ toggleShiftInSymbols(isSymbolShifted);
+ }
+ }
mShiftKeyState.onRelease();
}
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onCancelInput(boolean isAlphabetMode, boolean isSymbolShifted,
+ boolean isSinglePointer) {
+ // Snap back to the previous keyboard mode if the user cancels sliding input.
+ if (isSinglePointer) {
+ if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) {
+ toggleAlphabetAndSymbols(isAlphabetMode);
+ } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) {
+ toggleShiftInSymbols(isSymbolShifted);
+ }
+ }
+ }
+
+ public boolean isInMomentarySwitchState() {
+ return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL
+ || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
+ }
+
+ private static boolean isSpaceCharacter(int c) {
+ return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER;
+ }
+
+ private boolean isLayoutSwitchBackCharacter(int c) {
+ if (TextUtils.isEmpty(mLayoutSwitchBackSymbols)) return false;
+ if (mLayoutSwitchBackSymbols.indexOf(c) >= 0) return true;
+ return false;
+ }
+
+ // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
+ public void onCodeInput(boolean isAlphabetMode, boolean isSymbolShifted, int code,
+ boolean isSinglePointer) {
+ 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 (isAlphabetMode) {
+ mSwitchState = SWITCH_STATE_ALPHA;
+ } else {
+ mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
+ }
+ } else if (isSinglePointer) {
+ // Snap back to the previous keyboard mode if the user pressed the mode change key
+ // and slid to other key, then released the finger.
+ // If the user cancels the sliding input, snapping back to the previous keyboard
+ // mode is handled by {@link #onCancelInput}.
+ toggleAlphabetAndSymbols(isAlphabetMode);
+ } 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.
+ 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 (isSinglePointer) {
+ // 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.
+ toggleShiftInSymbols(isSymbolShifted);
+ 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 SWITCH_STATE_SYMBOL_BEGIN:
+ if (!isSpaceCharacter(code) && code >= 0) {
+ mSwitchState = SWITCH_STATE_SYMBOL;
+ }
+ // Snap back to alpha keyboard mode immediately if user types a quote character.
+ if (isLayoutSwitchBackCharacter(code)) {
+ mSwitchActions.setAlphabetKeyboard();
+ }
+ break;
+ 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 or a quote character.
+ if (isSpaceCharacter(code) || isLayoutSwitchBackCharacter(code)) {
+ mSwitchActions.setAlphabetKeyboard();
+ }
+ break;
+ }
+ }
+
+ private static String switchStateToString(int switchState) {
+ switch (switchState) {
+ case SWITCH_STATE_ALPHA: return "ALPHA";
+ case SWITCH_STATE_SYMBOL_BEGIN: return "SYMBOL-BEGIN";
+ 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;
+ }
+ }
+
@Override
public String toString() {
return "[keyboard=" + mKeyboardShiftState
+ " shift=" + mShiftKeyState
- + " symbol=" + mSymbolKeyState + "]";
+ + " symbol=" + mSymbolKeyState
+ + " switch=" + switchStateToString(mSwitchState) + "]";
}
}