From ca7447daf62d45b01bff6147d5c00cd283940e47 Mon Sep 17 00:00:00 2001
From: Ruslan Mustakov <r.mustakov@gmail.com>
Date: Mon, 2 Oct 2017 16:40:16 +0700
Subject: [PATCH] Improve input handling on Android

 - Dispatch input immediately as it comes, instead of delaying it to the
   next step().

 - Fix text box input handling when caret is at the middle of the text.

 - Minimize queueEvent calls on Java side.
---
 .../godot/input/GodotTextInputWrapper.java    | 73 ++++++-------------
 platform/android/java_glue.cpp                | 63 +++-------------
 2 files changed, 30 insertions(+), 106 deletions(-)

diff --git a/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java
index 04669a3b0c2..ac424ab9f82 100644
--- a/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java
+++ b/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java
@@ -88,79 +88,48 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
 	public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) {
 		//Log.d(TAG, "beforeTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",after: " + after);
 
-		for (int i=0;i<count;i++){
-			mView.queueEvent(new Runnable() {
-				@Override
-				public void run() {
+		mView.queueEvent(new Runnable() {
+			@Override
+			public void run() {
+				for (int i = 0; i < count; ++i) {
 					GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true);
 					GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false);
 				}
-			});
-		}
+			}
+		});
 	}
 
 	@Override
 	public void onTextChanged(final CharSequence pCharSequence, final int start, final int before, final int count) {
 		//Log.d(TAG, "onTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",before: " + before);
 
-		for (int i=start;i<start+count;i++){
-			final int ch = pCharSequence.charAt(i);
-			mView.queueEvent(new Runnable() {
-				@Override
-				public void run() {
+		mView.queueEvent(new Runnable() {
+			@Override
+			public void run() {
+				for (int i = start; i < start + count; ++i) {
+					final int ch = pCharSequence.charAt(i);
 					GodotLib.key(0, ch, true);
 					GodotLib.key(0, ch, false);
 				}
-			});
-		}
-
+			}
+		});
 	}
 
 	@Override
 	public boolean onEditorAction(final TextView pTextView, final int pActionID, final KeyEvent pKeyEvent) {
 		if (this.mEdit == pTextView && this.isFullScreenEdit()) {
-			// user press the action button, delete all old text and insert new text
-			for (int i = this.mOriginText.length(); i > 0; i--) {
-				mView.queueEvent(new Runnable() {
-					@Override
-					public void run() {
-						GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true);
-						GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false);
-					}
-				});
+			final String characters = pKeyEvent.getCharacters();
 
-				/*
-				if (BuildConfig.DEBUG) {
-					Log.d(TAG, "deleteBackward");
-				}
-				*/
-			}
-			String text = pTextView.getText().toString();
-
-			/* If user input nothing, translate "\n" to engine. */
-			if (text.compareTo("") == 0) {
-				text = "\n";
-			}
-
-			if ('\n' != text.charAt(text.length() - 1)) {
-				text += '\n';
-			}
-
-			for(int i = 0; i < text.length(); i++) {
-				final int ch = text.codePointAt(i);
-				mView.queueEvent(new Runnable() {
-					@Override
-					public void run() {
+			mView.queueEvent(new Runnable() {
+				@Override
+				public void run() {
+					for (int i = 0; i < characters.length(); i++) {
+						final int ch = characters.codePointAt(i);
 						GodotLib.key(0, ch, true);
 						GodotLib.key(0, ch, false);
 					}
-				});
-			}
-			/*
-			if (BuildConfig.DEBUG) {
-				Log.d(TAG, "insertText(" + insertText + ")");
-			}
-			*/
+				}
+			});
 		}
 
 		if (pActionID == EditorInfo.IME_ACTION_DONE) {
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
index 509d1bf1236..125b034b479 100644
--- a/platform/android/java_glue.cpp
+++ b/platform/android/java_glue.cpp
@@ -602,21 +602,10 @@ struct TST {
 
 TST tst;
 
-struct JAndroidPointerEvent {
-
-	Vector<OS_Android::TouchPos> points;
-	int pointer;
-	int what;
-};
-
-static List<JAndroidPointerEvent> pointer_events;
-static List<Ref<InputEvent> > key_events;
-static List<OS_Android::JoypadEvent> joy_events;
 static bool initialized = false;
 static int step = 0;
 static bool resized = false;
 static bool resized_reload = false;
-static bool go_back_request = false;
 static Size2 new_size;
 static Vector3 accelerometer;
 static Vector3 magnetometer;
@@ -624,8 +613,6 @@ static Vector3 gyroscope;
 static HashMap<String, JNISingleton *> jni_singletons;
 static jobject godot_io;
 
-static Vector<int> joy_device_ids;
-
 typedef void (*GFXInitFunc)(void *ud, bool gl2);
 
 static jmethodID _on_video_init = 0;
@@ -986,7 +973,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en
 }
 
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jobject obj) {
-	go_back_request = true;
+	os_android->main_loop_request_go_back();
 }
 
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj) {
@@ -1011,36 +998,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job
 
 	//__android_log_print(ANDROID_LOG_INFO,"godot","**STEP EVENT! - %p-%i\n",env,Thread::get_caller_id());
 
-	while (pointer_events.size()) {
-
-		JAndroidPointerEvent jpe = pointer_events.front()->get();
-		os_android->process_touch(jpe.what, jpe.pointer, jpe.points);
-
-		pointer_events.pop_front();
-	}
-
-	while (key_events.size()) {
-
-		Ref<InputEvent> event = key_events.front()->get();
-		os_android->process_event(event);
-
-		key_events.pop_front();
-	};
-
-	while (joy_events.size()) {
-
-		OS_Android::JoypadEvent event = joy_events.front()->get();
-		os_android->process_joy_event(event);
-
-		joy_events.pop_front();
-	}
-
-	if (go_back_request) {
-
-		os_android->main_loop_request_go_back();
-		go_back_request = false;
-	}
-
 	os_android->process_accelerometer(accelerometer);
 
 	os_android->process_magnetometer(magnetometer);
@@ -1071,12 +1028,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jo
 		points.push_back(tp);
 	}
 
