From 81df61b90058bf281527504bd298baaff9776f7c Mon Sep 17 00:00:00 2001 From: Dimo Karaivanov Date: Mon, 28 Aug 2023 12:19:17 +0300 Subject: [PATCH] improved support for phone, decimal and signed integer numeric fields --- .../github/sspanak/tt9/ime/TraditionalT9.java | 22 +++++++-- .../sspanak/tt9/ime/helpers/InputType.java | 42 +++++++++++----- .../sspanak/tt9/ime/modes/InputMode.java | 5 +- .../github/sspanak/tt9/ime/modes/Mode123.java | 48 ++++++++++++++++++- .../tt9/ui/main/keys/SoftNumberKey.java | 11 +++-- .../tt9/ui/main/keys/SoftPunctuationKey.java | 41 ++++++++-------- 6 files changed, 125 insertions(+), 44 deletions(-) diff --git a/src/io/github/sspanak/tt9/ime/TraditionalT9.java b/src/io/github/sspanak/tt9/ime/TraditionalT9.java index a490d1df..cdbc259a 100644 --- a/src/io/github/sspanak/tt9/ime/TraditionalT9.java +++ b/src/io/github/sspanak/tt9/ime/TraditionalT9.java @@ -63,8 +63,20 @@ public class TraditionalT9 extends KeyPadHandler { return settings; } - public int getInputMode() { - return mInputMode != null ? mInputMode.getId() : InputMode.MODE_UNDEFINED; + public boolean isInputModeNumeric() { + return mInputMode != null && mInputMode.is123(); + } + + public boolean isNumericModeStrict() { + return mInputMode != null && mInputMode.is123() && inputType.isNumeric() && !inputType.isPhoneNumber(); + } + + public boolean isNumericModeSigned() { + return mInputMode != null && mInputMode.is123() && inputType.isSignedNumber(); + } + + public boolean isInputModePhone() { + return mInputMode != null && mInputMode.is123() && inputType.isPhoneNumber(); } public int getTextCase() { @@ -96,7 +108,7 @@ public class TraditionalT9 extends KeyPadHandler { private void determineInputMode() { allowedInputModes = textField.determineInputModes(inputType); int validModeId = InputModeValidator.validateMode(settings.getInputMode(), allowedInputModes); - mInputMode = InputMode.getInstance(settings, mLanguage, validModeId); + mInputMode = InputMode.getInstance(settings, mLanguage, inputType, validModeId); } @@ -669,7 +681,7 @@ public class TraditionalT9 extends KeyPadHandler { if (mInputMode.isPassthrough()) { return; } else if (allowedInputModes.size() == 1 && allowedInputModes.contains(InputMode.MODE_123)) { - mInputMode = !mInputMode.is123() ? InputMode.getInstance(settings, mLanguage, InputMode.MODE_123) : mInputMode; + mInputMode = !mInputMode.is123() ? InputMode.getInstance(settings, mLanguage, inputType, InputMode.MODE_123) : mInputMode; } // when typing a word or viewing scrolling the suggestions, only change the case else if (!isSuggestionViewHidden()) { @@ -693,7 +705,7 @@ public class TraditionalT9 extends KeyPadHandler { mInputMode.nextTextCase(); } else { int nextModeIndex = (allowedInputModes.indexOf(mInputMode.getId()) + 1) % allowedInputModes.size(); - mInputMode = InputMode.getInstance(settings, mLanguage, allowedInputModes.get(nextModeIndex)); + mInputMode = InputMode.getInstance(settings, mLanguage, inputType, allowedInputModes.get(nextModeIndex)); mInputMode.setTextFieldCase(textField.determineTextCase(inputType)); mInputMode.determineNextWordTextCase(textField.isThereText(), textField.getTextBeforeCursor()); diff --git a/src/io/github/sspanak/tt9/ime/helpers/InputType.java b/src/io/github/sspanak/tt9/ime/helpers/InputType.java index 660f4400..c7f97a0d 100644 --- a/src/io/github/sspanak/tt9/ime/helpers/InputType.java +++ b/src/io/github/sspanak/tt9/ime/helpers/InputType.java @@ -24,7 +24,7 @@ public class InputType { * isLimited * Special or limited input type means the input connection is not rich, * or it can not process or show things like candidate text, nor retrieve the current text. - * + *

* More info: android docs. */ public boolean isLimited() { @@ -36,24 +36,44 @@ public class InputType { * isSpecialNumeric * Calculator and 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 Phone field. Dialer is where you * actually dial and call a phone number. While the Phone field is a text * field in any app or a webpage, intended for typing phone numbers. - * + *

* More info: in this Github issue * and the PR about calculators. */ public boolean isSpecialNumeric() { - if (field == null) { - return false; - } - - int inputType = field.inputType & android.text.InputType.TYPE_MASK_CLASS; - return - inputType == android.text.InputType.TYPE_CLASS_PHONE && field.packageName.equals("com.android.dialer") - || inputType == android.text.InputType.TYPE_CLASS_NUMBER && field.packageName.contains("com.android.calculator"); + isPhoneNumber() && field.packageName.equals("com.android.dialer") + || isNumeric() && field.packageName.contains("com.android.calculator"); + } + + + public boolean isPhoneNumber() { + return + field != null + && (field.inputType & android.text.InputType.TYPE_MASK_CLASS) == android.text.InputType.TYPE_CLASS_PHONE; + } + + public boolean isNumeric() { + return + field != null + && (field.inputType & android.text.InputType.TYPE_MASK_CLASS) == android.text.InputType.TYPE_CLASS_NUMBER; + } + + public boolean isDecimal() { + return + isNumeric() + && (field.inputType & android.text.InputType.TYPE_MASK_FLAGS) == android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL; + } + + + public boolean isSignedNumber() { + return + isNumeric() + && (field.inputType & android.text.InputType.TYPE_MASK_FLAGS) == android.text.InputType.TYPE_NUMBER_FLAG_SIGNED; } diff --git a/src/io/github/sspanak/tt9/ime/modes/InputMode.java b/src/io/github/sspanak/tt9/ime/modes/InputMode.java index 6639e593..aaf5b3f0 100644 --- a/src/io/github/sspanak/tt9/ime/modes/InputMode.java +++ b/src/io/github/sspanak/tt9/ime/modes/InputMode.java @@ -12,7 +12,6 @@ import io.github.sspanak.tt9.preferences.SettingsStore; abstract public class InputMode { // typing mode - public static final int MODE_UNDEFINED = -1; public static final int MODE_PREDICTIVE = 0; public static final int MODE_ABC = 1; public static final int MODE_123 = 2; @@ -34,7 +33,7 @@ abstract public class InputMode { protected final ArrayList suggestions = new ArrayList<>(); - public static InputMode getInstance(SettingsStore settings, Language language, int mode) { + public static InputMode getInstance(SettingsStore settings, Language language, InputType inputType, int mode) { switch (mode) { case MODE_PREDICTIVE: return new ModePredictive(settings, language); @@ -45,7 +44,7 @@ abstract public class InputMode { default: Logger.w("InputMode", "Defaulting to mode: " + Mode123.class.getName() + " for unknown InputMode: " + mode); case MODE_123: - return new Mode123(); + return new Mode123(inputType); } } diff --git a/src/io/github/sspanak/tt9/ime/modes/Mode123.java b/src/io/github/sspanak/tt9/ime/modes/Mode123.java index 367412ea..c3f50de5 100644 --- a/src/io/github/sspanak/tt9/ime/modes/Mode123.java +++ b/src/io/github/sspanak/tt9/ime/modes/Mode123.java @@ -3,8 +3,10 @@ package io.github.sspanak.tt9.ime.modes; import androidx.annotation.NonNull; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import io.github.sspanak.tt9.ime.helpers.InputType; import io.github.sspanak.tt9.languages.Characters; public class Mode123 extends ModePassthrough { @@ -18,7 +20,47 @@ public class Mode123 extends ModePassthrough { private final ArrayList> KEY_CHARACTERS = new ArrayList<>(); - public Mode123() { + + public Mode123(InputType inputType) { + if (inputType.isPhoneNumber()) { + getPhoneSpecialCharacters(); + } else if (inputType.isNumeric()) { + getNumberSpecialCharacters(inputType.isDecimal(), inputType.isSignedNumber()); + } else { + getDefaultSpecialCharacters(); + } + } + + + /** + * getPhoneSpecialCharacters + * Special characters for phone number fields, including both characters for conveniently typing a phone number: "()-", + * as well as command characters such as "," = "slight pause" and ";" = "wait" used in Japan and some other countries. + */ + private void getPhoneSpecialCharacters() { + KEY_CHARACTERS.add(new ArrayList<>(Arrays.asList("+", " "))); + KEY_CHARACTERS.add(new ArrayList<>(Arrays.asList("-", "(", ")", ".", ";", ","))); + } + + + /** + * getNumberSpecialCharacters + * Special characters for all kinds of numeric fields: integer, decimal with +/- included as necessary. + */ + private void getNumberSpecialCharacters(boolean decimal, boolean signed) { + KEY_CHARACTERS.add(signed ? new ArrayList<>(Arrays.asList("-", "+")) : new ArrayList<>()); + if (decimal) { + KEY_CHARACTERS.add(new ArrayList<>(Arrays.asList(".", ","))); + } + } + + + /** + * getDefaultSpecialCharacters + * Special characters for when the user has selected 123 mode in a text field. In this case, we just + * use the default list, but reorder it a bit for convenience. + */ + private void getDefaultSpecialCharacters() { // 0-key KEY_CHARACTERS.add(new ArrayList<>(Collections.singletonList("+"))); for (String character : Characters.Special) { @@ -36,10 +78,11 @@ public class Mode123 extends ModePassthrough { } } + @Override public boolean onNumber(int number, boolean hold, int repeat) { reset(); - if (hold && number < KEY_CHARACTERS.size()) { + if (hold && number < KEY_CHARACTERS.size() && KEY_CHARACTERS.get(number).size() > 0) { suggestions.addAll(KEY_CHARACTERS.get(number)); } else { autoAcceptTimeout = 0; @@ -49,6 +92,7 @@ public class Mode123 extends ModePassthrough { return true; } + /** * shouldIgnoreText * Since this is a numeric mode, we allow typing only numbers and: diff --git a/src/io/github/sspanak/tt9/ui/main/keys/SoftNumberKey.java b/src/io/github/sspanak/tt9/ui/main/keys/SoftNumberKey.java index 4ec78d1f..5b09c481 100644 --- a/src/io/github/sspanak/tt9/ui/main/keys/SoftNumberKey.java +++ b/src/io/github/sspanak/tt9/ui/main/keys/SoftNumberKey.java @@ -64,8 +64,13 @@ public class SoftNumberKey extends SoftKey { int number = getNumber(getId()); + // 0 if (number == 0) { - if (tt9.getInputMode() == InputMode.MODE_123) { + if (tt9.isNumericModeSigned()) { + return "+/-"; + } else if (tt9.isNumericModeStrict()) { + return null; + } else if (tt9.isInputModeNumeric()) { return "+"; } else { COMPLEX_LABEL_SUB_TITLE_SIZE = 1; @@ -75,11 +80,11 @@ public class SoftNumberKey extends SoftKey { // 1 if (number == 1) { - return ",:-)"; + return tt9.isNumericModeStrict() ? null : ",:-)"; } // no other special labels in 123 mode - if (tt9.getInputMode() == InputMode.MODE_123) { + if (tt9.isInputModeNumeric()) { return null; } diff --git a/src/io/github/sspanak/tt9/ui/main/keys/SoftPunctuationKey.java b/src/io/github/sspanak/tt9/ui/main/keys/SoftPunctuationKey.java index 734e0a9d..294b655a 100644 --- a/src/io/github/sspanak/tt9/ui/main/keys/SoftPunctuationKey.java +++ b/src/io/github/sspanak/tt9/ui/main/keys/SoftPunctuationKey.java @@ -4,7 +4,6 @@ import android.content.Context; import android.util.AttributeSet; import io.github.sspanak.tt9.R; -import io.github.sspanak.tt9.ime.modes.InputMode; public class SoftPunctuationKey extends SoftKey { public SoftPunctuationKey(Context context) { @@ -21,37 +20,39 @@ public class SoftPunctuationKey extends SoftKey { @Override protected boolean handleRelease() { - if (!validateTT9Handler()) { - return false; - } - - int keyId = getId(); - if (tt9.getInputMode() == InputMode.MODE_123) { - if (keyId == R.id.soft_key_punctuation_1) return tt9.onText("*"); - if (keyId == R.id.soft_key_punctuation_2) return tt9.onText("#"); - } else { - if (keyId == R.id.soft_key_punctuation_1) return tt9.onText("!"); - if (keyId == R.id.soft_key_punctuation_2) return tt9.onText("?"); - } - - return true; + return tt9.onText(getKeyChar()); } @Override protected String getTitle() { - if (tt9 == null) { - return "PUNC"; + String keyChar = getKeyChar(); + switch (keyChar) { + case "": + return "PUNC"; + case "*": + return "✱"; + default: + return keyChar; + } + } + + private String getKeyChar() { + if (!validateTT9Handler()) { + return ""; } int keyId = getId(); - if (tt9.getInputMode() == InputMode.MODE_123) { - if (keyId == R.id.soft_key_punctuation_1) return "✱"; + if (tt9.isInputModePhone()) { + if (keyId == R.id.soft_key_punctuation_1) return "*"; if (keyId == R.id.soft_key_punctuation_2) return "#"; + } else if (tt9.isInputModeNumeric()) { + if (keyId == R.id.soft_key_punctuation_1) return ","; + if (keyId == R.id.soft_key_punctuation_2) return "."; } else { if (keyId == R.id.soft_key_punctuation_1) return "!"; if (keyId == R.id.soft_key_punctuation_2) return "?"; } - return "PUNC"; + return ""; } }