Fix Android LineEdit editing bugs

This commit is contained in:
SkyJJ 2020-04-28 19:57:45 +02:00
parent 2fa795dea9
commit cc473b948f
14 changed files with 62 additions and 29 deletions

View File

@ -155,12 +155,12 @@ bool DisplayServerAndroid::screen_is_touchscreen(int p_screen) const {
return true; return true;
} }
void DisplayServerAndroid::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_length) { void DisplayServerAndroid::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_length, int p_cursor_start, int p_cursor_end) {
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java(); GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
ERR_FAIL_COND(!godot_io_java); ERR_FAIL_COND(!godot_io_java);
if (godot_io_java->has_vk()) { if (godot_io_java->has_vk()) {
godot_io_java->show_vk(p_existing_text, p_max_length); godot_io_java->show_vk(p_existing_text, p_max_length, p_cursor_start, p_cursor_end);
} else { } else {
ERR_PRINT("Virtual keyboard not available"); ERR_PRINT("Virtual keyboard not available");
} }

View File

@ -106,7 +106,7 @@ public:
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const; virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const; virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_length = -1); virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
virtual void virtual_keyboard_hide(); virtual void virtual_keyboard_hide();
virtual int virtual_keyboard_get_height() const; virtual int virtual_keyboard_get_height() const;

View File

@ -460,9 +460,9 @@ public class GodotIO {
return (int)(metrics.density * 160f); return (int)(metrics.density * 160f);
} }
public void showKeyboard(String p_existing_text, int p_max_input_length) { public void showKeyboard(String p_existing_text, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
if (edit != null) if (edit != null)
edit.showKeyboard(p_existing_text, p_max_input_length); edit.showKeyboard(p_existing_text, p_max_input_length, p_cursor_start, p_cursor_end);
//InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE); //InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
//inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); //inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);

View File

@ -58,6 +58,7 @@ public class GodotEditText extends EditText {
private GodotTextInputWrapper mInputWrapper; private GodotTextInputWrapper mInputWrapper;
private EditHandler sHandler = new EditHandler(this); private EditHandler sHandler = new EditHandler(this);
private String mOriginText; private String mOriginText;
private int mMaxInputLength;
private static class EditHandler extends Handler { private static class EditHandler extends Handler {
private final WeakReference<GodotEditText> mEdit; private final WeakReference<GodotEditText> mEdit;
@ -104,11 +105,18 @@ public class GodotEditText extends EditText {
String text = edit.mOriginText; String text = edit.mOriginText;
if (edit.requestFocus()) { if (edit.requestFocus()) {
edit.removeTextChangedListener(edit.mInputWrapper); edit.removeTextChangedListener(edit.mInputWrapper);
setMaxInputLength(edit);
edit.setText(""); edit.setText("");
edit.append(text); edit.append(text);
if (msg.arg2 != -1) {
edit.setSelection(msg.arg1, msg.arg2);
edit.mInputWrapper.setSelection(true);
} else {
edit.mInputWrapper.setSelection(false);
}
edit.mInputWrapper.setOriginText(text); edit.mInputWrapper.setOriginText(text);
edit.addTextChangedListener(edit.mInputWrapper); edit.addTextChangedListener(edit.mInputWrapper);
setMaxInputLength(edit, msg.arg1);
final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE); final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(edit, 0); imm.showSoftInput(edit, 0);
} }
@ -125,14 +133,10 @@ public class GodotEditText extends EditText {
} }
} }
private void setMaxInputLength(EditText p_edit_text, int p_max_input_length) { private void setMaxInputLength(EditText p_edit_text) {
if (p_max_input_length > 0) { InputFilter[] filters = new InputFilter[1];
InputFilter[] filters = new InputFilter[1]; filters[0] = new InputFilter.LengthFilter(this.mMaxInputLength);
filters[0] = new InputFilter.LengthFilter(p_max_input_length); p_edit_text.setFilters(filters);
p_edit_text.setFilters(filters);
} else {
p_edit_text.setFilters(new InputFilter[] {});
}
} }
// =========================================================== // ===========================================================
@ -164,13 +168,24 @@ public class GodotEditText extends EditText {
// =========================================================== // ===========================================================
// Methods // Methods
// =========================================================== // ===========================================================
public void showKeyboard(String p_existing_text, int p_max_input_length) { public void showKeyboard(String p_existing_text, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
mOriginText = p_existing_text; int maxInputLength = (p_max_input_length <= 0) ? Integer.MAX_VALUE : p_max_input_length;
if (p_cursor_start == -1) { // cursor position not given
this.mOriginText = p_existing_text;
this.mMaxInputLength = maxInputLength;
} else if (p_cursor_end == -1) { // not text selection
this.mOriginText = p_existing_text.substring(0, p_cursor_start);
this.mMaxInputLength = maxInputLength - (p_existing_text.length() - p_cursor_start);
} else {
this.mOriginText = p_existing_text.substring(0, p_cursor_end);
this.mMaxInputLength = maxInputLength - (p_existing_text.length() - p_cursor_end);
}
final Message msg = new Message(); final Message msg = new Message();
msg.what = HANDLER_OPEN_IME_KEYBOARD; msg.what = HANDLER_OPEN_IME_KEYBOARD;
msg.obj = this; msg.obj = this;
msg.arg1 = p_max_input_length; msg.arg1 = p_cursor_start;
msg.arg2 = p_cursor_end;
sHandler.sendMessage(msg); sHandler.sendMessage(msg);
} }

View File

@ -53,6 +53,7 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
private final GodotRenderView mRenderView; private final GodotRenderView mRenderView;
private final GodotEditText mEdit; private final GodotEditText mEdit;
private String mOriginText; private String mOriginText;
private boolean mHasSelection;
// =========================================================== // ===========================================================
// Constructors // Constructors
@ -77,6 +78,10 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
mOriginText = originText; mOriginText = originText;
} }
public void setSelection(boolean selection) {
mHasSelection = selection;
}
// =========================================================== // ===========================================================
// Methods for/from SuperClass/Interfaces // Methods for/from SuperClass/Interfaces
// =========================================================== // ===========================================================
@ -95,6 +100,11 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, true); GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, true);
GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, false); GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, false);
if (mHasSelection) {
mHasSelection = false;
break;
}
} }
} }
}); });

