fixed unexpected text reset when starting to type in a new input field, caused by multiple IME restarts in the same field, causing InputMode re-creation; also reduced the InputMode recreations in general
This commit is contained in:
parent
d9b620790b
commit
caad8a5446
5 changed files with 55 additions and 31 deletions
|
|
@ -19,7 +19,7 @@ abstract public class AbstractHandler extends InputMethodService {
|
||||||
// helpers
|
// helpers
|
||||||
abstract public SettingsStore getSettings();
|
abstract public SettingsStore getSettings();
|
||||||
abstract protected void onInit();
|
abstract protected void onInit();
|
||||||
abstract protected void onStart(InputConnection inputConnection, EditorInfo inputField);
|
abstract protected boolean onStart(InputConnection inputConnection, EditorInfo inputField);
|
||||||
abstract protected void onFinishTyping();
|
abstract protected void onFinishTyping();
|
||||||
abstract protected void onStop();
|
abstract protected void onStop();
|
||||||
abstract protected void setInputField(InputConnection inputConnection, EditorInfo inputField);
|
abstract protected void setInputField(InputConnection inputConnection, EditorInfo inputField);
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ public abstract class HotkeyHandler extends TypingHandler {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart(InputConnection connection, EditorInfo field) {
|
protected boolean onStart(InputConnection connection, EditorInfo field) {
|
||||||
super.onStart(connection, field);
|
|
||||||
isSystemRTL = LanguageKind.isRTL(LanguageCollection.getDefault(this));
|
isSystemRTL = LanguageKind.isRTL(LanguageCollection.getDefault(this));
|
||||||
|
return super.onStart(connection, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import io.github.sspanak.tt9.db.DictionaryLoader;
|
import io.github.sspanak.tt9.db.DictionaryLoader;
|
||||||
import io.github.sspanak.tt9.db.WordStoreAsync;
|
import io.github.sspanak.tt9.db.WordStoreAsync;
|
||||||
|
import io.github.sspanak.tt9.ime.modes.InputMode;
|
||||||
import io.github.sspanak.tt9.ime.modes.ModePassthrough;
|
import io.github.sspanak.tt9.ime.modes.ModePassthrough;
|
||||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||||
import io.github.sspanak.tt9.ui.UI;
|
import io.github.sspanak.tt9.ui.UI;
|
||||||
|
|
@ -85,22 +86,22 @@ public class TraditionalT9 extends HotkeyHandler {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart(InputConnection connection, EditorInfo field) {
|
protected boolean onStart(InputConnection connection, EditorInfo field) {
|
||||||
Logger.setLevel(settings.getLogLevel());
|
if (!super.onStart(connection, field)) {
|
||||||
|
return false;
|
||||||
super.onStart(connection, field);
|
|
||||||
|
|
||||||
if (mInputMode.isPassthrough()) {
|
|
||||||
// When the input is invalid or simple, let Android handle it.
|
|
||||||
onStop();
|
|
||||||
updateInputViewShown();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
normalizationHandler.removeCallbacksAndMessages(null);
|
Logger.setLevel(settings.getLogLevel());
|
||||||
|
|
||||||
|
if (mInputMode.isPassthrough()) {
|
||||||
|
onStop();
|
||||||
|
} else {
|
||||||
|
normalizationHandler.removeCallbacksAndMessages(null);
|
||||||
|
initUi();
|
||||||
|
}
|
||||||
|
|
||||||
initUi();
|
|
||||||
updateInputViewShown();
|
updateInputViewShown();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -154,11 +155,11 @@ public class TraditionalT9 extends HotkeyHandler {
|
||||||
* Some applications may hide our window and it remains invisible until the screen is touched or OK is pressed.
|
* Some applications may hide our window and it remains invisible until the screen is touched or OK is pressed.
|
||||||
* This is fine for touchscreen keyboards, but the hardware keyboard allows typing even when the window and the suggestions
|
* This is fine for touchscreen keyboards, but the hardware keyboard allows typing even when the window and the suggestions
|
||||||
* are invisible. This function forces the InputMethodManager to show our window.
|
* are invisible. This function forces the InputMethodManager to show our window.
|
||||||
* WARNING! While this is running, it is not possible to load or display suggestions,
|
* WARNING! Calling this may cause a restart, which will cause InputMode to be recreated. Depending
|
||||||
* or change the composing text. Use with care, after all processing is done.
|
* on how much time the restart takes, this may erase the current user input.
|
||||||
*/
|
*/
|
||||||
protected void forceShowWindowIfHidden() {
|
protected void forceShowWindowIfHidden() {
|
||||||
if (getInputMode().isPassthrough() || isInputViewShown() || settings.isMainLayoutStealth()) {
|
if (getInputModeId() == InputMode.MODE_PASSTHROUGH || isInputViewShown() || settings.isMainLayoutStealth()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,7 +189,7 @@ public class TraditionalT9 extends HotkeyHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldBeVisible() {
|
protected boolean shouldBeVisible() {
|
||||||
return !getInputMode().isPassthrough();
|
return getInputModeId() != InputMode.MODE_PASSTHROUGH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import io.github.sspanak.tt9.ime.modes.ModePredictive;
|
||||||
import io.github.sspanak.tt9.languages.Language;
|
import io.github.sspanak.tt9.languages.Language;
|
||||||
import io.github.sspanak.tt9.languages.LanguageCollection;
|
import io.github.sspanak.tt9.languages.LanguageCollection;
|
||||||
import io.github.sspanak.tt9.ui.UI;
|
import io.github.sspanak.tt9.ui.UI;
|
||||||
import io.github.sspanak.tt9.util.Logger;
|
|
||||||
import io.github.sspanak.tt9.util.Text;
|
import io.github.sspanak.tt9.util.Text;
|
||||||
|
|
||||||
public abstract class TypingHandler extends KeyPadHandler {
|
public abstract class TypingHandler extends KeyPadHandler {
|
||||||
|
|
@ -46,7 +45,13 @@ public abstract class TypingHandler extends KeyPadHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart(InputConnection connection, EditorInfo field) {
|
protected boolean onStart(InputConnection connection, EditorInfo field) {
|
||||||
|
// ignore multiple calls for the same field, caused by showWindow()
|
||||||
|
// or weirdly functioning apps, such as the Qin SMS app
|
||||||
|
if (textField.equals(connection, field)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
setInputField(connection, field);
|
setInputField(connection, field);
|
||||||
|
|
||||||
// in case we are back from Settings screen, update the language list
|
// in case we are back from Settings screen, update the language list
|
||||||
|
|
@ -58,10 +63,11 @@ public abstract class TypingHandler extends KeyPadHandler {
|
||||||
mInputMode = getInputMode();
|
mInputMode = getInputMode();
|
||||||
determineTextCase();
|
determineTextCase();
|
||||||
|
|
||||||
suggestionOps.setTextField(textField);
|
|
||||||
suggestionOps.set(null);
|
suggestionOps.set(null);
|
||||||
|
|
||||||
appHacks = new AppHacks(settings, connection, field, textField);
|
appHacks = new AppHacks(settings, connection, field, textField);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -69,6 +75,7 @@ public abstract class TypingHandler extends KeyPadHandler {
|
||||||
currentInputConnection = connection;
|
currentInputConnection = connection;
|
||||||
inputType = new InputType(currentInputConnection, field);
|
inputType = new InputType(currentInputConnection, field);
|
||||||
textField = new TextField(currentInputConnection, field);
|
textField = new TextField(currentInputConnection, field);
|
||||||
|
suggestionOps.setTextField(textField);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -84,6 +91,7 @@ public abstract class TypingHandler extends KeyPadHandler {
|
||||||
protected void onFinishTyping() {
|
protected void onFinishTyping() {
|
||||||
suggestionOps.cancelDelayedAccept();
|
suggestionOps.cancelDelayedAccept();
|
||||||
mInputMode = InputMode.getInstance(null, null, null, InputMode.MODE_PASSTHROUGH);
|
mInputMode = InputMode.getInstance(null, null, null, InputMode.MODE_PASSTHROUGH);
|
||||||
|
setInputField(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -94,7 +102,6 @@ public abstract class TypingHandler extends KeyPadHandler {
|
||||||
// 3. Some app may need special treatment, so let it be.
|
// 3. Some app may need special treatment, so let it be.
|
||||||
boolean noTextBeforeCursor = textField.getStringBeforeCursor(1).isEmpty();
|
boolean noTextBeforeCursor = textField.getStringBeforeCursor(1).isEmpty();
|
||||||
if (mInputMode.isPassthrough() || appHacks.onBackspace(mInputMode) || noTextBeforeCursor) {
|
if (mInputMode.isPassthrough() || appHacks.onBackspace(mInputMode) || noTextBeforeCursor) {
|
||||||
Logger.d("onBackspace", "backspace ignored");
|
|
||||||
mInputMode.reset();
|
mInputMode.reset();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -109,7 +116,6 @@ public abstract class TypingHandler extends KeyPadHandler {
|
||||||
super.sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
|
super.sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.d("onBackspace", "backspace handled");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,18 +213,28 @@ public abstract class TypingHandler extends KeyPadHandler {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getInputMode
|
* getInputModeId
|
||||||
* Load the last input mode or choose a more appropriate one.
|
* Return the last input mode ID or choose a more appropriate one.
|
||||||
* Some input fields support only numbers or are not suited for predictions (e.g. password fields)
|
* Some input fields support only numbers or are not suited for predictions (e.g. password fields).
|
||||||
|
* Others do not support text retrieval or composing text, or the AppHacks detected them as incompatible with us.
|
||||||
|
* We do not want to handle any of these, hence we pass through all input to the system.
|
||||||
*/
|
*/
|
||||||
protected InputMode getInputMode() {
|
protected int getInputModeId() {
|
||||||
if (!inputType.isValid() || (inputType.isLimited() && !appHacks.isTermux())) {
|
if (!inputType.isValid() || (inputType.isLimited() && !appHacks.isTermux())) {
|
||||||
return InputMode.getInstance(settings, mLanguage, inputType, InputMode.MODE_PASSTHROUGH);
|
return InputMode.MODE_PASSTHROUGH;
|
||||||
}
|
}
|
||||||
|
|
||||||
allowedInputModes = textField.determineInputModes(inputType);
|
allowedInputModes = textField.determineInputModes(inputType);
|
||||||
int validModeId = InputModeValidator.validateMode(settings.getInputMode(), allowedInputModes);
|
return InputModeValidator.validateMode(settings.getInputMode(), allowedInputModes);
|
||||||
return InputMode.getInstance(settings, mLanguage, inputType, validModeId);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getInputMode
|
||||||
|
* Same as getInputModeId(), but returns an actual InputMode.
|
||||||
|
*/
|
||||||
|
protected InputMode getInputMode() {
|
||||||
|
return InputMode.getInstance(settings, mLanguage, inputType, getInputModeId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,13 @@ public class TextField {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean equals(InputConnection inputConnection, EditorInfo inputField) {
|
||||||
|
return
|
||||||
|
connection != null && connection == inputConnection
|
||||||
|
&& field != null && field == inputField;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean isThereText() {
|
public boolean isThereText() {
|
||||||
if (connection == null) {
|
if (connection == null) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue