Allow copying from STK edit box to android edit text

This commit is contained in:
Benau 2019-05-25 22:19:15 +08:00
parent e1a7901c4c
commit 34e680bfbd
5 changed files with 164 additions and 72 deletions

View File

@ -17,6 +17,11 @@ public class STKEditText extends EditText
private int m_composing_end; 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, private native static void editText2STKEditbox(String full_text, int start,
int end, int composing_start, int end, int composing_start,
@ -28,31 +33,29 @@ public class STKEditText extends EditText
setFocusableInTouchMode(true); setFocusableInTouchMode(true);
m_composing_start = 0; m_composing_start = 0;
m_composing_end = 0; m_composing_end = 0;
m_from_stk_editbox = false;
m_stk_input_connection = null;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@Override @Override
public InputConnection onCreateInputConnection(EditorInfo out_attrs) public InputConnection onCreateInputConnection(EditorInfo out_attrs)
{ {
STKInputConnection sic = if (m_stk_input_connection == null)
new STKInputConnection(super.onCreateInputConnection(out_attrs), this); {
m_stk_input_connection = new STKInputConnection(
super.onCreateInputConnection(out_attrs), this);
}
out_attrs.actionLabel = null; out_attrs.actionLabel = null;
out_attrs.inputType = InputType.TYPE_CLASS_TEXT; out_attrs.inputType = InputType.TYPE_CLASS_TEXT;
out_attrs.imeOptions = EditorInfo.IME_ACTION_NEXT | out_attrs.imeOptions = EditorInfo.IME_ACTION_NEXT |
EditorInfo.IME_FLAG_NO_FULLSCREEN | EditorInfo.IME_FLAG_NO_FULLSCREEN |
EditorInfo.IME_FLAG_NO_EXTRACT_UI; EditorInfo.IME_FLAG_NO_EXTRACT_UI;
return sic; return m_stk_input_connection;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@Override @Override
public boolean onCheckIsTextEditor() { return true; } 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) public void setComposingRegion(int start, int end)
{ {
// From doc of InputConnectionWrapper, it says: // From doc of InputConnectionWrapper, it says:
@ -71,7 +74,7 @@ public class STKEditText extends EditText
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
public void updateSTKEditBox() public void updateSTKEditBox()
{ {
if (!isFocused()) if (!isFocused() || m_from_stk_editbox)
return; return;
editText2STKEditbox(getText().toString(), getSelectionStart(), editText2STKEditbox(getText().toString(), getSelectionStart(),
getSelectionEnd(), m_composing_start, m_composing_end); getSelectionEnd(), m_composing_start, m_composing_end);
@ -82,4 +85,14 @@ public class STKEditText extends EditText
clearFocus(); clearFocus();
setVisibility(View.GONE); 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; }
} }

View File

@ -31,6 +31,9 @@ public class SuperTuxKartActivity extends NativeActivity
InputMethodManager imm = (InputMethodManager) InputMethodManager imm = (InputMethodManager)
getSystemService(Context.INPUT_METHOD_SERVICE); getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null)
return;
imm.hideSoftInputFromWindow(m_stk_edittext.getWindowToken(), 0); imm.hideSoftInputFromWindow(m_stk_edittext.getWindowToken(), 0);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -47,6 +50,34 @@ public class SuperTuxKartActivity extends NativeActivity
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); 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 @Override
public void onCreate(Bundle instance) public void onCreate(Bundle instance)
{ {
@ -120,38 +151,12 @@ public class SuperTuxKartActivity extends NativeActivity
{ {
InputMethodManager imm = (InputMethodManager) InputMethodManager imm = (InputMethodManager)
getSystemService(Context.INPUT_METHOD_SERVICE); 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) if (m_stk_edittext == null)
{ createSTKEditText();
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);
m_stk_edittext.resetWhenFocus();
m_stk_edittext.setVisibility(View.VISIBLE); m_stk_edittext.setVisibility(View.VISIBLE);
m_stk_edittext.requestFocus(); 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);
}
});
}
} }

View File

@ -92,7 +92,6 @@ CIrrDeviceAndroid::CIrrDeviceAndroid(const SIrrlichtCreationParameters& param)
Gyroscope(0), Gyroscope(0),
AccelerometerActive(false), AccelerometerActive(false),
GyroscopeActive(false), GyroscopeActive(false),
TextInputEnabled(false),
HasTouchDevice(false), HasTouchDevice(false),
IsMousePressed(false), IsMousePressed(false),
GamepadAxisX(0), GamepadAxisX(0),
@ -771,11 +770,6 @@ s32 CIrrDeviceAndroid::handleKeyboard(AInputEvent* androidEvent)
if (event.KeyInput.Key > 0) if (event.KeyInput.Key > 0)
{ {
if (TextInputEnabled == true)
{
event.KeyInput.Char = getUnicodeChar(androidEvent);
}
if (event.KeyInput.Char == 0) if (event.KeyInput.Char == 0)
{ {
event.KeyInput.Char = getKeyChar(event); 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<char> 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() int CIrrDeviceAndroid::getRotation()
{ {
bool was_detached = false; bool was_detached = false;

View File

@ -73,7 +73,7 @@ namespace irr
virtual bool deactivateGyroscope(); virtual bool deactivateGyroscope();
virtual bool isGyroscopeActive(); virtual bool isGyroscopeActive();
virtual bool isGyroscopeAvailable(); 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 void toggleOnScreenKeyboard(bool show);
virtual bool supportsTouchDevice() const { return HasTouchDevice; } virtual bool supportsTouchDevice() const { return HasTouchDevice; }
virtual bool hasHardwareKeyboard() const; virtual bool hasHardwareKeyboard() const;
@ -141,7 +141,6 @@ namespace irr
const ASensor* Gyroscope; const ASensor* Gyroscope;
bool AccelerometerActive; bool AccelerometerActive;
bool GyroscopeActive; bool GyroscopeActive;
bool TextInputEnabled;
static AndroidApplicationInfo ApplicationInfo; static AndroidApplicationInfo ApplicationInfo;
static bool IsPaused; static bool IsPaused;

View File

@ -124,14 +124,6 @@ CGUIEditBox::~CGUIEditBox()
irr_driver->getDevice()); irr_driver->getDevice());
dl->setIMEEnable(false); dl->setIMEEnable(false);
} }
#endif
#ifdef ANDROID
if (irr_driver->getDevice()->getType() == irr::EIDT_ANDROID)
{
CIrrDeviceAndroid* dl = dynamic_cast<CIrrDeviceAndroid*>(
irr_driver->getDevice());
dl->setTextInputEnabled(false);
}
#endif #endif
irr_driver->getDevice()->toggleOnScreenKeyboard(false); irr_driver->getDevice()->toggleOnScreenKeyboard(false);
@ -286,14 +278,6 @@ bool CGUIEditBox::OnEvent(const SEvent& event)
irr_driver->getDevice()); irr_driver->getDevice());
dl->setIMEEnable(false); dl->setIMEEnable(false);
} }
#endif
#ifdef ANDROID
if (irr_driver->getDevice()->getType() == irr::EIDT_ANDROID)
{
CIrrDeviceAndroid* dl = dynamic_cast<CIrrDeviceAndroid*>(
irr_driver->getDevice());
dl->setTextInputEnabled(false);
}
#endif #endif
m_from_android_edittext = false; m_from_android_edittext = false;
m_composing_start = 0; m_composing_start = 0;
@ -315,7 +299,7 @@ bool CGUIEditBox::OnEvent(const SEvent& event)
{ {
CIrrDeviceAndroid* dl = dynamic_cast<CIrrDeviceAndroid*>( CIrrDeviceAndroid* dl = dynamic_cast<CIrrDeviceAndroid*>(
irr_driver->getDevice()); irr_driver->getDevice());
dl->setTextInputEnabled(true); dl->fromSTKEditBox(Text, MarkBegin, MarkEnd);
} }
#endif #endif
} }
@ -1195,6 +1179,15 @@ void CGUIEditBox::setText(const wchar_t* text)
CursorPos = Text.size(); CursorPos = Text.size();
HScrollPos = 0; HScrollPos = 0;
breakText(); breakText();
#ifdef ANDROID
if (irr_driver->getDevice()->hasOnScreenKeyboard() &&
irr_driver->getDevice()->getType() == irr::EIDT_ANDROID)
{
CIrrDeviceAndroid* dl = dynamic_cast<CIrrDeviceAndroid*>(
irr_driver->getDevice());
dl->fromSTKEditBox(Text, MarkBegin, MarkEnd);
}
#endif
} }
@ -1727,6 +1720,15 @@ void CGUIEditBox::setTextMarkers(s32 begin, s32 end)
MarkBegin = begin; MarkBegin = begin;
MarkEnd = end; MarkEnd = end;
sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED); sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED);
#ifdef ANDROID
if (irr_driver->getDevice()->hasOnScreenKeyboard() &&
irr_driver->getDevice()->getType() == irr::EIDT_ANDROID)
{
CIrrDeviceAndroid* dl = dynamic_cast<CIrrDeviceAndroid*>(
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_start = 0;
m_composing_end = 0; m_composing_end = 0;
if (start != end) MarkBegin = start;
setTextMarkers(start, end); MarkEnd = end;
else
{
MarkBegin = 0;
MarkEnd = 0;
}
if (composing_start != composing_end) if (composing_start != composing_end)
{ {