Fix Return key events in LineEdit & TextEdit on Android
Depending on the device implementation, editor actions could be received with different action ids or not at all for multi-line. Added a parameter to virtual keyboards to properly handle single-line and multi-line cases in all situations. Single-line: Input type set to text without multiline to make sure actions are sent. IME options are set to DONE action to force action id consistency. Multi-line: Input type set to text and multiline to make sure enter triggers new lines. Actions are disabled by the multiline flag, so '\n' characters are handled in text changed callbacks.
This commit is contained in:
parent
33d423e240
commit
8c05dadcff
16 changed files with 57 additions and 29 deletions
|
@ -627,12 +627,14 @@
|
|||
<return type="int">
|
||||
</return>
|
||||
<description>
|
||||
Returns the on-screen keyboard's height in pixels. Returns 0 if there is no keyboard or if it is currently hidden.
|
||||
</description>
|
||||
</method>
|
||||
<method name="virtual_keyboard_hide">
|
||||
<return type="void">
|
||||
</return>
|
||||
<description>
|
||||
Hides the virtual keyboard if it is shown, does nothing otherwise.
|
||||
</description>
|
||||
</method>
|
||||
<method name="virtual_keyboard_show">
|
||||
|
@ -642,13 +644,23 @@
|
|||
</argument>
|
||||
<argument index="1" name="position" type="Rect2" default="Rect2i( 0, 0, 0, 0 )">
|
||||
</argument>
|
||||
<argument index="2" name="max_length" type="int" default="-1">
|
||||
<argument index="2" name="multiline" type="bool" default="false">
|
||||
</argument>
|
||||
<argument index="3" name="cursor_start" type="int" default="-1">
|
||||
<argument index="3" name="max_length" type="int" default="-1">
|
||||
</argument>
|
||||
<argument index="4" name="cursor_end" type="int" default="-1">
|
||||
<argument index="4" name="cursor_start" type="int" default="-1">
|
||||
</argument>
|
||||
<argument index="5" name="cursor_end" type="int" default="-1">
|
||||
</argument>
|
||||
<description>
|
||||
Shows the virtual keyboard if the platform has one.
|
||||
[code]existing_text[/code] parameter is useful for implementing your own [LineEdit] or [TextEdit], as it tells the virtual keyboard what text has already been typed (the virtual keyboard uses it for auto-correct and predictions).
|
||||
[code]position[/code] parameter is the screen space [Rect2] of the edited text.
|
||||
[code]multiline[/code] parameter needs to be set to [code]true[/code] to be able to enter multiple lines of text, as in [TextEdit].
|
||||
[code]max_length[/code] limits the number of characters that can be entered if different from [code]-1[/code].
|
||||
[code]cursor_start[/code] can optionally define the current text cursor position if [code]cursor_end[/code] is not set.
|
||||
[code]cursor_start[/code] and [code]cursor_end[/code] can optionally define the current text selection.
|
||||
[b]Note:[/b] This method is implemented on Android, iOS and UWP.
|
||||
</description>
|
||||
</method>
|
||||
<method name="vsync_is_enabled" qualifiers="const">
|
||||
|
|
|
@ -155,12 +155,12 @@ bool DisplayServerAndroid::screen_is_touchscreen(int p_screen) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
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) {
|
||||
void DisplayServerAndroid::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) {
|
||||
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
|
||||
ERR_FAIL_COND(!godot_io_java);
|
||||
|
||||
if (godot_io_java->has_vk()) {
|
||||
godot_io_java->show_vk(p_existing_text, p_max_length, p_cursor_start, p_cursor_end);
|
||||
godot_io_java->show_vk(p_existing_text, p_multiline, p_max_length, p_cursor_start, p_cursor_end);
|
||||
} else {
|
||||
ERR_PRINT("Virtual keyboard not available");
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ public:
|
|||
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 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_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
|
||||
virtual void virtual_keyboard_hide();
|
||||
virtual int virtual_keyboard_get_height() const;
|
||||
|
||||
|
|
|
@ -461,9 +461,9 @@ public class GodotIO {
|
|||
return (int)(metrics.density * 160f);
|
||||
}
|
||||
|
||||
public void showKeyboard(String p_existing_text, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||
public void showKeyboard(String p_existing_text, boolean p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||
if (edit != null)
|
||||
edit.showKeyboard(p_existing_text, p_max_input_length, p_cursor_start, p_cursor_end);
|
||||
edit.showKeyboard(p_existing_text, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end);
|
||||
|
||||
//InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
//inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
|
||||
|
|
|
@ -36,6 +36,7 @@ import android.content.Context;
|
|||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.text.InputFilter;
|
||||
import android.text.InputType;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
|
@ -58,7 +59,8 @@ public class GodotEditText extends EditText {
|
|||
private GodotTextInputWrapper mInputWrapper;
|
||||
private EditHandler sHandler = new EditHandler(this);
|
||||
private String mOriginText;
|
||||
private int mMaxInputLength;
|
||||
private int mMaxInputLength = Integer.MAX_VALUE;
|
||||
private boolean mMultiline = false;
|
||||
|
||||
private static class EditHandler extends Handler {
|
||||
private final WeakReference<GodotEditText> mEdit;
|
||||
|
@ -95,7 +97,11 @@ public class GodotEditText extends EditText {
|
|||
|
||||
protected void initView() {
|
||||
setPadding(0, 0, 0, 0);
|
||||
setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
|
||||
setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE);
|
||||
}
|
||||
|
||||
public boolean isMultiline() {
|
||||
return mMultiline;
|
||||
}
|
||||
|
||||
private void handleMessage(final Message msg) {
|
||||
|
@ -115,6 +121,12 @@ public class GodotEditText extends EditText {
|
|||
edit.mInputWrapper.setSelection(false);
|
||||
}
|
||||
|
||||
int inputType = InputType.TYPE_CLASS_TEXT;
|
||||
if (edit.isMultiline()) {
|
||||
inputType |= InputType.TYPE_TEXT_FLAG_MULTI_LINE;
|
||||
}
|
||||
edit.setInputType(inputType);
|
||||
|
||||
edit.mInputWrapper.setOriginText(text);
|
||||
edit.addTextChangedListener(edit.mInputWrapper);
|
||||
final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
|
@ -189,7 +201,7 @@ public class GodotEditText extends EditText {
|
|||
// ===========================================================
|
||||
// Methods
|
||||
// ===========================================================
|
||||
public void showKeyboard(String p_existing_text, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||
public void showKeyboard(String p_existing_text, boolean p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||
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;
|
||||
|
@ -202,6 +214,8 @@ public class GodotEditText extends EditText {
|
|||
this.mMaxInputLength = maxInputLength - (p_existing_text.length() - p_cursor_end);
|
||||
}
|
||||
|
||||
this.mMultiline = p_multiline;
|
||||
|
||||
final Message msg = new Message();
|
||||
msg.what = HANDLER_OPEN_IME_KEYBOARD;
|
||||
msg.obj = this;
|
||||
|
|
|
@ -123,7 +123,7 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
|
|||
public void run() {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
int key = newChars[i];
|
||||
if (key == '\n') {
|
||||
if ((key == '\n') && !mEdit.isMultiline()) {
|
||||
// Return keys are handled through action events
|
||||
continue;
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
|
|||
});
|
||||
}
|
||||
|
||||
if (pActionID == EditorInfo.IME_NULL) {
|
||||
if (pActionID == EditorInfo.IME_ACTION_DONE) {
|
||||
// Enter key has been pressed
|
||||
GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, true);
|
||||
GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, false);
|
||||
|
|
|
@ -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_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I");
|
||||
_get_unique_id = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;");
|
||||
_show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;III)V");
|
||||
_show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;ZIII)V");
|
||||
_hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V");
|
||||
_set_screen_orientation = p_env->GetMethodID(cls, "setScreenOrientation", "(I)V");
|
||||
_get_screen_orientation = p_env->GetMethodID(cls, "getScreenOrientation", "()I");
|
||||
|
@ -132,11 +132,11 @@ bool GodotIOJavaWrapper::has_vk() {
|
|||
return (_show_keyboard != 0) && (_hide_keyboard != 0);
|
||||
}
|
||||
|
||||
void GodotIOJavaWrapper::show_vk(const String &p_existing, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||
void GodotIOJavaWrapper::show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||
if (_show_keyboard) {
|
||||
JNIEnv *env = ThreadAndroid::get_env();
|
||||
jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
|
||||
env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_max_input_length, p_cursor_start, p_cursor_end);
|
||||
env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ public:
|
|||
int get_screen_dpi();
|
||||
String get_unique_id();
|
||||
bool has_vk();
|
||||
void show_vk(const String &p_existing, int p_max_input_length, int p_cursor_start, int p_cursor_end);
|
||||
void show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end);
|
||||
void hide_vk();
|
||||
int get_vk_height();
|
||||
void set_vk_height(int p_height);
|
||||
|
|
|
@ -178,7 +178,7 @@ public:
|
|||
|
||||
virtual bool screen_is_touchscreen(int p_screen) const override;
|
||||
|
||||
virtual void 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) override;
|
||||
virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) override;
|
||||
virtual void virtual_keyboard_hide() override;
|
||||
|
||||
void virtual_keyboard_set_height(int height);
|
||||
|
|
|
@ -638,7 +638,7 @@ bool DisplayServerIPhone::screen_is_touchscreen(int p_screen) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
void DisplayServerIPhone::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) {
|
||||
void DisplayServerIPhone::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) {
|
||||
[AppDelegate.viewController.godotView becomeFirstResponderWithString:p_existing_text];
|
||||
}
|
||||
|
||||
|
|
|
@ -715,7 +715,7 @@ bool OS_UWP::has_virtual_keyboard() const {
|
|||
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, int p_cursor_start, int p_cursor_end) {
|
||||
void OS_UWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
||||
InputPane ^ pane = InputPane::GetForCurrentView();
|
||||
pane->TryShow();
|
||||
}
|
||||
|
|
|
@ -234,7 +234,7 @@ public:
|
|||
virtual bool has_touchscreen_ui_hint() 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, int p_cursor_start = -1, int p_cursor_end = -1);
|
||||
virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
|
||||
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);
|
||||
|
|
|
@ -120,9 +120,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
|
|||
|
||||
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
|
||||
if (selection.enabled) {
|
||||
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, selection.begin, selection.end);
|
||||
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end);
|
||||
} else {
|
||||
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, cursor_pos);
|
||||
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, cursor_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -313,6 +313,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
|
|||
DisplayServer::get_singleton()->virtual_keyboard_hide();
|
||||
}
|
||||
|
||||
return;
|
||||
} break;
|
||||
|
||||
case KEY_BACKSPACE: {
|
||||
|
@ -943,9 +944,9 @@ void LineEdit::_notification(int p_what) {
|
|||
|
||||
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
|
||||
if (selection.enabled) {
|
||||
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, selection.begin, selection.end);
|
||||
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end);
|
||||
} else {
|
||||
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length, cursor_pos);
|
||||
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, cursor_pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1632,7 +1632,7 @@ void TextEdit::_notification(int p_what) {
|
|||
}
|
||||
|
||||
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) {
|
||||
DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect());
|
||||
DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), true);
|
||||
}
|
||||
} break;
|
||||
case NOTIFICATION_FOCUS_EXIT: {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "display_server.h"
|
||||
|
||||
#include "core/input/input.h"
|
||||
#include "core/method_bind_ext.gen.inc"
|
||||
#include "scene/resources/texture.h"
|
||||
|
||||
DisplayServer *DisplayServer::singleton = nullptr;
|
||||
|
@ -213,7 +214,7 @@ bool DisplayServer::is_console_visible() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void DisplayServer::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) {
|
||||
void DisplayServer::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) {
|
||||
WARN_PRINT("Virtual keyboard not supported by this display server.");
|
||||
}
|
||||
|
||||
|
@ -455,7 +456,7 @@ void DisplayServer::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("console_set_visible", "console_visible"), &DisplayServer::console_set_visible);
|
||||
ClassDB::bind_method(D_METHOD("is_console_visible"), &DisplayServer::is_console_visible);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("virtual_keyboard_show", "existing_text", "position", "max_length", "cursor_start", "cursor_end"), &DisplayServer::virtual_keyboard_show, DEFVAL(Rect2i()), DEFVAL(-1), DEFVAL(-1), DEFVAL(-1));
|
||||
ClassDB::bind_method(D_METHOD("virtual_keyboard_show", "existing_text", "position", "multiline", "max_length", "cursor_start", "cursor_end"), &DisplayServer::virtual_keyboard_show, DEFVAL(Rect2i()), DEFVAL(false), DEFVAL(-1), DEFVAL(-1), DEFVAL(-1));
|
||||
ClassDB::bind_method(D_METHOD("virtual_keyboard_hide"), &DisplayServer::virtual_keyboard_hide);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("virtual_keyboard_get_height"), &DisplayServer::virtual_keyboard_get_height);
|
||||
|
|
|
@ -288,7 +288,7 @@ public:
|
|||
virtual void console_set_visible(bool p_enabled);
|
||||
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_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
|
||||
virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
|
||||
virtual void virtual_keyboard_hide();
|
||||
|
||||
// returns height of the currently shown virtual keyboard (0 if keyboard is hidden)
|
||||
|
|
Loading…
Reference in a new issue