diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index dee7cd466..cbc52d98c 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -426,119 +426,16 @@ public final class InputLogic { cancelDoubleSpacePeriodCountdown(); } - boolean didAutoCorrect = false; + final boolean didAutoCorrect; if (processedEvent.isConsumed()) { - // A consumed event may have text to commit and an update to the composing state, so - // we evaluate both. With some combiners, it's possible than an event contains both - // and we enter both of the following if clauses. - final CharSequence textToCommit = processedEvent.getTextToCommit(); - if (!TextUtils.isEmpty(textToCommit)) { - mConnection.commitText(textToCommit, 1); - inputTransaction.setDidAffectContents(); - } - if (mWordComposer.isComposingWord()) { - mConnection.setComposingText(mWordComposer.getTypedWord(), 1); - inputTransaction.setDidAffectContents(); - inputTransaction.setRequiresUpdateSuggestions(); - } + handleConsumedEvent(inputTransaction); + didAutoCorrect = false; } else if (processedEvent.isFunctionalKeyEvent()) { - // A special key, like delete, shift, emoji, or the settings key. - switch (processedEvent.mKeyCode) { - case Constants.CODE_DELETE: - handleBackspace(inputTransaction, currentKeyboardScriptId); - // Backspace is a functional key, but it affects the contents of the editor. - inputTransaction.setDidAffectContents(); - break; - case Constants.CODE_SHIFT: - performRecapitalization(inputTransaction.mSettingsValues); - inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); - if (mSuggestedWords.mIsPrediction) { - inputTransaction.setRequiresUpdateSuggestions(); - } - break; - case Constants.CODE_CAPSLOCK: - // Note: Changing keyboard to shift lock state is handled in - // {@link KeyboardSwitcher#onCodeInput(int)}. - break; - case Constants.CODE_SYMBOL_SHIFT: - // Note: Calling back to the keyboard on the symbol Shift key is handled in - // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}. - break; - case Constants.CODE_SWITCH_ALPHA_SYMBOL: - // Note: Calling back to the keyboard on symbol key is handled in - // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}. - break; - case Constants.CODE_SETTINGS: - onSettingsKeyPressed(); - break; - case Constants.CODE_SHORTCUT: - // We need to switch to the shortcut IME. This is handled by LatinIME since the - // input logic has no business with IME switching. - break; - case Constants.CODE_ACTION_NEXT: - performEditorAction(EditorInfo.IME_ACTION_NEXT); - break; - case Constants.CODE_ACTION_PREVIOUS: - performEditorAction(EditorInfo.IME_ACTION_PREVIOUS); - break; - case Constants.CODE_LANGUAGE_SWITCH: - handleLanguageSwitchKey(); - break; - case Constants.CODE_EMOJI: - // Note: Switching emoji keyboard is being handled in - // {@link KeyboardState#onCodeInput(int,int)}. - break; - case Constants.CODE_ALPHA_FROM_EMOJI: - // Note: Switching back from Emoji keyboard to the main keyboard is being - // handled in {@link KeyboardState#onCodeInput(int,int)}. - break; - case Constants.CODE_SHIFT_ENTER: - // TODO: remove this object - final Event tmpEvent = Event.createSoftwareKeypressEvent(Constants.CODE_ENTER, - processedEvent.mKeyCode, processedEvent.mX, processedEvent.mY, - processedEvent.isKeyRepeat()); - final InputTransaction tmpTransaction = new InputTransaction( - inputTransaction.mSettingsValues, tmpEvent, - inputTransaction.mTimestamp, inputTransaction.mSpaceState, - inputTransaction.mShiftState); - didAutoCorrect = handleNonSpecialCharacter(tmpTransaction, handler); - // Shift + Enter is treated as a functional key but it results in adding a new - // line, so that does affect the contents of the editor. - inputTransaction.setDidAffectContents(); - break; - default: - throw new RuntimeException("Unknown key code : " + processedEvent.mKeyCode); - } + didAutoCorrect = handleFunctionalEventAndReturnIfDidAutoCorrect(inputTransaction, + currentKeyboardScriptId, handler); } else { - inputTransaction.setDidAffectContents(); - switch (processedEvent.mCodePoint) { - case Constants.CODE_ENTER: - final EditorInfo editorInfo = getCurrentInputEditorInfo(); - final int imeOptionsActionId = - InputTypeUtils.getImeOptionsActionIdFromEditorInfo(editorInfo); - if (InputTypeUtils.IME_ACTION_CUSTOM_LABEL == imeOptionsActionId) { - // Either we have an actionLabel and we should performEditorAction with - // actionId regardless of its value. - performEditorAction(editorInfo.actionId); - } else if (EditorInfo.IME_ACTION_NONE != imeOptionsActionId) { - // We didn't have an actionLabel, but we had another action to execute. - // EditorInfo.IME_ACTION_NONE explicitly means no action. In contrast, - // EditorInfo.IME_ACTION_UNSPECIFIED is the default value for an action, so it - // means there should be an action and the app didn't bother to set a specific - // code for it - presumably it only handles one. It does not have to be treated - // in any specific way: anything that is not IME_ACTION_NONE should be sent to - // performEditorAction. - performEditorAction(imeOptionsActionId); - } else { - // No action label, and the action from imeOptions is NONE: this is a regular - // enter key that should input a carriage return. - didAutoCorrect = handleNonSpecialCharacter(inputTransaction, handler); - } - break; - default: - didAutoCorrect = handleNonSpecialCharacter(inputTransaction, handler); - break; - } + didAutoCorrect = handleNonFunctionalEventAndReturnIfDidAutoCorrect(inputTransaction, + handler); } if (!didAutoCorrect && processedEvent.mKeyCode != Constants.CODE_SHIFT && processedEvent.mKeyCode != Constants.CODE_CAPSLOCK @@ -685,6 +582,163 @@ public final class InputLogic { } } + /** + * Handle a consumed event. + * + * Consumed events represent events that have already been consumed, typically by the + * combining chain. + * + * @param inputTransaction The transaction in progress. + */ + private void handleConsumedEvent(final InputTransaction inputTransaction) { + // A consumed event may have text to commit and an update to the composing state, so + // we evaluate both. With some combiners, it's possible than an event contains both + // and we enter both of the following if clauses. + final CharSequence textToCommit = inputTransaction.mEvent.getTextToCommit(); + if (!TextUtils.isEmpty(textToCommit)) { + mConnection.commitText(textToCommit, 1); + inputTransaction.setDidAffectContents(); + } + if (mWordComposer.isComposingWord()) { + mConnection.setComposingText(mWordComposer.getTypedWord(), 1); + inputTransaction.setDidAffectContents(); + inputTransaction.setRequiresUpdateSuggestions(); + } + } + + /** + * Handle a functional key event. + * + * A functional event is a special key, like delete, shift, emoji, or the settings key. + * Non-special keys are those that generate a single code point. + * This includes all letters, digits, punctuation, separators, emoji. It excludes keys that + * manage keyboard-related stuff like shift, language switch, settings, layout switch, or + * any key that results in multiple code points like the ".com" key. + * + * @param inputTransaction The transaction in progress. + * @return whether this caused an auto-correction to happen. + */ + private boolean handleFunctionalEventAndReturnIfDidAutoCorrect( + final InputTransaction inputTransaction, + // TODO: remove these arguments + final int currentKeyboardScriptId, final LatinIME.UIHandler handler) { + final Event event = inputTransaction.mEvent; + boolean didAutoCorrect = false; + switch (event.mKeyCode) { + case Constants.CODE_DELETE: + handleBackspace(inputTransaction, currentKeyboardScriptId); + // Backspace is a functional key, but it affects the contents of the editor. + inputTransaction.setDidAffectContents(); + break; + case Constants.CODE_SHIFT: + performRecapitalization(inputTransaction.mSettingsValues); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); + if (mSuggestedWords.mIsPrediction) { + inputTransaction.setRequiresUpdateSuggestions(); + } + break; + case Constants.CODE_CAPSLOCK: + // Note: Changing keyboard to shift lock state is handled in + // {@link KeyboardSwitcher#onCodeInput(int)}. + break; + case Constants.CODE_SYMBOL_SHIFT: + // Note: Calling back to the keyboard on the symbol Shift key is handled in + // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}. + break; + case Constants.CODE_SWITCH_ALPHA_SYMBOL: + // Note: Calling back to the keyboard on symbol key is handled in + // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}. + break; + case Constants.CODE_SETTINGS: + onSettingsKeyPressed(); + break; + case Constants.CODE_SHORTCUT: + // We need to switch to the shortcut IME. This is handled by LatinIME since the + // input logic has no business with IME switching. + break; + case Constants.CODE_ACTION_NEXT: + performEditorAction(EditorInfo.IME_ACTION_NEXT); + break; + case Constants.CODE_ACTION_PREVIOUS: + performEditorAction(EditorInfo.IME_ACTION_PREVIOUS); + break; + case Constants.CODE_LANGUAGE_SWITCH: + handleLanguageSwitchKey(); + break; + case Constants.CODE_EMOJI: + // Note: Switching emoji keyboard is being handled in + // {@link KeyboardState#onCodeInput(int,int)}. + break; + case Constants.CODE_ALPHA_FROM_EMOJI: + // Note: Switching back from Emoji keyboard to the main keyboard is being + // handled in {@link KeyboardState#onCodeInput(int,int)}. + break; + case Constants.CODE_SHIFT_ENTER: + // TODO: remove this object + final Event tmpEvent = Event.createSoftwareKeypressEvent(Constants.CODE_ENTER, + event.mKeyCode, event.mX, event.mY, event.isKeyRepeat()); + final InputTransaction tmpTransaction = new InputTransaction( + inputTransaction.mSettingsValues, tmpEvent, + inputTransaction.mTimestamp, inputTransaction.mSpaceState, + inputTransaction.mShiftState); + didAutoCorrect = handleNonSpecialCharacter(tmpTransaction, handler); + // Shift + Enter is treated as a functional key but it results in adding a new + // line, so that does affect the contents of the editor. + inputTransaction.setDidAffectContents(); + break; + default: + throw new RuntimeException("Unknown key code : " + event.mKeyCode); + } + return didAutoCorrect; + } + + /** + * Handle an event that is not a functional event. + * + * These events are generally events that cause input, but in some cases they may do other + * things like trigger an editor action. + * + * @param inputTransaction The transaction in progress. + * @return whether this caused an auto-correction to happen. + */ + private boolean handleNonFunctionalEventAndReturnIfDidAutoCorrect( + final InputTransaction inputTransaction, + // TODO: remove this argument + final LatinIME.UIHandler handler) { + final Event event = inputTransaction.mEvent; + inputTransaction.setDidAffectContents(); + boolean didAutoCorrect = false; + switch (event.mCodePoint) { + case Constants.CODE_ENTER: + final EditorInfo editorInfo = getCurrentInputEditorInfo(); + final int imeOptionsActionId = + InputTypeUtils.getImeOptionsActionIdFromEditorInfo(editorInfo); + if (InputTypeUtils.IME_ACTION_CUSTOM_LABEL == imeOptionsActionId) { + // Either we have an actionLabel and we should performEditorAction with + // actionId regardless of its value. + performEditorAction(editorInfo.actionId); + } else if (EditorInfo.IME_ACTION_NONE != imeOptionsActionId) { + // We didn't have an actionLabel, but we had another action to execute. + // EditorInfo.IME_ACTION_NONE explicitly means no action. In contrast, + // EditorInfo.IME_ACTION_UNSPECIFIED is the default value for an action, so it + // means there should be an action and the app didn't bother to set a specific + // code for it - presumably it only handles one. It does not have to be treated + // in any specific way: anything that is not IME_ACTION_NONE should be sent to + // performEditorAction. + performEditorAction(imeOptionsActionId); + } else { + // No action label, and the action from imeOptions is NONE: this is a regular + // enter key that should input a carriage return. + didAutoCorrect = handleNonSpecialCharacter(inputTransaction, handler); + } + break; + default: + didAutoCorrect = handleNonSpecialCharacter(inputTransaction, handler); + break; + } + return didAutoCorrect; + } + /** * Handle inputting a code point to the editor. *