From 9514685337e7b83a6a968ec939ce5a056f25c612 Mon Sep 17 00:00:00 2001 From: artdeell Date: Wed, 15 Jan 2025 16:07:35 +0300 Subject: [PATCH] Fix[touch_char_input]: use TextWatcher instead of onTextChanged override Avoids a bug on some devices caused by setText called by the framework early --- .../keyboard/TouchCharInput.java | 62 +++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/keyboard/TouchCharInput.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/keyboard/TouchCharInput.java index 14b8a9eefa..ef0fe4e825 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/keyboard/TouchCharInput.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/keyboard/TouchCharInput.java @@ -5,6 +5,7 @@ import android.annotation.SuppressLint; import android.content.Context; +import android.text.Editable; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.inputmethod.InputMethodManager; @@ -34,31 +35,6 @@ public TouchCharInput(@NonNull Context context, @Nullable AttributeSet attrs, in private boolean mIsDoingInternalChanges = false; private CharacterSenderStrategy mCharacterSender; - /** - * We take the new chars, and send them to the game. - * If less chars are present, remove some. - * The text is always cleaned up. - */ - @Override - protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { - super.onTextChanged(text, start, lengthBefore, lengthAfter); - if(mIsDoingInternalChanges)return; - if(mCharacterSender != null){ - for(int i=0; i < lengthBefore; ++i){ - mCharacterSender.sendBackspace(); - } - - for(int i=start, count = 0; count < lengthAfter; ++i){ - mCharacterSender.sendChar(text.charAt(i)); - ++count; - } - } - - //Reset the keyboard state - if(text.length() < 1) clear(); - } - - /** * When we change from app to app, the keyboard gets disabled. * So, we disable the object @@ -142,6 +118,9 @@ public void setCharacterSender(CharacterSenderStrategy characterSender){ /** This function deals with anything that has to be executed when the constructor is called */ private void setup(){ + // Using TextWatcher instead of overriding onTextChanged because some Huawei firmware + // calls setText in constructor, causing havoc for our listener + addTextChangedListener(new InputTextWatcher()); setOnEditorActionListener((textView, i, keyEvent) -> { sendEnter(); clear(); @@ -151,5 +130,38 @@ private void setup(){ clear(); disable(); } + private class InputTextWatcher implements android.text.TextWatcher { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + } + + /** + * We take the new chars, and send them to the game. + * If less chars are present, remove some. + * The text is always cleaned up. + */ + @Override + public void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { + if(mIsDoingInternalChanges) return; + if(mCharacterSender != null){ + for(int i=0; i < lengthBefore; ++i){ + mCharacterSender.sendBackspace(); + } + + for(int i=start, count = 0; count < lengthAfter; ++i){ + mCharacterSender.sendChar(text.charAt(i)); + ++count; + } + } + } + + @Override + public void afterTextChanged(Editable editable) { + if(mIsDoingInternalChanges) return; + // Moved from onTextChanged because "It is an error to attempt to make changes to s from this callback." + // reference: https://developer.android.com/reference/android/text/TextWatcher#onTextChanged(java.lang.CharSequence,%20int,%20int,%20int) + if(editable.length() < 1) clear(); + } + } }