View File

@ -53,7 +53,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
_get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;"); _get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;");
_get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I"); _get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I");
_get_unique_id = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;"); _get_unique_id = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;");
_show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;I)V"); _show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;III)V");
_hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V"); _hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V");
_set_screen_orientation = p_env->GetMethodID(cls, "setScreenOrientation", "(I)V"); _set_screen_orientation = p_env->GetMethodID(cls, "setScreenOrientation", "(I)V");
_get_screen_orientation = p_env->GetMethodID(cls, "getScreenOrientation", "()I"); _get_screen_orientation = p_env->GetMethodID(cls, "getScreenOrientation", "()I");
@ -132,11 +132,11 @@ bool GodotIOJavaWrapper::has_vk() {
return (_show_keyboard != 0) && (_hide_keyboard != 0); return (_show_keyboard != 0) && (_hide_keyboard != 0);
} }
void GodotIOJavaWrapper::show_vk(const String &p_existing, int p_max_input_length) { void GodotIOJavaWrapper::show_vk(const String &p_existing, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
if (_show_keyboard) { if (_show_keyboard) {
JNIEnv *env = ThreadAndroid::get_env(); JNIEnv *env = ThreadAndroid::get_env();
jstring jStr = env->NewStringUTF(p_existing.utf8().get_data()); jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_max_input_length); env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_max_input_length, p_cursor_start, p_cursor_end);
} }
} }

View File

@ -70,7 +70,7 @@ public:
int get_screen_dpi(); int get_screen_dpi();
String get_unique_id(); String get_unique_id();
bool has_vk(); bool has_vk();
void show_vk(const String &p_existing, int p_max_input_length); void show_vk(const String &p_existing, int p_max_input_length, int p_cursor_start, int p_cursor_end);
void hide_vk(); void hide_vk();
int get_vk_height(); int get_vk_height();
void set_vk_height(int p_height); void set_vk_height(int p_height);

View File

@ -441,7 +441,7 @@ extern Error _shell_open(String p_uri);
extern void _set_keep_screen_on(bool p_enabled); extern void _set_keep_screen_on(bool p_enabled);
extern void _vibrate(); extern void _vibrate();
void OSIPhone::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length) { void OSIPhone::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
_show_keyboard(p_existing_text); _show_keyboard(p_existing_text);
}; };

View File

@ -170,7 +170,7 @@ public:
virtual bool can_draw() const; virtual bool can_draw() const;
virtual bool has_virtual_keyboard() const; virtual bool has_virtual_keyboard() const;
virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1); virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
virtual void hide_virtual_keyboard(); virtual void hide_virtual_keyboard();
virtual int get_virtual_keyboard_height() const; virtual int get_virtual_keyboard_height() const;

View File

@ -698,7 +698,7 @@ bool OS_UWP::has_virtual_keyboard() const {
return UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Touch; return UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Touch;
} }
void OS_UWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length) { void OS_UWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
InputPane ^ pane = InputPane::GetForCurrentView(); InputPane ^ pane = InputPane::GetForCurrentView();
pane->TryShow(); pane->TryShow();
} }

View File

@ -234,7 +234,7 @@ public:
virtual bool has_touchscreen_ui_hint() const; virtual bool has_touchscreen_ui_hint() const;
virtual bool has_virtual_keyboard() const; virtual bool has_virtual_keyboard() const;
virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1); virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
virtual void hide_virtual_keyboard(); virtual void hide_virtual_keyboard();
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false); virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);

View File

@ -119,7 +119,11 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
selection.doubleclick = false; selection.doubleclick = false;
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) { if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) {
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length); if (selection.enabled) {
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, selection.begin, selection.end);
} else {
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, cursor_pos);
}
} }
} }
@ -918,7 +922,11 @@ void LineEdit::_notification(int p_what) {
} }
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) { if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) {
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length); if (selection.enabled) {
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, selection.begin, selection.end);
} else {
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, cursor_pos);
}
} }
} break; } break;

View File

@ -213,7 +213,7 @@ bool DisplayServer::is_console_visible() const {
return false; return false;
} }
void DisplayServer::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_legth) { void DisplayServer::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_legth, int p_cursor_start, int p_cursor_end) {
WARN_PRINT("Virtual keyboard not supported by this display server."); WARN_PRINT("Virtual keyboard not supported by this display server.");
} }

View File

@ -280,7 +280,7 @@ public:
virtual void console_set_visible(bool p_enabled); virtual void console_set_visible(bool p_enabled);
virtual bool is_console_visible() const; virtual bool is_console_visible() const;
virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_legth = -1); virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_legth = -1, int p_cursor_start = -1, int p_cursor_end = -1);
virtual void virtual_keyboard_hide(); virtual void virtual_keyboard_hide();
// returns height of the currently shown virtual keyboard (0 if keyboard is hidden) // returns height of the currently shown virtual keyboard (0 if keyboard is hidden)