diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin/LatinIME.java')
-rw-r--r-- | java/src/com/android/inputmethod/latin/LatinIME.java | 137 |
1 files changed, 118 insertions, 19 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 47d51c586..0e1c4dc31 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -161,6 +161,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mPositionalInfoForUserDictPendingAddition = null; private final WordComposer mWordComposer = new WordComposer(); private final RichInputConnection mConnection = new RichInputConnection(this); + private final RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus(); // Keep track of the last selection range to decide if we need to show word alternatives private static final int NOT_A_CURSOR_POSITION = -1; @@ -741,6 +742,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction resetComposingState(true /* alsoResetLastComposedWord */); mDeleteCount = 0; mSpaceState = SPACE_STATE_NONE; + mRecapitalizeStatus.deactivate(); mCurrentlyPressedHardwareKeys.clear(); if (mSuggestionStripView != null) { @@ -923,7 +925,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // We moved the cursor. If we are touching a word, we need to resume suggestion. mHandler.postResumeSuggestions(); - + // Reset the last recapitalization. + mRecapitalizeStatus.deactivate(); mKeyboardSwitcher.updateShiftState(); } mExpectingUpdateSelection = false; @@ -993,8 +996,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } } if (!mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) return; - mApplicationSpecifiedCompletions = - CompletionInfoUtils.removeNulls(applicationSpecifiedCompletions); if (applicationSpecifiedCompletions == null) { clearSuggestionStrip(); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { @@ -1002,6 +1003,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } return; } + mApplicationSpecifiedCompletions = + CompletionInfoUtils.removeNulls(applicationSpecifiedCompletions); final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords = SuggestedWords.getFromApplicationSpecifiedCompletions( @@ -1177,6 +1180,15 @@ public final class LatinIME extends InputMethodService implements KeyboardAction SPACE_STATE_PHANTOM == mSpaceState); } + public int getCurrentRecapitalizeState() { + if (!mRecapitalizeStatus.isActive() + || !mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) { + // Not recapitalizing at the moment + return RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; + } + return mRecapitalizeStatus.getCurrentMode(); + } + // Factor in auto-caps and manual caps and compute the current caps mode. private int getActualCapsMode() { final int keyboardShiftMode = mKeyboardSwitcher.getKeyboardShiftMode(); @@ -1387,8 +1399,18 @@ public final class LatinIME extends InputMethodService implements KeyboardAction LatinImeLogger.logOnDelete(x, y); break; case Constants.CODE_SHIFT: + // Note: calling back to the keyboard on Shift key is handled in onPressKey() + // and onReleaseKey(). + final Keyboard currentKeyboard = switcher.getKeyboard(); + if (null != currentKeyboard && currentKeyboard.mId.isAlphabetKeyboard()) { + // TODO: Instead of checking for alphabetic keyboard here, separate keycodes for + // alphabetic shift and shift while in symbol layout. + handleRecapitalize(); + } + break; case Constants.CODE_SWITCH_ALPHA_SYMBOL: - // Shift and symbol key is handled in onPressKey() and onReleaseKey(). + // Note: calling back to the keyboard on symbol key is handled in onPressKey() + // and onReleaseKey(). break; case Constants.CODE_SETTINGS: onSettingsKeyPressed(); @@ -1466,7 +1488,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction "", mWordComposer.getTypedWord(), " ", mWordComposer); } } - commitTyped(LastComposedWord.NOT_A_SEPARATOR); + if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { + // If we are in the middle of a recorrection, we need to commit the recorrection + // first so that we can insert the character at the current cursor position. + resetEntireInputState(mLastSelectionStart); + } else { + commitTyped(LastComposedWord.NOT_A_SEPARATOR); + } } final int keyX, keyY; final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); @@ -1522,8 +1550,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } final int wordComposerSize = mWordComposer.size(); // Since isComposingWord() is true, the size is at least 1. - final int lastChar = mWordComposer.getCodeAt(wordComposerSize - 1); - if (wordComposerSize <= 1) { + final int lastChar = mWordComposer.getCodeBeforeCursor(); + if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { + // If we are in the middle of a recorrection, we need to commit the recorrection + // first so that we can insert the batch input at the current cursor position. + resetEntireInputState(mLastSelectionStart); + } else if (wordComposerSize <= 1) { // We auto-correct the previous (typed, not gestured) string iff it's one character // long. The reason for this is, even in the middle of gesture typing, you'll still // tap one-letter words and you want them auto-corrected (typically, "i" in English @@ -1734,8 +1766,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // during key repeat. mHandler.postUpdateShiftState(); - if (mWordComposer.isComposingWord() && !mWordComposer.isCursorAtEndOfComposingWord()) { + if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { + // If we are in the middle of a recorrection, we need to commit the recorrection + // first so that we can remove the character at the current cursor position. resetEntireInputState(mLastSelectionStart); + // When we exit this if-clause, mWordComposer.isComposingWord() will return false. } if (mWordComposer.isComposingWord()) { final int length = mWordComposer.size(); @@ -1870,7 +1905,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction promotePhantomSpace(); } - if (mWordComposer.isComposingWord() && !mWordComposer.isCursorAtEndOfComposingWord()) { + if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { + // If we are in the middle of a recorrection, we need to commit the recorrection + // first so that we can insert the character at the current cursor position. resetEntireInputState(mLastSelectionStart); isComposingWord = false; } @@ -1928,6 +1965,38 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } } + private void handleRecapitalize() { + if (mLastSelectionStart == mLastSelectionEnd) return; // No selection + // If we have a recapitalize in progress, use it; otherwise, create a new one. + if (!mRecapitalizeStatus.isActive() + || !mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) { + mRecapitalizeStatus.initialize(mLastSelectionStart, mLastSelectionEnd, + mConnection.getSelectedText(0 /* flags, 0 for no styles */).toString(), + mSettings.getCurrentLocale(), mSettings.getWordSeparators()); + // We trim leading and trailing whitespace. + mRecapitalizeStatus.trim(); + // Trimming the object may have changed the length of the string, and we need to + // reposition the selection handles accordingly. As this result in an IPC call, + // only do it if it's actually necessary, in other words if the recapitalize status + // is not set at the same place as before. + if (!mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) { + mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart(); + mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd(); + mConnection.setSelection(mLastSelectionStart, mLastSelectionEnd); + } + } + mRecapitalizeStatus.rotate(); + final int numCharsDeleted = mLastSelectionEnd - mLastSelectionStart; + mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd); + mConnection.deleteSurroundingText(numCharsDeleted, 0); + mConnection.commitText(mRecapitalizeStatus.getRecapitalizedString(), 0); + mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart(); + mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd(); + mConnection.setSelection(mLastSelectionStart, mLastSelectionEnd); + // Match the keyboard to the new state. + mKeyboardSwitcher.updateShiftState(); + } + // Returns true if we did an autocorrection, false otherwise. private boolean handleSeparator(final int primaryCode, final int x, final int y, final int spaceState) { @@ -1935,7 +2004,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord()); } boolean didAutoCorrect = false; - // Handle separator + if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { + // If we are in the middle of a recorrection, we need to commit the recorrection + // first so that we can insert the separator at the current cursor position. + resetEntireInputState(mLastSelectionStart); + } if (mWordComposer.isComposingWord()) { if (mSettings.getCurrent().mCorrectionEnabled) { // TODO: maybe cache Strings in an <String> sparse array or something @@ -2356,10 +2429,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) return; final Range range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(), 0 /* additionalPrecedingWordsCount */); + if (null == range) return; // Happens if we don't have an input connection at all final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList(); + final String typedWord = range.mWord.toString(); if (range.mWord instanceof SpannableString) { final SpannableString spannableString = (SpannableString)range.mWord; - final String typedWord = spannableString.toString(); int i = 0; for (Object object : spannableString.getSpans(0, spannableString.length(), SuggestionSpan.class)) { @@ -2374,18 +2448,42 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } } } - mWordComposer.setComposingWord(range.mWord, mKeyboardSwitcher.getKeyboard()); + mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard()); mWordComposer.setCursorPositionWithinWord(range.mCharsBefore); mConnection.setComposingRegion(mLastSelectionStart - range.mCharsBefore, mLastSelectionEnd + range.mCharsAfter); + final SuggestedWords suggestedWords; if (suggestions.isEmpty()) { - suggestions.add(new SuggestedWordInfo(range.mWord.toString(), 1, - SuggestedWordInfo.KIND_TYPED, Dictionary.TYPE_RESUMED)); + // We come here if there weren't any suggestion spans on this word. We will try to + // compute suggestions for it instead. + final SuggestedWords suggestedWordsIncludingTypedWord = + getSuggestedWords(Suggest.SESSION_TYPING); + if (suggestedWordsIncludingTypedWord.size() > 1) { + // We were able to compute new suggestions for this word. + // Remove the typed word, since we don't want to display it in this case. + // The #getSuggestedWordsExcludingTypedWord() method sets willAutoCorrect to false. + suggestedWords = + suggestedWordsIncludingTypedWord.getSuggestedWordsExcludingTypedWord(); + } else { + // No saved suggestions, and we were unable to compute any good one either. + // Rather than displaying an empty suggestion strip, we'll display the original + // word alone in the middle. + // Since there is only one word, willAutoCorrect is false. + suggestedWords = suggestedWordsIncludingTypedWord; + } + } else { + // We found suggestion spans in the word. We'll create the SuggestedWords out of + // them, and make willAutoCorrect false. + suggestedWords = new SuggestedWords(suggestions, + true /* typedWordValid */, false /* willAutoCorrect */, + false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, + false /* isPrediction */); } - showSuggestionStrip(new SuggestedWords(suggestions, - true /* typedWordValid */, false /* willAutoCorrect */, - false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, - false /* isPrediction */), range.mWord.toString()); + + // Note that it's very important here that suggestedWords.mWillAutoCorrect is false. + // We never want to auto-correct on a resumed suggestion. Please refer to the three + // places above where suggestedWords is affected. + showSuggestionStrip(suggestedWords, typedWord); } /** @@ -2461,7 +2559,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // This essentially inserts a space, and that's it. public void promotePhantomSpace() { - if (mSettings.getCurrent().shouldInsertSpacesAutomatically()) { + if (mSettings.getCurrent().shouldInsertSpacesAutomatically() + && !mConnection.textBeforeCursorLooksLikeURL()) { sendKeyCodePoint(Constants.CODE_SPACE); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.latinIME_promotePhantomSpace(); |