-	JAndroidPointerEvent jpe;
-	jpe.pointer = pointer;
-	jpe.points = points;
-	jpe.what = ev;
+	os_android->process_touch(ev, pointer, points);
 
-	pointer_events.push_back(jpe);
 	/*
 	if (os_android)
 		os_android->process_touch(ev,pointer,points);
@@ -1346,7 +1299,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env
 	jevent.index = p_button;
 	jevent.pressed = p_pressed;
 
-	joy_events.push_back(jevent);
+	os_android->process_joy_event(jevent);
 }
 
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jobject obj, jint p_device, jint p_axis, jfloat p_value) {
@@ -1357,7 +1310,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env,
 	jevent.index = p_axis;
 	jevent.value = p_value;
 
-	joy_events.push_back(jevent);
+	os_android->process_joy_event(jevent);
 }
 
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jobject obj, jint p_device, jint p_hat_x, jint p_hat_y) {
@@ -1378,7 +1331,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, j
 			hat |= InputDefault::HAT_MASK_DOWN;
 	}
 	jevent.hat = hat;
-	joy_events.push_back(jevent);
+
+	os_android->process_joy_event(jevent);
 }
 
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jobject obj, jint p_device, jboolean p_connected, jstring p_name) {
@@ -1391,6 +1345,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jobject obj, jint p_scancode, jint p_unicode_char, jboolean p_pressed) {
 
 	Ref<InputEventKey> ievent;
+	ievent.instance();
 	int val = p_unicode_char;
 	int scancode = android_get_keysym(p_scancode);
 	ievent->set_scancode(scancode);
@@ -1409,10 +1364,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jobj
 		ievent->set_unicode(KEY_ENTER);
 	} else if (p_scancode == 4) {
 
-		go_back_request = true;
+		os_android->main_loop_request_go_back();
 	}
 
-	key_events.push_back(ievent);
+	os_android->process_event(ievent);
 }
 
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) {