Remember typed words for auto-corrections

Change-Id: I475c2fa7604f91659100510079fa13c7615177e9
main
Amith Yamasani 2010-02-27 07:53:56 -08:00
parent dae9017014
commit a62f7c18f9
4 changed files with 279 additions and 34 deletions

View File

@ -14,7 +14,7 @@
* the License. * the License.
*/ */
package com.android.inputmethod.voice; package com.android.inputmethod.latin;
import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.ExtractedTextRequest;
@ -75,9 +75,21 @@ public class EditingUtil {
* represents the cursor, then "hello " will be returned. * represents the cursor, then "hello " will be returned.
*/ */
public static String getWordAtCursor( public static String getWordAtCursor(
InputConnection connection, String separators) { InputConnection connection, String separators) {
Range range = getWordRangeAtCursor(connection, separators); return getWordAtCursor(connection, separators, null);
return (range == null) ? null : range.word; }
/**
* @param connection connection to the current text field.
* @param sep characters which may separate words
* @return the word that surrounds the cursor, including up to one trailing
* separator. For example, if the field contains "he|llo world", where |
* represents the cursor, then "hello " will be returned.
*/
public static String getWordAtCursor(
InputConnection connection, String separators, Range range) {
Range r = getWordRangeAtCursor(connection, separators, range);
return (r == null) ? null : r.word;
} }
/** /**
@ -87,7 +99,7 @@ public class EditingUtil {
public static void deleteWordAtCursor( public static void deleteWordAtCursor(
InputConnection connection, String separators) { InputConnection connection, String separators) {
Range range = getWordRangeAtCursor(connection, separators); Range range = getWordRangeAtCursor(connection, separators, null);
if (range == null) return; if (range == null) return;
connection.finishComposingText(); connection.finishComposingText();
@ -101,18 +113,20 @@ public class EditingUtil {
/** /**
* Represents a range of text, relative to the current cursor position. * Represents a range of text, relative to the current cursor position.
*/ */
private static class Range { public static class Range {
/** Characters before selection start */ /** Characters before selection start */
int charsBefore; public int charsBefore;
/** /**
* Characters after selection start, including one trailing word * Characters after selection start, including one trailing word
* separator. * separator.
*/ */
int charsAfter; public int charsAfter;
/** The actual characters that make up a word */ /** The actual characters that make up a word */
String word; public String word;
public Range() {}
public Range(int charsBefore, int charsAfter, String word) { public Range(int charsBefore, int charsAfter, String word) {
if (charsBefore < 0 || charsAfter < 0) { if (charsBefore < 0 || charsAfter < 0) {
@ -125,7 +139,7 @@ public class EditingUtil {
} }
private static Range getWordRangeAtCursor( private static Range getWordRangeAtCursor(
InputConnection connection, String sep) { InputConnection connection, String sep, Range range) {
if (connection == null || sep == null) { if (connection == null || sep == null) {
return null; return null;
} }
@ -137,20 +151,22 @@ public class EditingUtil {
// Find first word separator before the cursor // Find first word separator before the cursor
int start = before.length(); int start = before.length();
while (--start > 0 && !isWhitespace(before.charAt(start - 1), sep)); while (start > 0 && !isWhitespace(before.charAt(start - 1), sep)) start--;
// Find last word separator after the cursor // Find last word separator after the cursor
int end = -1; int end = -1;
while (++end < after.length() && !isWhitespace(after.charAt(end), sep)); while (++end < after.length() && !isWhitespace(after.charAt(end), sep));
if (end < after.length() - 1) {
end++; // Include trailing space, if it exists, in word
}
int cursor = getCursorPosition(connection); int cursor = getCursorPosition(connection);
if (start >= 0 && cursor + end <= after.length() + before.length()) { if (start >= 0 && cursor + end <= after.length() + before.length()) {
String word = before.toString().substring(start, before.length()) String word = before.toString().substring(start, before.length())
+ after.toString().substring(0, end); + after.toString().substring(0, end);
return new Range(before.length() - start, end, word);
Range returnRange = range != null? range : new Range();
returnRange.charsBefore = before.length() - start;
returnRange.charsAfter = end;
returnRange.word = word;
return returnRange;
} }
return null; return null;

View File

@ -16,7 +16,6 @@
package com.android.inputmethod.latin; package com.android.inputmethod.latin;
import com.android.inputmethod.voice.EditingUtil;
import com.android.inputmethod.voice.FieldContext; import com.android.inputmethod.voice.FieldContext;
import com.android.inputmethod.voice.SettingsUtil; import com.android.inputmethod.voice.SettingsUtil;
import com.android.inputmethod.voice.VoiceInput; import com.android.inputmethod.voice.VoiceInput;
@ -128,6 +127,7 @@ public class LatinIME extends InputMethodService
private static final int MSG_UPDATE_SHIFT_STATE = 2; private static final int MSG_UPDATE_SHIFT_STATE = 2;
private static final int MSG_VOICE_RESULTS = 3; private static final int MSG_VOICE_RESULTS = 3;
private static final int MSG_START_LISTENING_AFTER_SWIPE = 4; private static final int MSG_START_LISTENING_AFTER_SWIPE = 4;
private static final int MSG_UPDATE_OLD_SUGGESTIONS = 5;
// If we detect a swipe gesture within N ms of typing, then swipe is // If we detect a swipe gesture within N ms of typing, then swipe is
// ignored, since it may in fact be two key presses in quick succession. // ignored, since it may in fact be two key presses in quick succession.
@ -205,6 +205,12 @@ public class LatinIME extends InputMethodService
private boolean mVoiceOnPrimary; private boolean mVoiceOnPrimary;
private int mOrientation; private int mOrientation;
private List<CharSequence> mSuggestPuncList; private List<CharSequence> mSuggestPuncList;
// Keep track of the last selection range to decide if we need to show word alternatives
private int mLastSelectionStart;
private int mLastSelectionEnd;
// Input type is such that we should not auto-correct
private boolean mInputTypeNoAutoCorrect;
// Indicates whether the suggestion strip is to be on in landscape // Indicates whether the suggestion strip is to be on in landscape
private boolean mJustAccepted; private boolean mJustAccepted;
@ -228,17 +234,66 @@ public class LatinIME extends InputMethodService
// Keeps track of most recently inserted text (multi-character key) for reverting // Keeps track of most recently inserted text (multi-character key) for reverting
private CharSequence mEnteredText; private CharSequence mEnteredText;
private boolean mRefreshKeyboardRequired;
// For each word, a list of potential replacements, usually from voice. // For each word, a list of potential replacements, usually from voice.
private Map<String, List<CharSequence>> mWordToSuggestions = private Map<String, List<CharSequence>> mWordToSuggestions =
new HashMap<String, List<CharSequence>>(); new HashMap<String, List<CharSequence>>();
private ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>();
private class VoiceResults { private class VoiceResults {
List<String> candidates; List<String> candidates;
Map<String, List<CharSequence>> alternatives; Map<String, List<CharSequence>> alternatives;
} }
public abstract static class WordAlternatives {
protected CharSequence mChosenWord;
private boolean mRefreshKeyboardRequired; public WordAlternatives() {
// Nothing
}
public WordAlternatives(CharSequence chosenWord) {
mChosenWord = chosenWord;
}
@Override
public int hashCode() {
return mChosenWord.hashCode();
}
public abstract CharSequence getOriginalWord();
public CharSequence getChosenWord() {
return mChosenWord;
}
public abstract List<CharSequence> getAlternatives();
}
public class TypedWordAlternatives extends WordAlternatives {
private WordComposer word;
public TypedWordAlternatives() {
// Nothing
}
public TypedWordAlternatives(CharSequence chosenWord, WordComposer wordComposer) {
super(chosenWord);
word = wordComposer;
}
@Override
public CharSequence getOriginalWord() {
return word.getTypedWord();
}
@Override
public List<CharSequence> getAlternatives() {
return getTypedSuggestions(word);
}
}
Handler mHandler = new Handler() { Handler mHandler = new Handler() {
@Override @Override
@ -247,6 +302,9 @@ public class LatinIME extends InputMethodService
case MSG_UPDATE_SUGGESTIONS: case MSG_UPDATE_SUGGESTIONS:
updateSuggestions(); updateSuggestions();
break; break;
case MSG_UPDATE_OLD_SUGGESTIONS:
setOldSuggestions();
break;
case MSG_START_TUTORIAL: case MSG_START_TUTORIAL:
if (mTutorial == null) { if (mTutorial == null) {
if (mInputView.isShown()) { if (mInputView.isShown()) {
@ -606,10 +664,11 @@ public class LatinIME extends InputMethodService
// clear whatever candidate text we have. // clear whatever candidate text we have.
if ((((mComposing.length() > 0 && mPredicting) || mVoiceInputHighlighted) if ((((mComposing.length() > 0 && mPredicting) || mVoiceInputHighlighted)
&& (newSelStart != candidatesEnd && (newSelStart != candidatesEnd
|| newSelEnd != candidatesEnd))) { || newSelEnd != candidatesEnd)
&& mLastSelectionStart != newSelStart)) {
mComposing.setLength(0); mComposing.setLength(0);
mPredicting = false; mPredicting = false;
updateSuggestions(); postUpdateSuggestions();
TextEntryState.reset(); TextEntryState.reset();
InputConnection ic = getCurrentInputConnection(); InputConnection ic = getCurrentInputConnection();
if (ic != null) { if (ic != null) {
@ -629,6 +688,21 @@ public class LatinIME extends InputMethodService
mJustAccepted = false; mJustAccepted = false;
postUpdateShiftKeyState(); postUpdateShiftKeyState();
// Make a note of the cursor position
mLastSelectionStart = newSelStart;
mLastSelectionEnd = newSelEnd;
// If a word is selected
if ((candidatesStart == candidatesEnd || newSelStart != oldSelStart)
&& (newSelStart < newSelEnd - 1 || (!mPredicting))
&& !mVoiceInputHighlighted) {
abortCorrection(false);
if (isCursorTouchingWord() || mLastSelectionStart < mLastSelectionEnd) {
postUpdateOldSuggestions();
}
}
if (VOICE_INSTALLED) { if (VOICE_INSTALLED) {
if (mShowingVoiceSuggestions) { if (mShowingVoiceSuggestions) {
if (mImmediatelyAfterVoiceSuggestions) { if (mImmediatelyAfterVoiceSuggestions) {
@ -671,6 +745,7 @@ public class LatinIME extends InputMethodService
mVoiceInput.cancel(); mVoiceInput.cancel();
} }
} }
mWordHistory.clear();
super.hideWindow(); super.hideWindow();
TextEntryState.endSession(); TextEntryState.endSession();
} }
@ -695,7 +770,6 @@ public class LatinIME extends InputMethodService
CompletionInfo ci = completions[i]; CompletionInfo ci = completions[i];
if (ci != null) stringList.add(ci.getText()); if (ci != null) stringList.add(ci.getText());
} }
//CharSequence typedWord = mWord.getTypedWord();
setSuggestions(stringList, true, true, true); setSuggestions(stringList, true, true, true);
mBestWord = null; mBestWord = null;
setCandidatesViewShown(isCandidateStripVisible() || mCompletionOn); setCandidatesViewShown(isCandidateStripVisible() || mCompletionOn);
@ -1007,6 +1081,7 @@ public class LatinIME extends InputMethodService
} }
InputConnection ic = getCurrentInputConnection(); InputConnection ic = getCurrentInputConnection();
if (ic == null) return; if (ic == null) return;
abortCorrection(false);
ic.beginBatchEdit(); ic.beginBatchEdit();
if (mPredicting) { if (mPredicting) {
commitTyped(ic); commitTyped(ic);
@ -1086,6 +1161,13 @@ public class LatinIME extends InputMethodService
} }
} }
private void abortCorrection(boolean force) {
if (force || TextEntryState.isCorrecting()) {
getCurrentInputConnection().finishComposingText();
setSuggestions(null, false, false, false);
}
}
private void handleCharacter(int primaryCode, int[] keyCodes) { private void handleCharacter(int primaryCode, int[] keyCodes) {
if (VOICE_INSTALLED && mVoiceInputHighlighted) { if (VOICE_INSTALLED && mVoiceInputHighlighted) {
commitVoiceInput(); commitVoiceInput();
@ -1095,11 +1177,13 @@ public class LatinIME extends InputMethodService
// Assume input length is 1. This assumption fails for smiley face insertions. // Assume input length is 1. This assumption fails for smiley face insertions.
mVoiceInput.incrementTextModificationInsertCount(1); mVoiceInput.incrementTextModificationInsertCount(1);
} }
abortCorrection(false);
if (isAlphabet(primaryCode) && isPredictionOn() && !isCursorTouchingWord()) { if (isAlphabet(primaryCode) && isPredictionOn() && !isCursorTouchingWord()) {
if (!mPredicting) { if (!mPredicting) {
mPredicting = true; mPredicting = true;
mComposing.setLength(0); mComposing.setLength(0);
saveWordInHistory(mBestWord);
mWord.reset(); mWord.reset();
} }
} }
@ -1150,6 +1234,7 @@ public class LatinIME extends InputMethodService
InputConnection ic = getCurrentInputConnection(); InputConnection ic = getCurrentInputConnection();
if (ic != null) { if (ic != null) {
ic.beginBatchEdit(); ic.beginBatchEdit();
abortCorrection(false);
} }
if (mPredicting) { if (mPredicting) {
// In certain languages where single quote is a separator, it's better // In certain languages where single quote is a separator, it's better
@ -1189,7 +1274,6 @@ public class LatinIME extends InputMethodService
&& primaryCode != KEYCODE_ENTER) { && primaryCode != KEYCODE_ENTER) {
swapPunctuationAndSpace(); swapPunctuationAndSpace();
} else if (isPredictionOn() && primaryCode == KEYCODE_SPACE) { } else if (isPredictionOn() && primaryCode == KEYCODE_SPACE) {
//else if (TextEntryState.STATE_SPACE_AFTER_ACCEPTED) {
doubleSpace(); doubleSpace();
} }
if (pickedDefault && mBestWord != null) { if (pickedDefault && mBestWord != null) {
@ -1211,6 +1295,17 @@ public class LatinIME extends InputMethodService
TextEntryState.endSession(); TextEntryState.endSession();
} }
private void saveWordInHistory(CharSequence result) {
if (mWord.size() <= 1) {
mWord.reset();
return;
}
TypedWordAlternatives entry = new TypedWordAlternatives(result, mWord);
// Create a new WordComposer as the old one is being saved for later use
mWord = new WordComposer(mWord);
mWordHistory.add(entry);
}
private void checkToggleCapsLock() { private void checkToggleCapsLock() {
if (mInputView.getKeyboard().isShifted()) { if (mInputView.getKeyboard().isShifted()) {
toggleCapsLock(); toggleCapsLock();
@ -1229,6 +1324,11 @@ public class LatinIME extends InputMethodService
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SUGGESTIONS), 100); mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SUGGESTIONS), 100);
} }
private void postUpdateOldSuggestions() {
mHandler.removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS), 300);
}
private boolean isPredictionOn() { private boolean isPredictionOn() {
boolean predictionOn = mPredictionOn; boolean predictionOn = mPredictionOn;
return predictionOn; return predictionOn;
@ -1453,24 +1553,45 @@ public class LatinIME extends InputMethodService
setNextSuggestions(); setNextSuggestions();
return; return;
} }
showSuggestions(mWord);
}
List<CharSequence> stringList = mSuggest.getSuggestions(mInputView, mWord, false); private List<CharSequence> getTypedSuggestions(WordComposer word) {
List<CharSequence> stringList = mSuggest.getSuggestions(mInputView, word, false);
return stringList;
}
private void showCorrections(WordAlternatives alternatives) {
List<CharSequence> stringList = alternatives.getAlternatives();
((LatinKeyboard) mInputView.getKeyboard()).setPreferredLetters(null);
showSuggestions(stringList, alternatives.getOriginalWord(), false, false);
}
private void showSuggestions(WordComposer word) {
List<CharSequence> stringList = mSuggest.getSuggestions(mInputView, word, false);
int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies(); int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies();
((LatinKeyboard) mInputView.getKeyboard()).setPreferredLetters(nextLettersFrequencies); ((LatinKeyboard) mInputView.getKeyboard()).setPreferredLetters(nextLettersFrequencies);
boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasMinimalCorrection(); boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasMinimalCorrection();
//|| mCorrectionMode == mSuggest.CORRECTION_FULL; //|| mCorrectionMode == mSuggest.CORRECTION_FULL;
CharSequence typedWord = mWord.getTypedWord(); CharSequence typedWord = word.getTypedWord();
// If we're in basic correct // If we're in basic correct
boolean typedWordValid = mSuggest.isValidWord(typedWord) || boolean typedWordValid = mSuggest.isValidWord(typedWord) ||
(preferCapitalization() && mSuggest.isValidWord(typedWord.toString().toLowerCase())); (preferCapitalization()
&& mSuggest.isValidWord(typedWord.toString().toLowerCase()));
if (mCorrectionMode == Suggest.CORRECTION_FULL) { if (mCorrectionMode == Suggest.CORRECTION_FULL) {
correctionAvailable |= typedWordValid; correctionAvailable |= typedWordValid;
} }
// Don't auto-correct words with multiple capital letter // Don't auto-correct words with multiple capital letter
correctionAvailable &= !mWord.isMostlyCaps(); correctionAvailable &= !word.isMostlyCaps();
correctionAvailable &= !TextEntryState.isCorrecting();
showSuggestions(stringList, typedWord, typedWordValid, correctionAvailable);
}
private void showSuggestions(List<CharSequence> stringList, CharSequence typedWord,
boolean typedWordValid, boolean correctionAvailable) {
setSuggestions(stringList, false, typedWordValid, correctionAvailable); setSuggestions(stringList, false, typedWordValid, correctionAvailable);
if (stringList.size() > 0) { if (stringList.size() > 0) {
if (correctionAvailable && !typedWordValid && stringList.size() > 1) { if (correctionAvailable && !typedWordValid && stringList.size() > 1) {
@ -1508,6 +1629,7 @@ public class LatinIME extends InputMethodService
mVoiceInput.logTextModifiedByChooseSuggestion(suggestion.length()); mVoiceInput.logTextModifiedByChooseSuggestion(suggestion.length());
} }
final boolean correcting = TextEntryState.isCorrecting();
InputConnection ic = getCurrentInputConnection(); InputConnection ic = getCurrentInputConnection();
if (ic != null) { if (ic != null) {
ic.beginBatchEdit(); ic.beginBatchEdit();
@ -1545,10 +1667,11 @@ public class LatinIME extends InputMethodService
} }
TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion); TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
// Follow it with a space // Follow it with a space
if (mAutoSpace) { if (mAutoSpace && !correcting) {
sendSpace(); sendSpace();
mJustAddedAutoSpace = true; mJustAddedAutoSpace = true;
} }
// Fool the state watcher so that a subsequent backspace will not do a revert // Fool the state watcher so that a subsequent backspace will not do a revert
TextEntryState.typedCharacter((char) KEYCODE_SPACE, true); TextEntryState.typedCharacter((char) KEYCODE_SPACE, true);
if (index == 0 && mCorrectionMode > 0 && !mSuggest.isValidWord(suggestion)) { if (index == 0 && mCorrectionMode > 0 && !mSuggest.isValidWord(suggestion)) {
@ -1576,6 +1699,7 @@ public class LatinIME extends InputMethodService
ic.commitText(suggestion, 1); ic.commitText(suggestion, 1);
} }
} }
saveWordInHistory(suggestion);
mPredicting = false; mPredicting = false;
mCommittedLength = suggestion.length(); mCommittedLength = suggestion.length();
((LatinKeyboard) mInputView.getKeyboard()).setPreferredLetters(null); ((LatinKeyboard) mInputView.getKeyboard()).setPreferredLetters(null);
@ -1583,16 +1707,99 @@ public class LatinIME extends InputMethodService
updateShiftKeyState(getCurrentInputEditorInfo()); updateShiftKeyState(getCurrentInputEditorInfo());
} }
private void setOldSuggestions() {
// TODO: Inefficient to check if touching word and then get the touching word. Do it
// in one go.
InputConnection ic = getCurrentInputConnection();
if (ic == null) return;
ic.beginBatchEdit();
// If there is a selection, then undo the selection first. Unfortunately this causes
// a flicker. TODO: Add getSelectionText() to InputConnection API.
if (mLastSelectionStart < mLastSelectionEnd) {
ic.setSelection(mLastSelectionStart, mLastSelectionStart);
}
if (!mPredicting && isCursorTouchingWord()) {
EditingUtil.Range range = new EditingUtil.Range();
CharSequence touching =
EditingUtil.getWordAtCursor(getCurrentInputConnection(), mWordSeparators,
range);
if (touching != null && touching.length() > 1) {
if (mWordSeparators.indexOf(touching.charAt(touching.length() - 1)) > 0) {
touching = touching.toString().substring(0, touching.length() - 1);
}
// Search for result in word history
WordComposer foundWord = null;
WordAlternatives alternatives = null;
for (WordAlternatives entry : mWordHistory) {
if (TextUtils.equals(entry.getChosenWord(), touching)) {
if (entry instanceof TypedWordAlternatives) {
foundWord = ((TypedWordAlternatives)entry).word;
}
alternatives = entry;
break;
}
}
// If we didn't find a match, at least suggest completions
if (foundWord == null && mSuggest.isValidWord(touching)) {
foundWord = new WordComposer();
for (int i = 0; i < touching.length(); i++) {
foundWord.add(touching.charAt(i), new int[] { touching.charAt(i) });
}
}
// Found a match, show suggestions
if (foundWord != null || alternatives != null) {
mSuggestionShouldReplaceCurrentWord = true;
underlineWord(touching, range.charsBefore, range.charsAfter);
TextEntryState.selectedForCorrection();
if (alternatives == null) alternatives = new TypedWordAlternatives(touching,
foundWord);
showCorrections(alternatives);
if (foundWord != null) {
mWord = foundWord;
} else {
mWord.reset();
}
// Revert the selection
if (mLastSelectionStart < mLastSelectionEnd) {
ic.setSelection(mLastSelectionStart, mLastSelectionEnd);
}
ic.endBatchEdit();
return;
}
abortCorrection(true);
} else {
abortCorrection(true);
setNextSuggestions();
}
} else {
abortCorrection(true);
}
// Revert the selection
if (mLastSelectionStart < mLastSelectionEnd) {
ic.setSelection(mLastSelectionStart, mLastSelectionEnd);
}
ic.endBatchEdit();
}
private void setNextSuggestions() { private void setNextSuggestions() {
setSuggestions(mSuggestPuncList, false, false, false); setSuggestions(mSuggestPuncList, false, false, false);
} }
private void underlineWord(CharSequence word, int left, int right) {
InputConnection ic = getCurrentInputConnection();
if (ic == null) return;
ic.deleteSurroundingText(left, right);
ic.setComposingText(word, 1);
ic.setSelection(mLastSelectionStart, mLastSelectionStart);
}
private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta) { private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta) {
if (suggestion == null || suggestion.length() < 1) return;
// Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
// adding words in situations where the user or application really didn't // adding words in situations where the user or application really didn't
// want corrections enabled or learned. // want corrections enabled or learned.
if (!(mCorrectionMode == Suggest.CORRECTION_FULL)) return; if (!(mCorrectionMode == Suggest.CORRECTION_FULL)) return;
if (mAutoDictionary.isValidWord(suggestion) if (suggestion != null && mAutoDictionary.isValidWord(suggestion)
|| (!mSuggest.isValidWord(suggestion.toString()) || (!mSuggest.isValidWord(suggestion.toString())
&& !mSuggest.isValidWord(suggestion.toString().toLowerCase()))) { && !mSuggest.isValidWord(suggestion.toString().toLowerCase()))) {
mAutoDictionary.addWord(suggestion.toString(), frequencyDelta); mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
@ -2008,7 +2215,6 @@ public class LatinIME extends InputMethodService
private static final int CPS_BUFFER_SIZE = 16; private static final int CPS_BUFFER_SIZE = 16;
private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE]; private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
private int mCpsIndex; private int mCpsIndex;
private boolean mInputTypeNoAutoCorrect;
private void measureCps() { private void measureCps() {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();

View File

@ -69,9 +69,11 @@ public class TextEntryState {
public static final int STATE_SPACE_AFTER_ACCEPTED = 7; public static final int STATE_SPACE_AFTER_ACCEPTED = 7;
public static final int STATE_SPACE_AFTER_PICKED = 8; public static final int STATE_SPACE_AFTER_PICKED = 8;
public static final int STATE_UNDO_COMMIT = 9; public static final int STATE_UNDO_COMMIT = 9;
public static final int STATE_CORRECTING = 10;
public static final int STATE_PICKED_CORRECTION = 11;
private static int sState = STATE_UNKNOWN; private static int sState = STATE_UNKNOWN;
private static FileOutputStream sKeyLocationFile; private static FileOutputStream sKeyLocationFile;
private static FileOutputStream sUserActionFile; private static FileOutputStream sUserActionFile;
@ -139,12 +141,17 @@ public class TextEntryState {
public static void acceptedSuggestion(CharSequence typedWord, CharSequence actualWord) { public static void acceptedSuggestion(CharSequence typedWord, CharSequence actualWord) {
sManualSuggestCount++; sManualSuggestCount++;
int oldState = sState;
if (typedWord.equals(actualWord)) { if (typedWord.equals(actualWord)) {
acceptedTyped(typedWord); acceptedTyped(typedWord);
} }
sState = STATE_PICKED_SUGGESTION; sState = oldState == STATE_CORRECTING ? STATE_PICKED_CORRECTION : STATE_PICKED_SUGGESTION;
} }
public static void selectedForCorrection() {
sState = STATE_CORRECTING;
}
public static void typedCharacter(char c, boolean isSeparator) { public static void typedCharacter(char c, boolean isSeparator) {
boolean isSpace = c == ' '; boolean isSpace = c == ' ';
switch (sState) { switch (sState) {
@ -166,6 +173,7 @@ public class TextEntryState {
} }
break; break;
case STATE_PICKED_SUGGESTION: case STATE_PICKED_SUGGESTION:
case STATE_PICKED_CORRECTION:
if (isSpace) { if (isSpace) {
sState = STATE_SPACE_AFTER_PICKED; sState = STATE_SPACE_AFTER_PICKED;
} else if (isSeparator) { } else if (isSeparator) {
@ -192,6 +200,10 @@ public class TextEntryState {
} else { } else {
sState = STATE_IN_WORD; sState = STATE_IN_WORD;
} }
break;
case STATE_CORRECTING:
sState = STATE_START;
break;
} }
} }
@ -212,7 +224,11 @@ public class TextEntryState {
public static int getState() { public static int getState() {
return sState; return sState;
} }
public static boolean isCorrecting() {
return sState == STATE_CORRECTING || sState == STATE_PICKED_CORRECTION;
}
public static void keyPressedAt(Key key, int x, int y) { public static void keyPressedAt(Key key, int x, int y) {
if (LOGGING && sKeyLocationFile != null && key.codes[0] >= 32) { if (LOGGING && sKeyLocationFile != null && key.codes[0] >= 32) {
String out = String out =

View File

@ -49,6 +49,13 @@ public class WordComposer {
mTypedWord = new StringBuilder(20); mTypedWord = new StringBuilder(20);
} }
WordComposer(WordComposer copy) {
mCodes = (ArrayList<int[]>) copy.mCodes.clone();
mPreferredWord = copy.mPreferredWord;
mTypedWord = new StringBuilder(copy.mTypedWord);
mCapsCount = copy.mCapsCount;
mAutoCapitalized = copy.mAutoCapitalized;
}
/** /**
* Clear out the keys registered so far. * Clear out the keys registered so far.
*/ */