2011-12-05 06:02:06 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2011 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
|
|
* use this file except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
* License for the specific language governing permissions and limitations under
|
|
|
|
* the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package com.android.inputmethod.keyboard.internal;
|
|
|
|
|
2011-12-07 10:31:11 +00:00
|
|
|
import android.text.TextUtils;
|
2011-12-08 05:42:12 +00:00
|
|
|
import android.util.Log;
|
2011-12-07 10:31:11 +00:00
|
|
|
|
|
|
|
import com.android.inputmethod.keyboard.Keyboard;
|
|
|
|
|
2011-12-08 12:27:57 +00:00
|
|
|
/**
|
|
|
|
* Keyboard state machine.
|
|
|
|
*
|
|
|
|
* This class contains all keyboard state transition logic.
|
2011-12-09 10:53:36 +00:00
|
|
|
*
|
2012-01-18 09:01:53 +00:00
|
|
|
* The input events are {@link #onLoadKeyboard(String)}, {@link #onSaveKeyboardState()},
|
2012-01-17 08:08:26 +00:00
|
|
|
* {@link #onPressKey(int)}, {@link #onReleaseKey(int, boolean)},
|
2011-12-26 14:40:09 +00:00
|
|
|
* {@link #onCodeInput(int, boolean, boolean)}, {@link #onCancelInput(boolean)},
|
2012-01-17 09:45:04 +00:00
|
|
|
* {@link #onUpdateShiftState(boolean)}.
|
2011-12-09 10:53:36 +00:00
|
|
|
*
|
2011-12-09 07:09:16 +00:00
|
|
|
* The actions are {@link SwitchActions}'s methods.
|
2011-12-08 12:27:57 +00:00
|
|
|
*/
|
2011-12-05 06:02:06 +00:00
|
|
|
public class KeyboardState {
|
2011-12-08 05:42:12 +00:00
|
|
|
private static final String TAG = KeyboardState.class.getSimpleName();
|
2012-01-17 08:08:26 +00:00
|
|
|
private static final boolean DEBUG_EVENT = false;
|
|
|
|
private static final boolean DEBUG_ACTION = false;
|
2011-12-08 05:42:12 +00:00
|
|
|
|
2011-12-07 10:31:11 +00:00
|
|
|
public interface SwitchActions {
|
|
|
|
public void setAlphabetKeyboard();
|
2012-01-24 03:06:49 +00:00
|
|
|
public void setAlphabetManualShiftedKeyboard();
|
|
|
|
public void setAlphabetAutomaticShiftedKeyboard();
|
|
|
|
public void setAlphabetShiftLockedKeyboard();
|
2011-12-07 10:31:11 +00:00
|
|
|
public void setSymbolsKeyboard();
|
|
|
|
public void setSymbolsShiftedKeyboard();
|
2012-01-13 11:15:14 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Request to call back {@link KeyboardState#onUpdateShiftState(boolean)}.
|
|
|
|
*/
|
|
|
|
public void requestUpdatingShiftState();
|
2011-12-07 10:31:11 +00:00
|
|
|
}
|
|
|
|
|
2012-01-19 09:42:11 +00:00
|
|
|
private final SwitchActions mSwitchActions;
|
2011-12-06 02:19:39 +00:00
|
|
|
|
2011-12-05 06:02:06 +00:00
|
|
|
private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift");
|
|
|
|
private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol");
|
|
|
|
|
2012-01-24 03:06:49 +00:00
|
|
|
// TODO: Merge {@link #mSwitchState}, {@link #mIsAlphabetMode}, {@link #mAlphabetShiftState},
|
|
|
|
// {@link #mIsSymbolShifted}, {@link #mPrevMainKeyboardWasShiftLocked}, and
|
|
|
|
// {@link #mPrevSymbolsKeyboardWasShifted} into single state variable.
|
2011-12-07 10:31:11 +00:00
|
|
|
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;
|
|
|
|
|
2011-12-09 07:09:16 +00:00
|
|
|
private boolean mIsAlphabetMode;
|
2012-01-19 09:42:11 +00:00
|
|
|
private KeyboardShiftState mAlphabetShiftState = new KeyboardShiftState();
|
2011-12-09 07:09:16 +00:00
|
|
|
private boolean mIsSymbolShifted;
|
2012-01-19 09:42:11 +00:00
|
|
|
private boolean mPrevMainKeyboardWasShiftLocked;
|
2012-01-19 09:53:38 +00:00
|
|
|
private boolean mPrevSymbolsKeyboardWasShifted;
|
2011-12-09 07:09:16 +00:00
|
|
|
|
2011-12-08 05:42:12 +00:00
|
|
|
private final SavedKeyboardState mSavedKeyboardState = new SavedKeyboardState();
|
|
|
|
|
2011-12-09 07:09:16 +00:00
|
|
|
static class SavedKeyboardState {
|
2011-12-08 05:42:12 +00:00
|
|
|
public boolean mIsValid;
|
|
|
|
public boolean mIsAlphabetMode;
|
|
|
|
public boolean mIsShiftLocked;
|
|
|
|
public boolean mIsShifted;
|
2012-01-23 04:14:02 +00:00
|
|
|
|
2012-01-24 03:06:49 +00:00
|
|
|
@Override
|
2012-01-23 04:14:02 +00:00
|
|
|
public String toString() {
|
|
|
|
if (!mIsValid) return "INVALID";
|
|
|
|
if (mIsAlphabetMode) {
|
|
|
|
if (mIsShiftLocked) return "ALPHABET_SHIFT_LOCKED";
|
|
|
|
return mIsShifted ? "ALPHABET_SHIFTED" : "ALPHABET";
|
|
|
|
} else {
|
|
|
|
return mIsShifted ? "SYMBOLS_SHIFTED" : "SYMBOLS";
|
|
|
|
}
|
|
|
|
}
|
2011-12-08 05:42:12 +00:00
|
|
|
}
|
|
|
|
|
2011-12-07 10:31:11 +00:00
|
|
|
public KeyboardState(SwitchActions switchActions) {
|
|
|
|
mSwitchActions = switchActions;
|
2011-12-05 06:02:06 +00:00
|
|
|
}
|
|
|
|
|
2012-01-18 09:01:53 +00:00
|
|
|
public void onLoadKeyboard(String layoutSwitchBackSymbols) {
|
2012-01-17 08:08:26 +00:00
|
|
|
if (DEBUG_EVENT) {
|
2012-01-23 04:14:02 +00:00
|
|
|
Log.d(TAG, "onLoadKeyboard: " + this);
|
2011-12-08 13:10:27 +00:00
|
|
|
}
|
2011-12-07 10:31:11 +00:00
|
|
|
mLayoutSwitchBackSymbols = layoutSwitchBackSymbols;
|
2012-01-19 09:42:11 +00:00
|
|
|
// Reset alphabet shift state.
|
|
|
|
mAlphabetShiftState.setShiftLocked(false);
|
|
|
|
mPrevMainKeyboardWasShiftLocked = false;
|
2012-01-19 09:53:38 +00:00
|
|
|
mPrevSymbolsKeyboardWasShifted = false;
|
2011-12-07 08:55:22 +00:00
|
|
|
mShiftKeyState.onRelease();
|
|
|
|
mSymbolKeyState.onRelease();
|
2011-12-08 07:30:13 +00:00
|
|
|
onRestoreKeyboardState();
|
2011-12-07 08:55:22 +00:00
|
|
|
}
|
|
|
|
|
2011-12-09 07:09:16 +00:00
|
|
|
public void onSaveKeyboardState() {
|
2011-12-08 05:42:12 +00:00
|
|
|
final SavedKeyboardState state = mSavedKeyboardState;
|
2011-12-09 07:09:16 +00:00
|
|
|
state.mIsAlphabetMode = mIsAlphabetMode;
|
|
|
|
if (mIsAlphabetMode) {
|
2012-01-19 09:42:11 +00:00
|
|
|
state.mIsShiftLocked = mAlphabetShiftState.isShiftLocked();
|
2011-12-09 10:53:36 +00:00
|
|
|
state.mIsShifted = !state.mIsShiftLocked
|
2012-01-19 09:42:11 +00:00
|
|
|
&& mAlphabetShiftState.isShiftedOrShiftLocked();
|
2011-12-08 05:42:12 +00:00
|
|
|
} else {
|
|
|
|
state.mIsShiftLocked = false;
|
2011-12-09 07:09:16 +00:00
|
|
|
state.mIsShifted = mIsSymbolShifted;
|
2011-12-08 05:42:12 +00:00
|
|
|
}
|
|
|
|
state.mIsValid = true;
|
2012-01-17 08:08:26 +00:00
|
|
|
if (DEBUG_EVENT) {
|
2012-01-23 04:14:02 +00:00
|
|
|
Log.d(TAG, "onSaveKeyboardState: saved=" + state + " " + this);
|
2011-12-08 05:42:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-08 07:30:13 +00:00
|
|
|
private void onRestoreKeyboardState() {
|
2011-12-08 05:42:12 +00:00
|
|
|
final SavedKeyboardState state = mSavedKeyboardState;
|
2012-01-17 08:08:26 +00:00
|
|
|
if (DEBUG_EVENT) {
|
2012-01-23 04:14:02 +00:00
|
|
|
Log.d(TAG, "onRestoreKeyboardState: saved=" + state + " " + this);
|
2011-12-08 05:42:12 +00:00
|
|
|
}
|
|
|
|
if (!state.mIsValid || state.mIsAlphabetMode) {
|
2011-12-08 12:03:25 +00:00
|
|
|
setAlphabetKeyboard();
|
2011-12-08 05:42:12 +00:00
|
|
|
} else {
|
|
|
|
if (state.mIsShifted) {
|
2011-12-08 12:03:25 +00:00
|
|
|
setSymbolsShiftedKeyboard();
|
2011-12-08 05:42:12 +00:00
|
|
|
} else {
|
2011-12-08 12:03:25 +00:00
|
|
|
setSymbolsKeyboard();
|
2011-12-08 05:42:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!state.mIsValid) return;
|
|
|
|
state.mIsValid = false;
|
|
|
|
|
|
|
|
if (state.mIsAlphabetMode) {
|
2011-12-08 12:27:57 +00:00
|
|
|
setShiftLocked(state.mIsShiftLocked);
|
2011-12-08 05:42:12 +00:00
|
|
|
if (!state.mIsShiftLocked) {
|
2012-01-24 03:06:49 +00:00
|
|
|
setShifted(state.mIsShifted ? MANUAL_SHIFT : UNSHIFT);
|
2011-12-08 05:42:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-09 10:53:36 +00:00
|
|
|
// TODO: Remove this method.
|
2011-12-06 02:19:39 +00:00
|
|
|
public boolean isShiftLocked() {
|
2012-01-19 09:42:11 +00:00
|
|
|
return mAlphabetShiftState.isShiftLocked();
|
2011-12-06 02:19:39 +00:00
|
|
|
}
|
|
|
|
|
2012-01-24 03:06:49 +00:00
|
|
|
private static final int UNSHIFT = 0;
|
|
|
|
private static final int MANUAL_SHIFT = 1;
|
|
|
|
private static final int AUTOMATIC_SHIFT = 2;
|
|
|
|
|
2011-12-08 12:27:57 +00:00
|
|
|
private void setShifted(int shiftMode) {
|
2012-01-17 08:08:26 +00:00
|
|
|
if (DEBUG_ACTION) {
|
2012-01-24 03:06:49 +00:00
|
|
|
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;
|
2011-12-08 13:10:27 +00:00
|
|
|
}
|
2012-01-18 09:01:53 +00:00
|
|
|
switch (shiftMode) {
|
2012-01-24 03:06:49 +00:00
|
|
|
case AUTOMATIC_SHIFT:
|
2012-01-19 09:42:11 +00:00
|
|
|
mAlphabetShiftState.setAutomaticTemporaryUpperCase();
|
2012-01-24 03:06:49 +00:00
|
|
|
if (shiftMode != prevShiftMode) {
|
|
|
|
mSwitchActions.setAlphabetAutomaticShiftedKeyboard();
|
|
|
|
}
|
2012-01-18 09:01:53 +00:00
|
|
|
break;
|
2012-01-24 03:06:49 +00:00
|
|
|
case MANUAL_SHIFT:
|
2012-01-19 09:42:11 +00:00
|
|
|
mAlphabetShiftState.setShifted(true);
|
2012-01-24 03:06:49 +00:00
|
|
|
if (shiftMode != prevShiftMode) {
|
|
|
|
mSwitchActions.setAlphabetManualShiftedKeyboard();
|
|
|
|
}
|
2012-01-18 09:01:53 +00:00
|
|
|
break;
|
2012-01-24 03:06:49 +00:00
|
|
|
case UNSHIFT:
|
2012-01-19 09:42:11 +00:00
|
|
|
mAlphabetShiftState.setShifted(false);
|
2012-01-24 03:06:49 +00:00
|
|
|
if (shiftMode != prevShiftMode) {
|
|
|
|
mSwitchActions.setAlphabetKeyboard();
|
|
|
|
}
|
2012-01-18 09:01:53 +00:00
|
|
|
break;
|
2011-12-08 12:27:57 +00:00
|
|
|
}
|
2011-12-06 02:19:39 +00:00
|
|
|
}
|
|
|
|
|
2011-12-08 12:27:57 +00:00
|
|
|
private void setShiftLocked(boolean shiftLocked) {
|
2012-01-17 08:08:26 +00:00
|
|
|
if (DEBUG_ACTION) {
|
2012-01-24 03:06:49 +00:00
|
|
|
Log.d(TAG, "setShiftLocked: shiftLocked=" + shiftLocked + " " + this);
|
|
|
|
}
|
|
|
|
if (!mIsAlphabetMode) return;
|
|
|
|
if (shiftLocked && (!mAlphabetShiftState.isShiftLocked()
|
|
|
|
|| mAlphabetShiftState.isShiftLockShifted())) {
|
|
|
|
mSwitchActions.setAlphabetShiftLockedKeyboard();
|
|
|
|
}
|
|
|
|
if (!shiftLocked && mAlphabetShiftState.isShiftLocked()) {
|
|
|
|
mSwitchActions.setAlphabetKeyboard();
|
2011-12-08 13:10:27 +00:00
|
|
|
}
|
2012-01-19 09:42:11 +00:00
|
|
|
mAlphabetShiftState.setShiftLocked(shiftLocked);
|
2011-12-06 02:19:39 +00:00
|
|
|
}
|
|
|
|
|
2011-12-09 07:09:16 +00:00
|
|
|
private void toggleAlphabetAndSymbols() {
|
|
|
|
if (mIsAlphabetMode) {
|
2011-12-08 12:03:25 +00:00
|
|
|
setSymbolsKeyboard();
|
2011-12-07 10:31:11 +00:00
|
|
|
} else {
|
2011-12-08 12:03:25 +00:00
|
|
|
setAlphabetKeyboard();
|
2011-12-07 10:31:11 +00:00
|
|
|
}
|
2011-12-05 06:02:06 +00:00
|
|
|
}
|
|
|
|
|
2011-12-09 07:09:16 +00:00
|
|
|
private void toggleShiftInSymbols() {
|
|
|
|
if (mIsSymbolShifted) {
|
2011-12-08 12:03:25 +00:00
|
|
|
setSymbolsKeyboard();
|
2011-12-07 10:31:11 +00:00
|
|
|
} else {
|
2011-12-08 12:03:25 +00:00
|
|
|
setSymbolsShiftedKeyboard();
|
2011-12-07 10:31:11 +00:00
|
|
|
}
|
2011-12-05 06:02:06 +00:00
|
|
|
}
|
|
|
|
|
2011-12-08 12:03:25 +00:00
|
|
|
private void setAlphabetKeyboard() {
|
2012-01-17 08:08:26 +00:00
|
|
|
if (DEBUG_ACTION) {
|
2011-12-08 13:10:27 +00:00
|
|
|
Log.d(TAG, "setAlphabetKeyboard");
|
|
|
|
}
|
2012-01-19 09:53:38 +00:00
|
|
|
mPrevSymbolsKeyboardWasShifted = mIsSymbolShifted;
|
2011-12-08 12:03:25 +00:00
|
|
|
mSwitchActions.setAlphabetKeyboard();
|
2011-12-09 07:09:16 +00:00
|
|
|
mIsAlphabetMode = true;
|
|
|
|
mIsSymbolShifted = false;
|
2011-12-08 12:03:25 +00:00
|
|
|
mSwitchState = SWITCH_STATE_ALPHA;
|
2011-12-08 12:27:57 +00:00
|
|
|
setShiftLocked(mPrevMainKeyboardWasShiftLocked);
|
2011-12-08 07:30:13 +00:00
|
|
|
mPrevMainKeyboardWasShiftLocked = false;
|
2012-01-13 11:15:14 +00:00
|
|
|
mSwitchActions.requestUpdatingShiftState();
|
2011-12-08 07:30:13 +00:00
|
|
|
}
|
|
|
|
|
2012-01-17 07:30:37 +00:00
|
|
|
// TODO: Make this method private
|
|
|
|
public void setSymbolsKeyboard() {
|
2012-01-19 09:42:11 +00:00
|
|
|
mPrevMainKeyboardWasShiftLocked = mAlphabetShiftState.isShiftLocked();
|
2012-01-19 09:53:38 +00:00
|
|
|
if (mPrevSymbolsKeyboardWasShifted) {
|
|
|
|
setSymbolsShiftedKeyboard();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-01-17 08:08:26 +00:00
|
|
|
if (DEBUG_ACTION) {
|
2011-12-08 13:10:27 +00:00
|
|
|
Log.d(TAG, "setSymbolsKeyboard");
|
|
|
|
}
|
2011-12-08 12:03:25 +00:00
|
|
|
mSwitchActions.setSymbolsKeyboard();
|
2011-12-09 07:09:16 +00:00
|
|
|
mIsAlphabetMode = false;
|
|
|
|
mIsSymbolShifted = false;
|
2012-01-19 09:42:11 +00:00
|
|
|
// Reset alphabet shift state.
|
|
|
|
mAlphabetShiftState.setShiftLocked(false);
|
2012-01-19 09:53:38 +00:00
|
|
|
mPrevSymbolsKeyboardWasShifted = false;
|
2011-12-08 12:03:25 +00:00
|
|
|
mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
|
2011-12-08 07:30:13 +00:00
|
|
|
}
|
|
|
|
|
2011-12-08 12:03:25 +00:00
|
|
|
private void setSymbolsShiftedKeyboard() {
|
2012-01-17 08:08:26 +00:00
|
|
|
if (DEBUG_ACTION) {
|
2011-12-08 13:10:27 +00:00
|
|
|
Log.d(TAG, "setSymbolsShiftedKeyboard");
|
|
|
|
}
|
2011-12-08 12:03:25 +00:00
|
|
|
mSwitchActions.setSymbolsShiftedKeyboard();
|
2011-12-09 07:09:16 +00:00
|
|
|
mIsAlphabetMode = false;
|
|
|
|
mIsSymbolShifted = true;
|
2012-01-19 09:42:11 +00:00
|
|
|
// Reset alphabet shift state.
|
|
|
|
mAlphabetShiftState.setShiftLocked(false);
|
2012-01-19 09:53:38 +00:00
|
|
|
mPrevSymbolsKeyboardWasShifted = false;
|
2011-12-08 12:03:25 +00:00
|
|
|
mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
|
2011-12-05 06:02:06 +00:00
|
|
|
}
|
|
|
|
|
2012-01-17 08:08:26 +00:00
|
|
|
public void onPressKey(int code) {
|
|
|
|
if (DEBUG_EVENT) {
|
|
|
|
Log.d(TAG, "onPressKey: code=" + Keyboard.printableCode(code) + " " + this);
|
2011-12-08 13:10:27 +00:00
|
|
|
}
|
2012-01-17 08:08:26 +00:00
|
|
|
if (code == Keyboard.CODE_SHIFT) {
|
|
|
|
onPressShift();
|
|
|
|
} else if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
|
|
|
|
onPressSymbol();
|
|
|
|
} else {
|
|
|
|
mShiftKeyState.onOtherKeyPressed();
|
|
|
|
mSymbolKeyState.onOtherKeyPressed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void onReleaseKey(int code, boolean withSliding) {
|
|
|
|
if (DEBUG_EVENT) {
|
|
|
|
Log.d(TAG, "onReleaseKey: code=" + Keyboard.printableCode(code)
|
|
|
|
+ " sliding=" + withSliding + " " + this);
|
|
|
|
}
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void onPressSymbol() {
|
2011-12-09 07:09:16 +00:00
|
|
|
toggleAlphabetAndSymbols();
|
2011-12-05 06:02:06 +00:00
|
|
|
mSymbolKeyState.onPress();
|
2011-12-07 10:31:11 +00:00
|
|
|
mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL;
|
2011-12-05 06:02:06 +00:00
|
|
|
}
|
|
|
|
|
2012-01-17 08:08:26 +00:00
|
|
|
private void onReleaseSymbol() {
|
2012-01-18 07:40:28 +00:00
|
|
|
// Switch back to the previous keyboard mode if the user chords the mode change key and
|
2011-12-07 10:31:11 +00:00
|
|
|
// another key, then releases the mode change key.
|
|
|
|
if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) {
|
2011-12-09 07:09:16 +00:00
|
|
|
toggleAlphabetAndSymbols();
|
2011-12-07 10:31:11 +00:00
|
|
|
}
|
2011-12-05 06:02:06 +00:00
|
|
|
mSymbolKeyState.onRelease();
|
|
|
|
}
|
|
|
|
|
2011-12-09 07:09:16 +00:00
|
|
|
public void onUpdateShiftState(boolean autoCaps) {
|
2012-01-17 08:08:26 +00:00
|
|
|
if (DEBUG_EVENT) {
|
2011-12-09 11:18:39 +00:00
|
|
|
Log.d(TAG, "onUpdateShiftState: autoCaps=" + autoCaps + " " + this);
|
2011-12-08 13:10:27 +00:00
|
|
|
}
|
2011-12-26 14:40:09 +00:00
|
|
|
onUpdateShiftStateInternal(autoCaps);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void onUpdateShiftStateInternal(boolean autoCaps) {
|
2011-12-09 07:09:16 +00:00
|
|
|
if (mIsAlphabetMode) {
|
2012-01-19 09:42:11 +00:00
|
|
|
if (!mAlphabetShiftState.isShiftLocked() && !mShiftKeyState.isIgnoring()) {
|
2011-12-07 10:31:11 +00:00
|
|
|
if (mShiftKeyState.isReleasing() && autoCaps) {
|
|
|
|
// Only when shift key is releasing, automatic temporary upper case will be set.
|
2012-01-24 03:06:49 +00:00
|
|
|
setShifted(AUTOMATIC_SHIFT);
|
2011-12-07 10:31:11 +00:00
|
|
|
} else {
|
2012-01-24 03:06:49 +00:00
|
|
|
setShifted(mShiftKeyState.isMomentary() ? MANUAL_SHIFT : UNSHIFT);
|
2011-12-07 10:31:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2011-12-05 06:02:06 +00:00
|
|
|
// In symbol keyboard mode, we should clear shift key state because only alphabet
|
|
|
|
// keyboard has shift key.
|
|
|
|
mSymbolKeyState.onRelease();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-17 08:08:26 +00:00
|
|
|
private void onPressShift() {
|
2011-12-09 07:09:16 +00:00
|
|
|
if (mIsAlphabetMode) {
|
2012-01-19 09:42:11 +00:00
|
|
|
if (mAlphabetShiftState.isShiftLocked()) {
|
2011-12-05 06:02:06 +00:00
|
|
|
// 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.
|
2012-01-24 03:06:49 +00:00
|
|
|
setShifted(MANUAL_SHIFT);
|
2011-12-05 06:02:06 +00:00
|
|
|
mShiftKeyState.onPress();
|
2012-01-19 09:42:11 +00:00
|
|
|
} else if (mAlphabetShiftState.isAutomaticTemporaryUpperCase()) {
|
2011-12-05 06:02:06 +00:00
|
|
|
// Shift key is pressed while automatic temporary upper case, we have to move to
|
|
|
|
// manual temporary upper case.
|
2012-01-24 03:06:49 +00:00
|
|
|
setShifted(MANUAL_SHIFT);
|
2011-12-05 06:02:06 +00:00
|
|
|
mShiftKeyState.onPress();
|
2012-01-19 09:42:11 +00:00
|
|
|
} else if (mAlphabetShiftState.isShiftedOrShiftLocked()) {
|
2011-12-05 06:02:06 +00:00
|
|
|
// 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.
|
2012-01-24 03:06:49 +00:00
|
|
|
setShifted(MANUAL_SHIFT);
|
2011-12-05 06:02:06 +00:00
|
|
|
mShiftKeyState.onPress();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// In symbol mode, just toggle symbol and symbol more keyboard.
|
2011-12-09 07:09:16 +00:00
|
|
|
toggleShiftInSymbols();
|
2011-12-07 10:31:11 +00:00
|
|
|
mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
|
2011-12-05 06:02:06 +00:00
|
|
|
mShiftKeyState.onPress();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-17 08:08:26 +00:00
|
|
|
private void onReleaseShift(boolean withSliding) {
|
2011-12-09 07:09:16 +00:00
|
|
|
if (mIsAlphabetMode) {
|
2012-01-19 09:42:11 +00:00
|
|
|
final boolean isShiftLocked = mAlphabetShiftState.isShiftLocked();
|
2011-12-07 10:31:11 +00:00
|
|
|
if (mShiftKeyState.isMomentary()) {
|
|
|
|
// After chording input while normal state.
|
2012-01-19 09:48:02 +00:00
|
|
|
if (mAlphabetShiftState.isShiftLockShifted()) {
|
|
|
|
setShiftLocked(true);
|
|
|
|
} else {
|
2012-01-24 03:06:49 +00:00
|
|
|
setShifted(UNSHIFT);
|
2012-01-19 09:48:02 +00:00
|
|
|
}
|
2012-01-19 09:42:11 +00:00
|
|
|
} else if (isShiftLocked && !mAlphabetShiftState.isShiftLockShifted()
|
2011-12-09 10:53:36 +00:00
|
|
|
&& (mShiftKeyState.isPressing() || mShiftKeyState.isPressingOnShifted())
|
|
|
|
&& !withSliding) {
|
2011-12-07 10:31:11 +00:00
|
|
|
// Shift has been long pressed, ignore this release.
|
|
|
|
} else if (isShiftLocked && !mShiftKeyState.isIgnoring() && !withSliding) {
|
|
|
|
// Shift has been pressed without chording while caps lock state.
|
2011-12-08 12:27:57 +00:00
|
|
|
setShiftLocked(false);
|
2012-01-19 09:42:11 +00:00
|
|
|
} else if (mAlphabetShiftState.isShiftedOrShiftLocked()
|
2011-12-09 10:53:36 +00:00
|
|
|
&& mShiftKeyState.isPressingOnShifted() && !withSliding) {
|
2011-12-07 10:31:11 +00:00
|
|
|
// Shift has been pressed without chording while shifted state.
|
2012-01-24 03:06:49 +00:00
|
|
|
setShifted(UNSHIFT);
|
2012-01-19 09:42:11 +00:00
|
|
|
} else if (mAlphabetShiftState.isManualTemporaryUpperCaseFromAuto()
|
2011-12-09 10:53:36 +00:00
|
|
|
&& mShiftKeyState.isPressing() && !withSliding) {
|
2011-12-07 10:31:11 +00:00
|
|
|
// Shift has been pressed without chording while manual temporary upper case
|
|
|
|
// transited from automatic temporary upper case.
|
2012-01-24 03:06:49 +00:00
|
|
|
setShifted(UNSHIFT);
|
2011-12-07 10:31:11 +00:00
|
|
|
}
|
|
|
|
} else {
|
2012-01-18 07:40:28 +00:00
|
|
|
// 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.
|
2011-12-07 10:31:11 +00:00
|
|
|
if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) {
|
2011-12-09 07:09:16 +00:00
|
|
|
toggleShiftInSymbols();
|
2011-12-07 10:31:11 +00:00
|
|
|
}
|
|
|
|
}
|
2011-12-05 06:02:06 +00:00
|
|
|
mShiftKeyState.onRelease();
|
|
|
|
}
|
|
|
|
|
2011-12-09 07:09:16 +00:00
|
|
|
public void onCancelInput(boolean isSinglePointer) {
|
2012-01-17 08:08:26 +00:00
|
|
|
if (DEBUG_EVENT) {
|
|
|
|
Log.d(TAG, "onCancelInput: single=" + isSinglePointer + " " + this);
|
2011-12-08 13:10:27 +00:00
|
|
|
}
|
2012-01-18 07:40:28 +00:00
|
|
|
// Switch back to the previous keyboard mode if the user cancels sliding input.
|
2011-12-07 10:31:11 +00:00
|
|
|
if (isSinglePointer) {
|
|
|
|
if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) {
|
2011-12-09 07:09:16 +00:00
|
|
|
toggleAlphabetAndSymbols();
|
2011-12-07 10:31:11 +00:00
|
|
|
} else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) {
|
2011-12-09 07:09:16 +00:00
|
|
|
toggleShiftInSymbols();
|
2011-12-07 10:31:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-12-26 14:40:09 +00:00
|
|
|
public void onCodeInput(int code, boolean isSinglePointer, boolean autoCaps) {
|
2012-01-17 08:08:26 +00:00
|
|
|
if (DEBUG_EVENT) {
|
|
|
|
Log.d(TAG, "onCodeInput: code=" + Keyboard.printableCode(code)
|
|
|
|
+ " single=" + isSinglePointer
|
2011-12-26 14:40:09 +00:00
|
|
|
+ " autoCaps=" + autoCaps + " " + this);
|
2011-12-08 13:10:27 +00:00
|
|
|
}
|
2012-01-17 09:45:04 +00:00
|
|
|
|
|
|
|
if (mIsAlphabetMode && code == Keyboard.CODE_CAPSLOCK) {
|
2012-01-19 09:42:11 +00:00
|
|
|
if (mAlphabetShiftState.isShiftLocked()) {
|
2012-01-17 09:45:04 +00:00
|
|
|
setShiftLocked(false);
|
|
|
|
// Shift key is long pressed or double tapped while caps lock state, we will
|
|
|
|
// toggle back to normal state. And mark as if shift key is released.
|
|
|
|
mShiftKeyState.onRelease();
|
|
|
|
} else {
|
|
|
|
setShiftLocked(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-07 10:31:11 +00:00
|
|
|
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.
|
2011-12-09 07:09:16 +00:00
|
|
|
if (mIsAlphabetMode) {
|
2011-12-07 10:31:11 +00:00
|
|
|
mSwitchState = SWITCH_STATE_ALPHA;
|
|
|
|
} else {
|
|
|
|
mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
|
|
|
|
}
|
|
|
|
} else if (isSinglePointer) {
|
2012-01-18 07:40:28 +00:00
|
|
|
// Switch back to the previous keyboard mode if the user pressed the mode change key
|
2011-12-07 10:31:11 +00:00
|
|
|
// and slid to other key, then released the finger.
|
2012-01-18 07:40:28 +00:00
|
|
|
// If the user cancels the sliding input, switching back to the previous keyboard
|
2011-12-07 10:31:11 +00:00
|
|
|
// mode is handled by {@link #onCancelInput}.
|
2011-12-09 07:09:16 +00:00
|
|
|
toggleAlphabetAndSymbols();
|
2011-12-07 10:31:11 +00:00
|
|
|
} else {
|
2012-01-18 07:40:28 +00:00
|
|
|
// Chording input is being started. The keyboard mode will be switched back to the
|
2011-12-07 10:31:11 +00:00
|
|
|
// 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) {
|
2012-01-18 07:40:28 +00:00
|
|
|
// Switch back to the previous keyboard mode if the user pressed the shift key on
|
2011-12-07 10:31:11 +00:00
|
|
|
// symbol mode and slid to other key, then released the finger.
|
2011-12-09 07:09:16 +00:00
|
|
|
toggleShiftInSymbols();
|
2011-12-07 10:31:11 +00:00
|
|
|
mSwitchState = SWITCH_STATE_SYMBOL;
|
|
|
|
} else {
|
2012-01-18 07:40:28 +00:00
|
|
|
// Chording input is being started. The keyboard mode will be switched back to the
|
2011-12-07 10:31:11 +00:00
|
|
|
// previous mode in {@link onReleaseShift} when the shift key is released.
|
|
|
|
mSwitchState = SWITCH_STATE_CHORDING_SYMBOL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SWITCH_STATE_SYMBOL_BEGIN:
|
2012-01-10 08:24:00 +00:00
|
|
|
if (!isSpaceCharacter(code) && (Keyboard.isLetterCode(code)
|
|
|
|
|| code == Keyboard.CODE_OUTPUT_TEXT)) {
|
2011-12-07 10:31:11 +00:00
|
|
|
mSwitchState = SWITCH_STATE_SYMBOL;
|
|
|
|
}
|
2012-01-18 07:40:28 +00:00
|
|
|
// Switch back to alpha keyboard mode immediately if user types a quote character.
|
2011-12-07 10:31:11 +00:00
|
|
|
if (isLayoutSwitchBackCharacter(code)) {
|
2011-12-08 12:03:25 +00:00
|
|
|
setAlphabetKeyboard();
|
2011-12-07 10:31:11 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SWITCH_STATE_SYMBOL:
|
|
|
|
case SWITCH_STATE_CHORDING_SYMBOL:
|
2012-01-18 07:40:28 +00:00
|
|
|
// Switch back to alpha keyboard mode if user types one or more non-space/enter
|
2011-12-07 10:31:11 +00:00
|
|
|
// characters followed by a space/enter or a quote character.
|
|
|
|
if (isSpaceCharacter(code) || isLayoutSwitchBackCharacter(code)) {
|
2011-12-08 12:03:25 +00:00
|
|
|
setAlphabetKeyboard();
|
2011-12-07 10:31:11 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2011-12-26 14:40:09 +00:00
|
|
|
|
|
|
|
// If the code is a letter, update keyboard shift state.
|
|
|
|
if (Keyboard.isLetterCode(code)) {
|
|
|
|
onUpdateShiftStateInternal(autoCaps);
|
|
|
|
}
|
2011-12-07 10:31:11 +00:00
|
|
|
}
|
|
|
|
|
2011-12-08 13:10:27 +00:00
|
|
|
private static String shiftModeToString(int shiftMode) {
|
|
|
|
switch (shiftMode) {
|
2012-01-24 03:06:49 +00:00
|
|
|
case UNSHIFT: return "UNSHIFT";
|
|
|
|
case MANUAL_SHIFT: return "MANUAL";
|
|
|
|
case AUTOMATIC_SHIFT: return "AUTOMATIC";
|
2011-12-08 13:10:27 +00:00
|
|
|
default: return null;
|
|
|
|
}
|
|
|
|
}
|
2011-12-09 10:53:36 +00:00
|
|
|
|
2011-12-07 10:31:11 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-05 06:02:06 +00:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
2012-01-19 09:42:11 +00:00
|
|
|
return "[keyboard=" + (mIsAlphabetMode ? mAlphabetShiftState.toString()
|
|
|
|
: (mIsSymbolShifted ? "SYMBOLS_SHIFTED" : "SYMBOLS"))
|
2011-12-06 02:19:39 +00:00
|
|
|
+ " shift=" + mShiftKeyState
|
2011-12-07 10:31:11 +00:00
|
|
|
+ " symbol=" + mSymbolKeyState
|
|
|
|
+ " switch=" + switchStateToString(mSwitchState) + "]";
|
2011-12-05 06:02:06 +00:00
|
|
|
}
|
|
|
|
}
|