diff --git a/src/io/github/sspanak/tt9/ime/InputFieldHelper.java b/src/io/github/sspanak/tt9/ime/InputFieldHelper.java index dedf11ed..f881217f 100644 --- a/src/io/github/sspanak/tt9/ime/InputFieldHelper.java +++ b/src/io/github/sspanak/tt9/ime/InputFieldHelper.java @@ -32,6 +32,8 @@ public class InputFieldHelper { * isDialerField * Dialer fields seem to take care of numbers and backspace on their own, * so we need to be aware of them. + * + * NOTE: A Dialer field is not the same as a Phone field in a phone book. */ public static boolean isDialerField(EditorInfo inputField) { return @@ -79,12 +81,23 @@ public class InputFieldHelper { return variation == InputType.TYPE_TEXT_VARIATION_PASSWORD - || variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD; + || variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD + || variation == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD; } - public static boolean isRegularTextField(EditorInfo inputField) { - return !isPasswordField(inputField) && !isEmailField(inputField); + private static boolean isPersonNameField(EditorInfo inputField) { + return inputField != null && (inputField.inputType & InputType.TYPE_MASK_VARIATION) == InputType.TYPE_TEXT_VARIATION_PERSON_NAME; + } + + + public static boolean isSpecializedTextField(EditorInfo inputField) { + return isEmailField(inputField) || isPasswordField(inputField) || isUriField(inputField); + } + + + private static boolean isUriField(EditorInfo inputField) { + return inputField != null && (inputField.inputType & InputType.TYPE_MASK_VARIATION) == InputType.TYPE_TEXT_VARIATION_URI; } @@ -153,27 +166,27 @@ public class InputFieldHelper { * Helper to update the shift state of our keyboard based on the initial * editor state. */ - public static void determineTextCase(EditorInfo inputField) { - // Logger.d("updateShift", "CM start: " + mCapsMode); - // if (inputField != null && mCapsMode != SettingsStore.CASE_UPPER) { - // int caps = 0; - // if (inputField.inputType != InputType.TYPE_NULL) { - // caps = currentInputConnection.getCursorCapsMode(inputField.inputType); - // } - // // mInputView.setShifted(mCapsLock || caps != 0); - // // Logger.d("updateShift", "caps: " + caps); - // if ((caps & TextUtils.CAP_MODE_CHARACTERS) == TextUtils.CAP_MODE_CHARACTERS) { - // mCapsMode = SettingsStore.CASE_UPPER; - // } else if ((caps & TextUtils.CAP_MODE_SENTENCES) == TextUtils.CAP_MODE_SENTENCES) { - // mCapsMode = SettingsStore.CASE_CAPITALIZE; - // } else if ((caps & TextUtils.CAP_MODE_WORDS) == TextUtils.CAP_MODE_WORDS) { - // mCapsMode = SettingsStore.CASE_CAPITALIZE; - // } else { - // mCapsMode = SettingsStore.CASE_LOWER; - // } - // updateStatusIcon(); - // } - // Logger.d("updateShift", "CM end: " + mCapsMode); + public static int determineTextCase(InputConnection inputConnection, EditorInfo inputField) { + if (inputField == null || inputConnection == null || inputField.inputType == InputType.TYPE_NULL) { + return InputMode.CASE_UNDEFINED; + } + + if (isSpecializedTextField(inputField)) { + return InputMode.CASE_LOWER; + } + + if (isPersonNameField(inputField)) { + return InputMode.CASE_CAPITALIZE; + } + + switch (inputField.inputType & InputType.TYPE_MASK_FLAGS) { + case InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS: + return InputMode.CASE_UPPER; + case InputType.TYPE_TEXT_FLAG_CAP_WORDS: + return InputMode.CASE_CAPITALIZE; + } + + return InputMode.CASE_UNDEFINED; } diff --git a/src/io/github/sspanak/tt9/ime/KeyPadHandler.java b/src/io/github/sspanak/tt9/ime/KeyPadHandler.java index e8e26e16..b131123a 100644 --- a/src/io/github/sspanak/tt9/ime/KeyPadHandler.java +++ b/src/io/github/sspanak/tt9/ime/KeyPadHandler.java @@ -95,7 +95,7 @@ abstract class KeyPadHandler extends InputMethodService { return; } - onRestart(inputField); + onStart(inputField); } @@ -386,7 +386,7 @@ abstract class KeyPadHandler extends InputMethodService { // helpers abstract protected void onInit(); - abstract protected void onRestart(EditorInfo inputField); + abstract protected void onStart(EditorInfo inputField); abstract protected void onFinish(); abstract protected View createSoftKeyView(); } diff --git a/src/io/github/sspanak/tt9/ime/TraditionalT9.java b/src/io/github/sspanak/tt9/ime/TraditionalT9.java index 7f713e2a..40603772 100644 --- a/src/io/github/sspanak/tt9/ime/TraditionalT9.java +++ b/src/io/github/sspanak/tt9/ime/TraditionalT9.java @@ -83,9 +83,8 @@ public class TraditionalT9 extends KeyPadHandler { } - protected void onRestart(EditorInfo inputField) { + protected void onStart(EditorInfo inputField) { this.inputField = inputField; - // in case we are back from Settings screen, update the language list mEnabledLanguages = settings.getEnabledLanguageIds(); validateLanguages(); @@ -94,6 +93,7 @@ public class TraditionalT9 extends KeyPadHandler { determineAllowedInputModes(); mInputMode = InputModeValidator.validateMode(settings, mInputMode, allowedInputModes); + mInputMode.setTextFieldCase(InputFieldHelper.determineTextCase(currentInputConnection, inputField)); // Some modes may want to change the default text case based on grammar rules. determineNextTextCase(); InputModeValidator.validateTextCase(settings, mInputMode, settings.getTextCase()); diff --git a/src/io/github/sspanak/tt9/ime/modes/InputMode.java b/src/io/github/sspanak/tt9/ime/modes/InputMode.java index b7077710..035d57e7 100644 --- a/src/io/github/sspanak/tt9/ime/modes/InputMode.java +++ b/src/io/github/sspanak/tt9/ime/modes/InputMode.java @@ -16,12 +16,14 @@ abstract public class InputMode { public static final int MODE_123 = 2; // text case + public static final int CASE_UNDEFINED = -1; public static final int CASE_UPPER = 0; public static final int CASE_CAPITALIZE = 1; public static final int CASE_LOWER = 2; public static final int CASE_DICTIONARY = 3; // do not force it, but use the dictionary word as-is protected ArrayList allowedTextCases = new ArrayList<>(); protected int textCase = CASE_LOWER; + protected int textFieldTextCase = CASE_UNDEFINED; // data protected ArrayList suggestions = new ArrayList<>(); @@ -91,11 +93,17 @@ abstract public class InputMode { return true; } + public void setTextFieldCase(int newTextCase) { + textFieldTextCase = allowedTextCases.contains(newTextCase) ? newTextCase : CASE_UNDEFINED; + } + public void defaultTextCase() { textCase = allowedTextCases.get(0); } public void nextTextCase() { + textFieldTextCase = CASE_UNDEFINED; // since it's a user's choice, the default matters no more + int nextIndex = (allowedTextCases.indexOf(textCase) + 1) % allowedTextCases.size(); textCase = allowedTextCases.get(nextIndex); } diff --git a/src/io/github/sspanak/tt9/ime/modes/ModePredictive.java b/src/io/github/sspanak/tt9/ime/modes/ModePredictive.java index 6146ba8a..678797ce 100644 --- a/src/io/github/sspanak/tt9/ime/modes/ModePredictive.java +++ b/src/io/github/sspanak/tt9/ime/modes/ModePredictive.java @@ -144,7 +144,7 @@ public class ModePredictive extends InputMode { || lastAcceptedWord.equals("'") || lastAcceptedWord.equals("@") ) - && InputFieldHelper.isRegularTextField(inputField); + && !InputFieldHelper.isSpecializedTextField(inputField); } @@ -168,7 +168,7 @@ public class ModePredictive extends InputMode { || lastAcceptedWord.endsWith("]") || lastAcceptedWord.endsWith("%") ) - && InputFieldHelper.isRegularTextField(inputField); + && !InputFieldHelper.isSpecializedTextField(inputField); } @@ -185,7 +185,7 @@ public class ModePredictive extends InputMode { && !lastAcceptedSequence.equals("0") // Emoji && !lastAcceptedSequence.startsWith("1") - && InputFieldHelper.isRegularTextField(inputField); + && !InputFieldHelper.isSpecializedTextField(inputField); } @@ -529,6 +529,11 @@ public class ModePredictive extends InputMode { return; } + if (textFieldTextCase != CASE_UNDEFINED) { + textCase = textFieldTextCase; + return; + } + // start of text if (!isThereText) { textCase = CASE_CAPITALIZE;