diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/TypingHandler.java b/app/src/main/java/io/github/sspanak/tt9/ime/TypingHandler.java index 4aead923..bdde28a3 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/TypingHandler.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/TypingHandler.java @@ -221,11 +221,11 @@ public abstract class TypingHandler extends KeyPadHandler { private void autoCorrectSpace(String currentWord, boolean isWordAcceptedManually, int nextKey) { - if (!inputType.isRustDesk() && mInputMode.shouldDeletePrecedingSpace(inputType)) { + if (!inputType.isRustDesk() && mInputMode.shouldDeletePrecedingSpace(inputType, textField)) { textField.deletePrecedingSpace(currentWord); } - if (mInputMode.shouldAddPrecedingSpace(textField)) { + if (mInputMode.shouldAddPrecedingSpace(inputType, textField)) { textField.addPrecedingSpace(currentWord); } diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/helpers/TextField.java b/app/src/main/java/io/github/sspanak/tt9/ime/helpers/TextField.java index cb6c5338..f642e218 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/helpers/TextField.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/helpers/TextField.java @@ -200,8 +200,8 @@ public class TextField extends InputField { /** * deletePrecedingSpace - * Deletes the preceding space before the given word. The word must be before the cursor. - * No action is taken when there is double space or when it's the beginning of the text field. + * Deletes the space before the given word. The word must be before the cursor. + * No action is taken when there is no such word. */ public void deletePrecedingSpace(String word) { if (connection == null) { @@ -211,13 +211,8 @@ public class TextField extends InputField { String searchText = " " + word; connection.beginBatchEdit(); - CharSequence beforeText = connection.getTextBeforeCursor(searchText.length() + 1, 0); - if ( - beforeText == null - || beforeText.length() < searchText.length() + 1 - || beforeText.charAt(1) != ' ' // preceding char must be " " - || beforeText.charAt(0) == ' ' // but do nothing when there is double space - ) { + CharSequence beforeText = connection.getTextBeforeCursor(searchText.length(), 0); + if (beforeText == null || !beforeText.equals(searchText)) { connection.endBatchEdit(); return; } diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/modes/InputMode.java b/app/src/main/java/io/github/sspanak/tt9/ime/modes/InputMode.java index ff2feab3..195263f6 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/modes/InputMode.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/modes/InputMode.java @@ -107,8 +107,8 @@ abstract public class InputMode { public boolean shouldAcceptPreviousSuggestion() { return false; } public boolean shouldAcceptPreviousSuggestion(int nextKey) { return false; } public boolean shouldAddTrailingSpace(InputType inputType, TextField textField, boolean isWordAcceptedManually, int nextKey) { return false; } - public boolean shouldAddPrecedingSpace(TextField textField) { return false; } - public boolean shouldDeletePrecedingSpace(InputType inputType) { return false; } + public boolean shouldAddPrecedingSpace(InputType inputType, TextField textField) { return false; } + public boolean shouldDeletePrecedingSpace(InputType inputType, TextField textField) { return false; } public boolean shouldIgnoreText(String text) { return text == null || text.isEmpty(); } public boolean shouldSelectNextSuggestion() { return false; } public boolean recompose(String word) { return false; } diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/modes/ModePredictive.java b/app/src/main/java/io/github/sspanak/tt9/ime/modes/ModePredictive.java index a5596f1d..5db68a9f 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/modes/ModePredictive.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/modes/ModePredictive.java @@ -465,30 +465,19 @@ public class ModePredictive extends InputMode { @Override public boolean shouldAddTrailingSpace(InputType inputType, TextField textField, boolean isWordAcceptedManually, int nextKey) { - return autoSpace - .setLastWord(lastAcceptedWord) - .setLastSequence() - .setInputType(inputType) - .setTextField(textField) - .shouldAddTrailingSpace(isWordAcceptedManually, nextKey); + return autoSpace.shouldAddTrailingSpace(textField, inputType, isWordAcceptedManually, nextKey); } @Override - public boolean shouldAddPrecedingSpace(TextField textField) { - return autoSpace - .setTextField(textField) - .shouldAddBeforePunctuation(); + public boolean shouldAddPrecedingSpace(InputType inputType, TextField textField) { + return autoSpace.shouldAddBeforePunctuation(inputType, textField); } @Override - public boolean shouldDeletePrecedingSpace(InputType inputType) { - return autoSpace - .setLastWord(lastAcceptedWord) - .setInputType(inputType) - .setTextField(null) - .shouldDeletePrecedingSpace(); + public boolean shouldDeletePrecedingSpace(InputType inputType, TextField textField) { + return autoSpace.shouldDeletePrecedingSpace(inputType, textField); } diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/modes/helpers/AutoSpace.java b/app/src/main/java/io/github/sspanak/tt9/ime/modes/helpers/AutoSpace.java index 4d143c6c..74035251 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/modes/helpers/AutoSpace.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/modes/helpers/AutoSpace.java @@ -1,5 +1,7 @@ package io.github.sspanak.tt9.ime.modes.helpers; +import java.util.Set; + import io.github.sspanak.tt9.hacks.InputType; import io.github.sspanak.tt9.ime.helpers.TextField; import io.github.sspanak.tt9.languages.Language; @@ -9,11 +11,14 @@ import io.github.sspanak.tt9.util.Characters; import io.github.sspanak.tt9.util.Text; public class AutoSpace { - private final SettingsStore settings; + private static final Set PRECEDING_SPACE_PUNCTUATION = Set.of('(', '«', '„'); + private static final Set PRECEDING_SPACE_FRENCH_PUNCTUATION = Set.of(';', ':', '!', '?', '»'); + private static final Set TRAILING_SPACE_PUNCTUATION = Set.of('.', ',', ';', '!', '?', ')', '%', '»', '؟', '“'); - private InputType inputType; - private TextField textField; - private String lastWord; + private static final Set NO_PRECEDING_SPACE_PUNCTUATION = Set.of('.', ',', ')', '\'', '@', '“', '؟'); + private static final Set NOT_FRENCH_NO_PRECEDING_SPACE_PUNCTUATION = Set.of(';', ':', '!', '?', '»'); + + private final SettingsStore settings; private boolean isLanguageFrench; private boolean isLanguageWithSpaceBetweenWords; @@ -26,41 +31,19 @@ public class AutoSpace { } - public AutoSpace setInputType(InputType inputType) { - this.inputType = inputType; - return this; - } - - - public AutoSpace setTextField(TextField textField) { - this.textField = textField; - return this; - } - - - public AutoSpace setLastWord(String lastWord) { - this.lastWord = lastWord; - return this; - } - - public AutoSpace setLanguage(Language language) { isLanguageFrench = LanguageKind.isFrench(language); isLanguageWithSpaceBetweenWords = language != null && language.hasSpaceBetweenWords(); return this; } - public AutoSpace setLastSequence() { - return this; - } - /** * Determines whether to automatically add a space at the end of a sentence or after accepting a * suggestion. This allows faster typing, without pressing space. See the helper functions for * the list of rules. */ - public boolean shouldAddTrailingSpace(boolean isWordAcceptedManually, int nextKey) { + public boolean shouldAddTrailingSpace(TextField textField, InputType inputType, boolean isWordAcceptedManually, int nextKey) { if (!isLanguageWithSpaceBetweenWords) { return false; } @@ -84,12 +67,12 @@ public class AutoSpace { * Determines the special French rules for space before punctuation, as well as some standard ones. * For example, should we transform "word?" to "word ?", or "something(" to "something (" */ - public boolean shouldAddBeforePunctuation() { + public boolean shouldAddBeforePunctuation(InputType inputType, TextField textField) { String previousChars = textField.getStringBeforeCursor(2); char penultimateChar = previousChars.length() < 2 ? 0 : previousChars.charAt(previousChars.length() - 2); char previousChar = previousChars.isEmpty() ? 0 : previousChars.charAt(previousChars.length() - 1); - if (previousChar == '¡' || previousChar == '¿' && settings.getAutoSpace()) { + if (previousChar == '¡' || previousChar == '¿' && settings.getAutoSpace()) { return true; } @@ -99,18 +82,8 @@ public class AutoSpace { && !inputType.isSpecialized() && Character.isAlphabetic(penultimateChar) && ( - previousChar == '(' - || previousChar == '[' - || previousChar == '«' - || previousChar == '„' - || isLanguageFrench && ( - previousChar == ';' - || previousChar == ':' - || previousChar == '!' - || previousChar == '?' - || previousChar == ')' - || previousChar == '»' - ) + PRECEDING_SPACE_PUNCTUATION.contains(previousChar) + || (isLanguageFrench && PRECEDING_SPACE_FRENCH_PUNCTUATION.contains(previousChar)) ); } @@ -129,22 +102,12 @@ public class AutoSpace { && !Text.nextIsPunctuation(nextChars.toString()) && !nextChars.startsWithNumber() && ( - previousChar == '.' - || previousChar == ',' - || previousChar == ';' + TRAILING_SPACE_PUNCTUATION.contains(previousChar) || (previousChar == ':' && !Character.isDigit(penultimateChar)) - || previousChar == '!' - || previousChar == '?' - || previousChar == ')' - || previousChar == ']' - || previousChar == '%' - || previousChar == '»' - || previousChar == '؟' - || previousChar == '“' || (isLanguageFrench && previousChar == '«') || (penultimateChar == ' ' && previousChar == '-') || (penultimateChar == ' ' && previousChar == '/') - || (Character.isDigit(penultimateChar) && Characters.Currency.contains(previousChar + "")) + || (Character.isDigit(penultimateChar) && Characters.Currency.contains(String.valueOf(previousChar))) ); } @@ -164,22 +127,20 @@ public class AutoSpace { /** * Determines whether to transform: "word ." to: "word." */ - public boolean shouldDeletePrecedingSpace() { + public boolean shouldDeletePrecedingSpace(InputType inputType, TextField textField) { + String previousChars = textField.getStringBeforeCursor(3); + char prePenultimateChar = previousChars.length() < 3 ? 0 : previousChars.charAt(previousChars.length() - 3); + char penultimateChar = previousChars.length() < 2 ? 0 : previousChars.charAt(previousChars.length() - 2); + char previousChar = previousChars.isEmpty() ? 0 : previousChars.charAt(previousChars.length() - 1); + return isLanguageWithSpaceBetweenWords && settings.getAutoSpace() + && !Character.isWhitespace(prePenultimateChar) + && Character.isWhitespace(penultimateChar) && ( - lastWord.equals(".") - || lastWord.equals(",") - || (!isLanguageFrench && lastWord.equals(";")) - || (!isLanguageFrench && lastWord.equals(":")) - || (!isLanguageFrench && lastWord.equals("!")) - || (!isLanguageFrench && lastWord.equals("?")) - || lastWord.equals("؟") - || (!isLanguageFrench && lastWord.equals(")")) - || lastWord.equals("]") - || lastWord.equals("'") - || lastWord.equals("@") + NO_PRECEDING_SPACE_PUNCTUATION.contains(previousChar) + || (!isLanguageFrench && NOT_FRENCH_NO_PRECEDING_SPACE_PUNCTUATION.contains(previousChar)) ) && !inputType.isSpecialized(); }