From 34e680bfbd0fbfe120f625f56001d23499e166d1 Mon Sep 17 00:00:00 2001 From: Benau Date: Sat, 25 May 2019 22:19:15 +0800 Subject: [PATCH] Allow copying from STK edit box to android edit text --- android/src/main/java/STKEditText.java | 35 +++++--- .../src/main/java/SuperTuxKartActivity.java | 83 ++++++++++++------- .../source/Irrlicht/CIrrDeviceAndroid.cpp | 70 ++++++++++++++-- .../source/Irrlicht/CIrrDeviceAndroid.h | 3 +- src/guiengine/widgets/CGUIEditBox.cpp | 45 +++++----- 5 files changed, 164 insertions(+), 72 deletions(-) diff --git a/android/src/main/java/STKEditText.java b/android/src/main/java/STKEditText.java index 7ac59acb0..e5884fddd 100644 --- a/android/src/main/java/STKEditText.java +++ b/android/src/main/java/STKEditText.java @@ -17,6 +17,11 @@ public class STKEditText extends EditText private int m_composing_end; + STKInputConnection m_stk_input_connection; + + /* Used to avoid infinite calling updateSTKEditBox if setText currently + * by jni. */ + private boolean m_from_stk_editbox; // ------------------------------------------------------------------------ private native static void editText2STKEditbox(String full_text, int start, int end, int composing_start, @@ -28,31 +33,29 @@ public class STKEditText extends EditText setFocusableInTouchMode(true); m_composing_start = 0; m_composing_end = 0; + m_from_stk_editbox = false; + m_stk_input_connection = null; } // ------------------------------------------------------------------------ @Override public InputConnection onCreateInputConnection(EditorInfo out_attrs) { - STKInputConnection sic = - new STKInputConnection(super.onCreateInputConnection(out_attrs), this); + if (m_stk_input_connection == null) + { + m_stk_input_connection = new STKInputConnection( + super.onCreateInputConnection(out_attrs), this); + } out_attrs.actionLabel = null; out_attrs.inputType = InputType.TYPE_CLASS_TEXT; out_attrs.imeOptions = EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_FULLSCREEN | EditorInfo.IME_FLAG_NO_EXTRACT_UI; - return sic; + return m_stk_input_connection; } // ------------------------------------------------------------------------ @Override public boolean onCheckIsTextEditor() { return true; } // ------------------------------------------------------------------------ - public void resetWhenFocus() - { - clearComposingText(); - getText().clear(); - m_composing_start = m_composing_end = 0; - } - // ------------------------------------------------------------------------ public void setComposingRegion(int start, int end) { // From doc of InputConnectionWrapper, it says: @@ -71,7 +74,7 @@ public class STKEditText extends EditText // ------------------------------------------------------------------------ public void updateSTKEditBox() { - if (!isFocused()) + if (!isFocused() || m_from_stk_editbox) return; editText2STKEditbox(getText().toString(), getSelectionStart(), getSelectionEnd(), m_composing_start, m_composing_end); @@ -82,4 +85,14 @@ public class STKEditText extends EditText clearFocus(); setVisibility(View.GONE); } + // ------------------------------------------------------------------------ + public void setTextFromSTK(final String text) + { + m_from_stk_editbox = true; + super.setText(text); + m_from_stk_editbox = false; + } + // ------------------------------------------------------------------------ + public STKInputConnection getSTKInputConnection() + { return m_stk_input_connection; } } diff --git a/android/src/main/java/SuperTuxKartActivity.java b/android/src/main/java/SuperTuxKartActivity.java index fbb446012..ed527ae1b 100644 --- a/android/src/main/java/SuperTuxKartActivity.java +++ b/android/src/main/java/SuperTuxKartActivity.java @@ -31,6 +31,9 @@ public class SuperTuxKartActivity extends NativeActivity InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm == null) + return; + imm.hideSoftInputFromWindow(m_stk_edittext.getWindowToken(), 0); } // ------------------------------------------------------------------------ @@ -47,6 +50,34 @@ public class SuperTuxKartActivity extends NativeActivity View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); } // ------------------------------------------------------------------------ + private void createSTKEditText() + { + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.WRAP_CONTENT, + FrameLayout.LayoutParams.WRAP_CONTENT); + m_stk_edittext = new STKEditText(this); + // For some copy-and-paste text are not done by commitText in + // STKInputConnection, so we need an extra watcher + m_stk_edittext.addTextChangedListener(new TextWatcher() + { + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) {} + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) {} + @Override + public void afterTextChanged(Editable edit) + { + if (m_stk_edittext != null) + m_stk_edittext.updateSTKEditBox(); + } + }); + addContentView(m_stk_edittext, params); + // Only focus it and make visible when soft keybord is opened + m_stk_edittext.setVisibility(View.GONE); + } + // ------------------------------------------------------------------------ @Override public void onCreate(Bundle instance) { @@ -120,38 +151,12 @@ public class SuperTuxKartActivity extends NativeActivity { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm == null) + return; - FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.WRAP_CONTENT, - FrameLayout.LayoutParams.WRAP_CONTENT); if (m_stk_edittext == null) - { - m_stk_edittext = new STKEditText(context); - // For some copy-and-paste text are not done by commitText - // in STKInputConnection, so we need an extra watcher - m_stk_edittext.addTextChangedListener(new TextWatcher() - { - @Override - public void onTextChanged(CharSequence s, - int start, int before, - int count) {} - @Override - public void beforeTextChanged(CharSequence s, - int start, int count, - int after) {} - @Override - public void afterTextChanged(Editable edit) - { - if (m_stk_edittext != null) - m_stk_edittext.updateSTKEditBox(); - } - }); - addContentView(m_stk_edittext, params); - } - else - m_stk_edittext.setLayoutParams(params); + createSTKEditText(); - m_stk_edittext.resetWhenFocus(); m_stk_edittext.setVisibility(View.VISIBLE); m_stk_edittext.requestFocus(); @@ -173,4 +178,24 @@ public class SuperTuxKartActivity extends NativeActivity } }); } + // ------------------------------------------------------------------------ + /* Called by STK in JNI. */ + public void fromSTKEditBox(final String text, final int selection_start, + final int selection_end) + { + runOnUiThread(new Runnable() + { + @Override + public void run() + { + if (m_stk_edittext == null) + createSTKEditText(); + m_stk_edittext.setTextFromSTK(text); + STKInputConnection ic = m_stk_edittext.getSTKInputConnection(); + if (ic == null) + return; + ic.setSelection(selection_start, selection_end); + } + }); + } } diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.cpp b/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.cpp index 608d205a7..e4d7cd748 100644 --- a/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.cpp +++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.cpp @@ -92,7 +92,6 @@ CIrrDeviceAndroid::CIrrDeviceAndroid(const SIrrlichtCreationParameters& param) Gyroscope(0), AccelerometerActive(false), GyroscopeActive(false), - TextInputEnabled(false), HasTouchDevice(false), IsMousePressed(false), GamepadAxisX(0), @@ -771,11 +770,6 @@ s32 CIrrDeviceAndroid::handleKeyboard(AInputEvent* androidEvent) if (event.KeyInput.Key > 0) { - if (TextInputEnabled == true) - { - event.KeyInput.Char = getUnicodeChar(androidEvent); - } - if (event.KeyInput.Char == 0) { event.KeyInput.Char = getKeyChar(event); @@ -1358,6 +1352,70 @@ void CIrrDeviceAndroid::toggleOnScreenKeyboard(bool show) } } +void CIrrDeviceAndroid::fromSTKEditBox(const core::stringw& text, int selection_start, int selection_end) +{ + if (!Android) + return; + + bool was_detached = false; + JNIEnv* env = NULL; + + jint status = Android->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6); + if (status == JNI_EDETACHED) + { + JavaVMAttachArgs args; + args.version = JNI_VERSION_1_6; + args.name = "NativeThread"; + args.group = NULL; + + status = Android->activity->vm->AttachCurrentThread(&env, &args); + was_detached = true; + } + if (status != JNI_OK) + { + os::Printer::log("Cannot attach current thread in fromSTKEditBox.", ELL_DEBUG); + return; + } + + jobject native_activity = Android->activity->clazz; + jclass class_native_activity = env->GetObjectClass(native_activity); + + if (class_native_activity == NULL) + { + os::Printer::log("fromSTKEditBox unable to find object class.", ELL_ERROR); + if (was_detached) + { + Android->activity->vm->DetachCurrentThread(); + } + return; + } + + jmethodID method_id = env->GetMethodID(class_native_activity, "fromSTKEditBox", "(Ljava/lang/String;II)V"); + if (method_id == NULL) + { + os::Printer::log("fromSTKEditBox unable to find method id.", ELL_ERROR); + if (was_detached) + { + Android->activity->vm->DetachCurrentThread(); + } + return; + } + + std::vector utf8; + // Use utf32 for emoji later + static_assert(sizeof(wchar_t) == sizeof(uint32_t), "wchar_t is not 32bit"); + uint32_t* chars = (uint32_t*)text.c_str(); + utf8::unchecked::utf32to8(chars, chars + text.size(), back_inserter(utf8)); + utf8.push_back(0); + jstring jstring_text = env->NewStringUTF(utf8.data()); + + env->CallVoidMethod(native_activity, method_id, jstring_text, (jint)selection_start, (jint)selection_end); + if (was_detached) + { + Android->activity->vm->DetachCurrentThread(); + } +} + int CIrrDeviceAndroid::getRotation() { bool was_detached = false; diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.h b/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.h index b105e4546..fbf38b2c7 100644 --- a/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.h +++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.h @@ -73,7 +73,7 @@ namespace irr virtual bool deactivateGyroscope(); virtual bool isGyroscopeActive(); virtual bool isGyroscopeAvailable(); - virtual void setTextInputEnabled(bool enabled) {TextInputEnabled = enabled;} + void fromSTKEditBox(const core::stringw& text, int selection_start, int selection_end); virtual void toggleOnScreenKeyboard(bool show); virtual bool supportsTouchDevice() const { return HasTouchDevice; } virtual bool hasHardwareKeyboard() const; @@ -141,7 +141,6 @@ namespace irr const ASensor* Gyroscope; bool AccelerometerActive; bool GyroscopeActive; - bool TextInputEnabled; static AndroidApplicationInfo ApplicationInfo; static bool IsPaused; diff --git a/src/guiengine/widgets/CGUIEditBox.cpp b/src/guiengine/widgets/CGUIEditBox.cpp index 207ac0f43..ea0d0aec3 100644 --- a/src/guiengine/widgets/CGUIEditBox.cpp +++ b/src/guiengine/widgets/CGUIEditBox.cpp @@ -124,14 +124,6 @@ CGUIEditBox::~CGUIEditBox() irr_driver->getDevice()); dl->setIMEEnable(false); } -#endif -#ifdef ANDROID - if (irr_driver->getDevice()->getType() == irr::EIDT_ANDROID) - { - CIrrDeviceAndroid* dl = dynamic_cast( - irr_driver->getDevice()); - dl->setTextInputEnabled(false); - } #endif irr_driver->getDevice()->toggleOnScreenKeyboard(false); @@ -286,14 +278,6 @@ bool CGUIEditBox::OnEvent(const SEvent& event) irr_driver->getDevice()); dl->setIMEEnable(false); } -#endif -#ifdef ANDROID - if (irr_driver->getDevice()->getType() == irr::EIDT_ANDROID) - { - CIrrDeviceAndroid* dl = dynamic_cast( - irr_driver->getDevice()); - dl->setTextInputEnabled(false); - } #endif m_from_android_edittext = false; m_composing_start = 0; @@ -315,7 +299,7 @@ bool CGUIEditBox::OnEvent(const SEvent& event) { CIrrDeviceAndroid* dl = dynamic_cast( irr_driver->getDevice()); - dl->setTextInputEnabled(true); + dl->fromSTKEditBox(Text, MarkBegin, MarkEnd); } #endif } @@ -1195,6 +1179,15 @@ void CGUIEditBox::setText(const wchar_t* text) CursorPos = Text.size(); HScrollPos = 0; breakText(); +#ifdef ANDROID + if (irr_driver->getDevice()->hasOnScreenKeyboard() && + irr_driver->getDevice()->getType() == irr::EIDT_ANDROID) + { + CIrrDeviceAndroid* dl = dynamic_cast( + irr_driver->getDevice()); + dl->fromSTKEditBox(Text, MarkBegin, MarkEnd); + } +#endif } @@ -1727,6 +1720,15 @@ void CGUIEditBox::setTextMarkers(s32 begin, s32 end) MarkBegin = begin; MarkEnd = end; sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED); +#ifdef ANDROID + if (irr_driver->getDevice()->hasOnScreenKeyboard() && + irr_driver->getDevice()->getType() == irr::EIDT_ANDROID) + { + CIrrDeviceAndroid* dl = dynamic_cast( + irr_driver->getDevice()); + dl->fromSTKEditBox(Text, MarkBegin, MarkEnd); + } +#endif } } @@ -1823,13 +1825,8 @@ void CGUIEditBox::fromAndroidEditText(const core::stringw& text, int start, m_composing_start = 0; m_composing_end = 0; - if (start != end) - setTextMarkers(start, end); - else - { - MarkBegin = 0; - MarkEnd = 0; - } + MarkBegin = start; + MarkEnd = end; if (composing_start != composing_end) {