Browse Source

Merge pull request #37158 from thebestnom/android-click-support

Support mouse events on Android
Rémi Verschelde 4 years ago
parent
commit
41f66761fd

+ 3 - 124
platform/android/android_keys_utils.h

@@ -31,130 +31,9 @@
 #ifndef ANDROID_KEYS_UTILS_H
 #define ANDROID_KEYS_UTILS_H
 
+#include <android/input.h>
 #include <core/os/keyboard.h>
 
-/*
- * Android Key codes.
- */
-enum {
-	AKEYCODE_UNKNOWN = 0,
-	AKEYCODE_SOFT_LEFT = 1,
-	AKEYCODE_SOFT_RIGHT = 2,
-	AKEYCODE_HOME = 3,
-	AKEYCODE_BACK = 4,
-	AKEYCODE_CALL = 5,
-	AKEYCODE_ENDCALL = 6,
-	AKEYCODE_0 = 7,
-	AKEYCODE_1 = 8,
-	AKEYCODE_2 = 9,
-	AKEYCODE_3 = 10,
-	AKEYCODE_4 = 11,
-	AKEYCODE_5 = 12,
-	AKEYCODE_6 = 13,
-	AKEYCODE_7 = 14,
-	AKEYCODE_8 = 15,
-	AKEYCODE_9 = 16,
-	AKEYCODE_STAR = 17,
-	AKEYCODE_POUND = 18,
-	AKEYCODE_DPAD_UP = 19,
-	AKEYCODE_DPAD_DOWN = 20,
-	AKEYCODE_DPAD_LEFT = 21,
-	AKEYCODE_DPAD_RIGHT = 22,
-	AKEYCODE_DPAD_CENTER = 23,
-	AKEYCODE_VOLUME_UP = 24,
-	AKEYCODE_VOLUME_DOWN = 25,
-	AKEYCODE_POWER = 26,
-	AKEYCODE_CAMERA = 27,
-	AKEYCODE_CLEAR = 28,
-	AKEYCODE_A = 29,
-	AKEYCODE_B = 30,
-	AKEYCODE_C = 31,
-	AKEYCODE_D = 32,
-	AKEYCODE_E = 33,
-	AKEYCODE_F = 34,
-	AKEYCODE_G = 35,
-	AKEYCODE_H = 36,
-	AKEYCODE_I = 37,
-	AKEYCODE_J = 38,
-	AKEYCODE_K = 39,
-	AKEYCODE_L = 40,
-	AKEYCODE_M = 41,
-	AKEYCODE_N = 42,
-	AKEYCODE_O = 43,
-	AKEYCODE_P = 44,
-	AKEYCODE_Q = 45,
-	AKEYCODE_R = 46,
-	AKEYCODE_S = 47,
-	AKEYCODE_T = 48,
-	AKEYCODE_U = 49,
-	AKEYCODE_V = 50,
-	AKEYCODE_W = 51,
-	AKEYCODE_X = 52,
-	AKEYCODE_Y = 53,
-	AKEYCODE_Z = 54,
-	AKEYCODE_COMMA = 55,
-	AKEYCODE_PERIOD = 56,
-	AKEYCODE_ALT_LEFT = 57,
-	AKEYCODE_ALT_RIGHT = 58,
-	AKEYCODE_SHIFT_LEFT = 59,
-	AKEYCODE_SHIFT_RIGHT = 60,
-	AKEYCODE_TAB = 61,
-	AKEYCODE_SPACE = 62,
-	AKEYCODE_SYM = 63,
-	AKEYCODE_EXPLORER = 64,
-	AKEYCODE_ENVELOPE = 65,
-	AKEYCODE_ENTER = 66,
-	AKEYCODE_DEL = 67,
-	AKEYCODE_GRAVE = 68,
-	AKEYCODE_MINUS = 69,
-	AKEYCODE_EQUALS = 70,
-	AKEYCODE_LEFT_BRACKET = 71,
-	AKEYCODE_RIGHT_BRACKET = 72,
-	AKEYCODE_BACKSLASH = 73,
-	AKEYCODE_SEMICOLON = 74,
-	AKEYCODE_APOSTROPHE = 75,
-	AKEYCODE_SLASH = 76,
-	AKEYCODE_AT = 77,
-	AKEYCODE_NUM = 78,
-	AKEYCODE_HEADSETHOOK = 79,
-	AKEYCODE_FOCUS = 80, // *Camera* focus
-	AKEYCODE_PLUS = 81,
-	AKEYCODE_MENU = 82,
-	AKEYCODE_NOTIFICATION = 83,
-	AKEYCODE_SEARCH = 84,
-	AKEYCODE_MEDIA_PLAY_PAUSE = 85,
-	AKEYCODE_MEDIA_STOP = 86,
-	AKEYCODE_MEDIA_NEXT = 87,
-	AKEYCODE_MEDIA_PREVIOUS = 88,
-	AKEYCODE_MEDIA_REWIND = 89,
-	AKEYCODE_MEDIA_FAST_FORWARD = 90,
-	AKEYCODE_MUTE = 91,
-	AKEYCODE_PAGE_UP = 92,
-	AKEYCODE_PAGE_DOWN = 93,
-	AKEYCODE_PICTSYMBOLS = 94,
-	AKEYCODE_SWITCH_CHARSET = 95,
-	AKEYCODE_BUTTON_A = 96,
-	AKEYCODE_BUTTON_B = 97,
-	AKEYCODE_BUTTON_C = 98,
-	AKEYCODE_BUTTON_X = 99,
-	AKEYCODE_BUTTON_Y = 100,
-	AKEYCODE_BUTTON_Z = 101,
-	AKEYCODE_BUTTON_L1 = 102,
-	AKEYCODE_BUTTON_R1 = 103,
-	AKEYCODE_BUTTON_L2 = 104,
-	AKEYCODE_BUTTON_R2 = 105,
-	AKEYCODE_BUTTON_THUMBL = 106,
-	AKEYCODE_BUTTON_THUMBR = 107,
-	AKEYCODE_BUTTON_START = 108,
-	AKEYCODE_BUTTON_SELECT = 109,
-	AKEYCODE_BUTTON_MODE = 110,
-	AKEYCODE_CONTROL_LEFT = 113,
-	AKEYCODE_CONTROL_RIGHT = 114,
-
-	// NOTE: If you add a new keycode here you must also add it to several other files.
-	//       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
-};
-
 struct _WinTranslatePair {
 	unsigned int keysym;
 	unsigned int keycode;
@@ -248,8 +127,8 @@ static _WinTranslatePair _ak_to_keycode[] = {
 	{ KEY_BACKSLASH, AKEYCODE_BACKSLASH },
 	{ KEY_BRACKETLEFT, AKEYCODE_LEFT_BRACKET },
 	{ KEY_BRACKETRIGHT, AKEYCODE_RIGHT_BRACKET },
-	{ KEY_CONTROL, AKEYCODE_CONTROL_LEFT },
-	{ KEY_CONTROL, AKEYCODE_CONTROL_RIGHT },
+	{ KEY_CONTROL, AKEYCODE_CTRL_LEFT },
+	{ KEY_CONTROL, AKEYCODE_CTRL_RIGHT },
 	{ KEY_UNKNOWN, 0 }
 };
 /*

+ 144 - 24
platform/android/display_server_android.cpp

@@ -36,6 +36,8 @@
 #include "java_godot_wrapper.h"
 #include "os_android.h"
 
+#include <android/input.h>
+
 #if defined(VULKAN_ENABLED)
 #include "drivers/vulkan/rendering_device_vulkan.h"
 #include "platform/android/vulkan/vulkan_context_android.h"
@@ -55,7 +57,7 @@ bool DisplayServerAndroid::has_feature(Feature p_feature) const {
 		//case FEATURE_HIDPI:
 		//case FEATURE_ICON:
 		//case FEATURE_IME:
-		//case FEATURE_MOUSE:
+		case FEATURE_MOUSE:
 		//case FEATURE_MOUSE_WARP:
 		//case FEATURE_NATIVE_DIALOG:
 		//case FEATURE_NATIVE_ICON:
@@ -343,7 +345,7 @@ void DisplayServerAndroid::alert(const String &p_alert, const String &p_title) {
 }
 
 void DisplayServerAndroid::process_events() {
-	// Nothing to do
+	Input::get_singleton()->flush_accumulated_events();
 }
 
 Vector<String> DisplayServerAndroid::get_rendering_drivers_func() {
@@ -398,6 +400,8 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
 
 	keep_screen_on = GLOBAL_GET("display/window/energy_saving/keep_screen_on");
 
+	buttons_state = 0;
+
 #if defined(OPENGL_ENABLED)
 	if (rendering_driver == "opengl") {
 		bool gl_initialization_error = false;
@@ -532,12 +536,12 @@ void DisplayServerAndroid::process_key_event(int p_keycode, int p_scancode, int
 		OS_Android::get_singleton()->main_loop_request_go_back();
 	}
 
-	Input::get_singleton()->parse_input_event(ev);
+	Input::get_singleton()->accumulate_input_event(ev);
 }
 
-void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector<DisplayServerAndroid::TouchPos> &p_points) {
-	switch (p_what) {
-		case 0: { //gesture begin
+void DisplayServerAndroid::process_touch(int p_event, int p_pointer, const Vector<DisplayServerAndroid::TouchPos> &p_points) {
+	switch (p_event) {
+		case AMOTION_EVENT_ACTION_DOWN: { //gesture begin
 			if (touch.size()) {
 				//end all if exist
 				for (int i = 0; i < touch.size(); i++) {
@@ -546,7 +550,7 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
 					ev->set_index(touch[i].id);
 					ev->set_pressed(false);
 					ev->set_position(touch[i].pos);
-					Input::get_singleton()->parse_input_event(ev);
+					Input::get_singleton()->accumulate_input_event(ev);
 				}
 			}
 
@@ -563,11 +567,11 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
 				ev->set_index(touch[i].id);
 				ev->set_pressed(true);
 				ev->set_position(touch[i].pos);
-				Input::get_singleton()->parse_input_event(ev);
+				Input::get_singleton()->accumulate_input_event(ev);
 			}
 
 		} break;
-		case 1: { //motion
+		case AMOTION_EVENT_ACTION_MOVE: { //motion
 			ERR_FAIL_COND(touch.size() != p_points.size());
 
 			for (int i = 0; i < touch.size(); i++) {
@@ -589,12 +593,13 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
 				ev->set_index(touch[i].id);
 				ev->set_position(p_points[idx].pos);
 				ev->set_relative(p_points[idx].pos - touch[i].pos);
-				Input::get_singleton()->parse_input_event(ev);
+				Input::get_singleton()->accumulate_input_event(ev);
 				touch.write[i].pos = p_points[idx].pos;
 			}
 
 		} break;
-		case 2: { //release
+		case AMOTION_EVENT_ACTION_CANCEL:
+		case AMOTION_EVENT_ACTION_UP: { //release
 			if (touch.size()) {
 				//end all if exist
 				for (int i = 0; i < touch.size(); i++) {
@@ -603,12 +608,12 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
 					ev->set_index(touch[i].id);
 					ev->set_pressed(false);
 					ev->set_position(touch[i].pos);
-					Input::get_singleton()->parse_input_event(ev);
+					Input::get_singleton()->accumulate_input_event(ev);
 				}
 				touch.clear();
 			}
 		} break;
-		case 3: { // add touch
+		case AMOTION_EVENT_ACTION_POINTER_DOWN: { // add touch
 			for (int i = 0; i < p_points.size(); i++) {
 				if (p_points[i].id == p_pointer) {
 					TouchPos tp = p_points[i];
@@ -620,13 +625,13 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
 					ev->set_index(tp.id);
 					ev->set_pressed(true);
 					ev->set_position(tp.pos);
-					Input::get_singleton()->parse_input_event(ev);
+					Input::get_singleton()->accumulate_input_event(ev);
 
 					break;
 				}
 			}
 		} break;
-		case 4: { // remove touch
+		case AMOTION_EVENT_ACTION_POINTER_UP: { // remove touch
 			for (int i = 0; i < touch.size(); i++) {
 				if (touch[i].id == p_pointer) {
 					Ref<InputEventScreenTouch> ev;
@@ -634,7 +639,7 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
 					ev->set_index(touch[i].id);
 					ev->set_pressed(false);
 					ev->set_position(touch[i].pos);
-					Input::get_singleton()->parse_input_event(ev);
+					Input::get_singleton()->accumulate_input_event(ev);
 					touch.remove(i);
 
 					break;
@@ -647,30 +652,116 @@ void DisplayServerAndroid::process_touch(int p_what, int p_pointer, const Vector
 void DisplayServerAndroid::process_hover(int p_type, Point2 p_pos) {
 	// https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER
 	switch (p_type) {
-		case 7: // hover move
-		case 9: // hover enter
-		case 10: { // hover exit
+		case AMOTION_EVENT_ACTION_HOVER_MOVE: // hover move
+		case AMOTION_EVENT_ACTION_HOVER_ENTER: // hover enter
+		case AMOTION_EVENT_ACTION_HOVER_EXIT: { // hover exit
 			Ref<InputEventMouseMotion> ev;
 			ev.instance();
 			_set_key_modifier_state(ev);
 			ev->set_position(p_pos);
 			ev->set_global_position(p_pos);
 			ev->set_relative(p_pos - hover_prev_pos);
-			Input::get_singleton()->parse_input_event(ev);
+			Input::get_singleton()->accumulate_input_event(ev);
 			hover_prev_pos = p_pos;
 		} break;
 	}
 }
 
-void DisplayServerAndroid::process_double_tap(Point2 p_pos) {
+void DisplayServerAndroid::process_mouse_event(int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor, float event_horizontal_factor) {
+	int event_buttons_mask = _android_button_mask_to_godot_button_mask(event_android_buttons_mask);
+	switch (event_action) {
+		case AMOTION_EVENT_ACTION_BUTTON_PRESS:
+		case AMOTION_EVENT_ACTION_BUTTON_RELEASE: {
+			Ref<InputEventMouseButton> ev;
+			ev.instance();
+			_set_key_modifier_state(ev);
+			ev->set_position(event_pos);
+			ev->set_global_position(event_pos);
+			ev->set_pressed(event_action == AMOTION_EVENT_ACTION_BUTTON_PRESS);
+			int changed_button_mask = buttons_state ^ event_buttons_mask;
+
+			buttons_state = event_buttons_mask;
+
+			ev->set_button_index(_button_index_from_mask(changed_button_mask));
+			ev->set_button_mask(event_buttons_mask);
+			Input::get_singleton()->accumulate_input_event(ev);
+		} break;
+
+		case AMOTION_EVENT_ACTION_MOVE: {
+			Ref<InputEventMouseMotion> ev;
+			ev.instance();
+			_set_key_modifier_state(ev);
+			ev->set_position(event_pos);
+			ev->set_global_position(event_pos);
+			ev->set_relative(event_pos - hover_prev_pos);
+			ev->set_button_mask(event_buttons_mask);
+			Input::get_singleton()->accumulate_input_event(ev);
+			hover_prev_pos = event_pos;
+		} break;
+		case AMOTION_EVENT_ACTION_SCROLL: {
+			Ref<InputEventMouseButton> ev;
+			ev.instance();
+			ev->set_position(event_pos);
+			ev->set_global_position(event_pos);
+			ev->set_pressed(true);
+			buttons_state = event_buttons_mask;
+			if (event_vertical_factor > 0) {
+				_wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_UP, event_vertical_factor);
+			} else if (event_vertical_factor < 0) {
+				_wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_DOWN, -event_vertical_factor);
+			}
+
+			if (event_horizontal_factor > 0) {
+				_wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_RIGHT, event_horizontal_factor);
+			} else if (event_horizontal_factor < 0) {
+				_wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_LEFT, -event_horizontal_factor);
+			}
+		} break;
+	}
+}
+
+void DisplayServerAndroid::_wheel_button_click(int event_buttons_mask, const Ref<InputEventMouseButton> &ev, int wheel_button, float factor) {
+	Ref<InputEventMouseButton> evd = ev->duplicate();
+	_set_key_modifier_state(evd);
+	evd->set_button_index(wheel_button);
+	evd->set_button_mask(event_buttons_mask ^ (1 << (wheel_button - 1)));
+	evd->set_factor(factor);
+	Input::get_singleton()->accumulate_input_event(evd);
+	Ref<InputEventMouseButton> evdd = evd->duplicate();
+	evdd->set_pressed(false);
+	evdd->set_button_mask(event_buttons_mask);
+	Input::get_singleton()->accumulate_input_event(evdd);
+}
+
+void DisplayServerAndroid::process_double_tap(int event_android_button_mask, Point2 p_pos) {
+	int event_button_mask = _android_button_mask_to_godot_button_mask(event_android_button_mask);
 	Ref<InputEventMouseButton> ev;
 	ev.instance();
 	_set_key_modifier_state(ev);
 	ev->set_position(p_pos);
 	ev->set_global_position(p_pos);
-	ev->set_pressed(false);
+	ev->set_pressed(event_button_mask != 0);
+	ev->set_button_index(_button_index_from_mask(event_button_mask));
+	ev->set_button_mask(event_button_mask);
 	ev->set_doubleclick(true);
-	Input::get_singleton()->parse_input_event(ev);
+	Input::get_singleton()->accumulate_input_event(ev);
+}
+
+int DisplayServerAndroid::_button_index_from_mask(int button_mask) {
+	switch (button_mask) {
+		case BUTTON_MASK_LEFT:
+			return BUTTON_LEFT;
+		case BUTTON_MASK_RIGHT:
+			return BUTTON_RIGHT;
+		case BUTTON_MASK_MIDDLE:
+			return BUTTON_MIDDLE;
+		case BUTTON_MASK_XBUTTON1:
+			return BUTTON_XBUTTON1;
+		case BUTTON_MASK_XBUTTON2:
+			return BUTTON_XBUTTON2;
+		default:
+			return 0;
+	}
 }
 
 void DisplayServerAndroid::process_scroll(Point2 p_pos) {
@@ -679,7 +770,7 @@ void DisplayServerAndroid::process_scroll(Point2 p_pos) {
 	_set_key_modifier_state(ev);
 	ev->set_position(p_pos);
 	ev->set_delta(p_pos - scroll_prev_pos);
-	Input::get_singleton()->parse_input_event(ev);
+	Input::get_singleton()->accumulate_input_event(ev);
 	scroll_prev_pos = p_pos;
 }
 
@@ -698,3 +789,32 @@ void DisplayServerAndroid::process_magnetometer(const Vector3 &p_magnetometer) {
 void DisplayServerAndroid::process_gyroscope(const Vector3 &p_gyroscope) {
 	Input::get_singleton()->set_gyroscope(p_gyroscope);
 }
+
+Point2i DisplayServerAndroid::mouse_get_position() const {
+	return hover_prev_pos;
+}
+
+int DisplayServerAndroid::mouse_get_button_state() const {
+	return buttons_state;
+}
+
+int DisplayServerAndroid::_android_button_mask_to_godot_button_mask(int android_button_mask) {
+	int godot_button_mask = 0;
+	if (android_button_mask & AMOTION_EVENT_BUTTON_PRIMARY) {
+		godot_button_mask |= BUTTON_MASK_LEFT;
+	}
+	if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) {
+		godot_button_mask |= BUTTON_MASK_RIGHT;
+	}
+	if (android_button_mask & AMOTION_EVENT_BUTTON_TERTIARY) {
+		godot_button_mask |= BUTTON_MASK_MIDDLE;
+	}
+	if (android_button_mask & AMOTION_EVENT_BUTTON_BACK) {
+		godot_button_mask |= BUTTON_MASK_XBUTTON1;
+	}
+	if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) {
+		godot_button_mask |= BUTTON_MASK_XBUTTON2;
+	}
+
+	return godot_button_mask;
+}

+ 14 - 2
platform/android/display_server_android.h

@@ -68,6 +68,8 @@ private:
 	bool control_mem = false;
 	bool meta_mem = false;
 
+	int buttons_state;
+
 	bool keep_screen_on;
 
 	Vector<TouchPos> touch;
@@ -91,6 +93,12 @@ private:
 
 	void _set_key_modifier_state(Ref<InputEventWithModifiers> ev);
 
+	static int _button_index_from_mask(int button_mask);
+
+	static int _android_button_mask_to_godot_button_mask(int android_button_mask);
+
+	void _wheel_button_click(int event_buttons_mask, const Ref<InputEventMouseButton> &ev, int wheel_button, float factor);
+
 public:
 	static DisplayServerAndroid *get_singleton();
 
@@ -162,9 +170,10 @@ public:
 	void process_gravity(const Vector3 &p_gravity);
 	void process_magnetometer(const Vector3 &p_magnetometer);
 	void process_gyroscope(const Vector3 &p_gyroscope);
-	void process_touch(int p_what, int p_pointer, const Vector<TouchPos> &p_points);
+	void process_touch(int p_event, int p_pointer, const Vector<TouchPos> &p_points);
 	void process_hover(int p_type, Point2 p_pos);
-	void process_double_tap(Point2 p_pos);
+	void process_mouse_event(int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor = 0, float event_horizontal_factor = 0);
+	void process_double_tap(int event_android_button_mask, Point2 p_pos);
 	void process_scroll(Point2 p_pos);
 	void process_joy_event(JoypadEvent p_event);
 	void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed);
@@ -175,6 +184,9 @@ public:
 
 	void reset_window();
 
+	virtual Point2i mouse_get_position() const;
+	virtual int mouse_get_button_state() const;
+
 	DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
 	~DisplayServerAndroid();
 };

+ 1 - 57
platform/android/java/lib/src/org/godotengine/godot/Godot.java

@@ -70,6 +70,7 @@ import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings.Secure;
 import android.view.Display;
+import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -854,63 +855,6 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
 		}
 	}
 
-	public boolean gotTouchEvent(final MotionEvent event) {
-		final int evcount = event.getPointerCount();
-		if (evcount == 0)
-			return true;
-
-		if (mRenderView != null) {
-			final int[] arr = new int[event.getPointerCount() * 3];
-
-			for (int i = 0; i < event.getPointerCount(); i++) {
-				arr[i * 3 + 0] = (int)event.getPointerId(i);
-				arr[i * 3 + 1] = (int)event.getX(i);
-				arr[i * 3 + 2] = (int)event.getY(i);
-			}
-			final int pointer_idx = event.getPointerId(event.getActionIndex());
-
-			//System.out.printf("gaction: %d\n",event.getAction());
-			final int action = event.getAction() & MotionEvent.ACTION_MASK;
-			mRenderView.queueOnRenderThread(new Runnable() {
-				@Override
-				public void run() {
-					switch (action) {
-						case MotionEvent.ACTION_DOWN: {
-							GodotLib.touch(0, 0, evcount, arr);
-							//System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
-						} break;
-						case MotionEvent.ACTION_MOVE: {
-							GodotLib.touch(1, 0, evcount, arr);
-							/*
-							for(int i=0;i<event.getPointerCount();i++) {
-								System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
-							}
-							*/
-						} break;
-						case MotionEvent.ACTION_POINTER_UP: {
-							GodotLib.touch(4, pointer_idx, evcount, arr);
-							//System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
-						} break;
-						case MotionEvent.ACTION_POINTER_DOWN: {
-							GodotLib.touch(3, pointer_idx, evcount, arr);
-							//System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
-						} break;
-						case MotionEvent.ACTION_CANCEL:
-						case MotionEvent.ACTION_UP: {
-							GodotLib.touch(2, 0, evcount, arr);
-							/*
-							for(int i=0;i<event.getPointerCount();i++) {
-								System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
-							}
-							*/
-						} break;
-					}
-				}
-			});
-		}
-		return true;
-	}
-
 	public boolean onKeyMultiple(final int inKeyCode, int repeatCount, KeyEvent event) {
 		String s = event.getCharacters();
 		if (s == null || s.length() == 0)

+ 1 - 2
platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java

@@ -29,7 +29,6 @@
 /*************************************************************************/
 
 package org.godotengine.godot;
-
 import org.godotengine.godot.input.GodotGestureHandler;
 import org.godotengine.godot.input.GodotInputHandler;
 import org.godotengine.godot.utils.GLUtils;
@@ -127,7 +126,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
 	public boolean onTouchEvent(MotionEvent event) {
 		super.onTouchEvent(event);
 		this.detector.onTouchEvent(event);
-		return godot.gotTouchEvent(event);
+		return inputHandler.onTouchEvent(event);
 	}
 
 	@Override

+ 5 - 3
platform/android/java/lib/src/org/godotengine/godot/GodotLib.java

@@ -94,17 +94,19 @@ public class GodotLib {
 	/**
 	 * Forward touch events from the main thread to the GL thread.
 	 */
-	public static native void touch(int what, int pointer, int howmany, int[] arr);
+	public static native void touch(int inputDevice, int event, int pointer, int pointerCount, float[] positions);
+	public static native void touch(int inputDevice, int event, int pointer, int pointerCount, float[] positions, int buttonsMask);
+	public static native void touch(int inputDevice, int event, int pointer, int pointerCount, float[] positions, int buttonsMask, float verticalFactor, float horizontalFactor);
 
 	/**
 	 * Forward hover events from the main thread to the GL thread.
 	 */
-	public static native void hover(int type, int x, int y);
+	public static native void hover(int type, float x, float y);
 
 	/**
 	 * Forward double_tap events from the main thread to the GL thread.
 	 */
-	public static native void doubletap(int x, int y);
+	public static native void doubleTap(int buttonMask, int x, int y);
 
 	/**
 	 * Forward scroll events from the main thread to the GL thread.

+ 5 - 4
platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java

@@ -38,6 +38,7 @@ import org.godotengine.godot.vulkan.VkSurfaceView;
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.view.GestureDetector;
+import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.SurfaceView;
@@ -100,22 +101,22 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
 	public boolean onTouchEvent(MotionEvent event) {
 		super.onTouchEvent(event);
 		mGestureDetector.onTouchEvent(event);
-		return godot.gotTouchEvent(event);
+		return mInputHandler.onTouchEvent(event);
 	}
 
 	@Override
 	public boolean onKeyUp(final int keyCode, KeyEvent event) {
-		return mInputHandler.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event);
+		return mInputHandler.onKeyUp(keyCode, event);
 	}
 
 	@Override
 	public boolean onKeyDown(final int keyCode, KeyEvent event) {
-		return mInputHandler.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
+		return mInputHandler.onKeyDown(keyCode, event);
 	}
 
 	@Override
 	public boolean onGenericMotionEvent(MotionEvent event) {
-		return mInputHandler.onGenericMotionEvent(event) || super.onGenericMotionEvent(event);
+		return mInputHandler.onGenericMotionEvent(event);
 	}
 
 	@Override

+ 2 - 2
platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java

@@ -33,7 +33,6 @@ package org.godotengine.godot.input;
 import org.godotengine.godot.GodotLib;
 import org.godotengine.godot.GodotRenderView;
 
-import android.util.Log;
 import android.view.GestureDetector;
 import android.view.MotionEvent;
 
@@ -75,10 +74,11 @@ public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener
 		//Log.i("GodotGesture", "onDoubleTap");
 		final int x = Math.round(event.getX());
 		final int y = Math.round(event.getY());
+		final int buttonMask = event.getButtonState();
 		queueEvent(new Runnable() {
 			@Override
 			public void run() {
-				GodotLib.doubletap(x, y);
+				GodotLib.doubleTap(buttonMask, x, y);
 			}
 		});
 		return true;

+ 103 - 2
platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java

@@ -36,6 +36,7 @@ import org.godotengine.godot.GodotLib;
 import org.godotengine.godot.GodotRenderView;
 import org.godotengine.godot.input.InputManagerCompat.InputDeviceListener;
 
+import android.os.Build;
 import android.util.Log;
 import android.view.InputDevice;
 import android.view.InputDevice.MotionRange;
@@ -156,6 +157,53 @@ public class GodotInputHandler implements InputDeviceListener {
 		return true;
 	}
 
+	public boolean onTouchEvent(final MotionEvent event) {
+		// Mouse drag (mouse pressed and move) doesn't fire onGenericMotionEvent so this is needed
+		if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+			if (event.getAction() != MotionEvent.ACTION_MOVE) {
+				// we return true because every time a mouse event is fired, the event is already handled
+				// in onGenericMotionEvent, so by touch event we can say that the event is also handled
+				return true;
+			}
+			return handleMouseEvent(event);
+		}
+
+		final int evcount = event.getPointerCount();
+		if (evcount == 0)
+			return true;
+
+		if (mRenderView != null) {
+			final float[] arr = new float[event.getPointerCount() * 3]; // pointerId1, x1, y1, pointerId2, etc...
+
+			for (int i = 0; i < event.getPointerCount(); i++) {
+				arr[i * 3 + 0] = event.getPointerId(i);
+				arr[i * 3 + 1] = event.getX(i);
+				arr[i * 3 + 2] = event.getY(i);
+			}
+			final int action = event.getActionMasked();
+
+			mRenderView.queueOnRenderThread(new Runnable() {
+				@Override
+				public void run() {
+					switch (action) {
+						case MotionEvent.ACTION_DOWN:
+						case MotionEvent.ACTION_CANCEL:
+						case MotionEvent.ACTION_UP:
+						case MotionEvent.ACTION_MOVE: {
+							GodotLib.touch(event.getSource(), action, 0, evcount, arr);
+						} break;
+						case MotionEvent.ACTION_POINTER_UP:
+						case MotionEvent.ACTION_POINTER_DOWN: {
+							int pointer_idx = event.getPointerId(event.getActionIndex());
+							GodotLib.touch(event.getSource(), action, pointer_idx, evcount, arr);
+						} break;
+					}
+				}
+			});
+		}
+		return true;
+	}
+
 	public boolean onGenericMotionEvent(MotionEvent event) {
 		if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) {
 			final int device_id = findJoystickDevice(event.getDeviceId());
@@ -189,8 +237,8 @@ public class GodotInputHandler implements InputDeviceListener {
 				return true;
 			}
 		} else if ((event.getSource() & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS) {
-			final int x = Math.round(event.getX());
-			final int y = Math.round(event.getY());
+			final float x = event.getX();
+			final float y = event.getY();
 			final int type = event.getAction();
 			queueEvent(new Runnable() {
 				@Override
@@ -199,6 +247,10 @@ public class GodotInputHandler implements InputDeviceListener {
 				}
 			});
 			return true;
+		} else if ((event.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
+			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+				return handleMouseEvent(event);
+			}
 		}
 
 		return false;
@@ -366,4 +418,53 @@ public class GodotInputHandler implements InputDeviceListener {
 
 		return -1;
 	}
+
+	private boolean handleMouseEvent(final MotionEvent event) {
+		switch (event.getActionMasked()) {
+			case MotionEvent.ACTION_HOVER_ENTER:
+			case MotionEvent.ACTION_HOVER_MOVE:
+			case MotionEvent.ACTION_HOVER_EXIT: {
+				final float x = event.getX();
+				final float y = event.getY();
+				final int type = event.getAction();
+				queueEvent(new Runnable() {
+					@Override
+					public void run() {
+						GodotLib.hover(type, x, y);
+					}
+				});
+				return true;
+			}
+			case MotionEvent.ACTION_BUTTON_PRESS:
+			case MotionEvent.ACTION_BUTTON_RELEASE:
+			case MotionEvent.ACTION_MOVE: {
+				final float x = event.getX();
+				final float y = event.getY();
+				final int buttonsMask = event.getButtonState();
+				final int action = event.getAction();
+				queueEvent(new Runnable() {
+					@Override
+					public void run() {
+						GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask);
+					}
+				});
+				return true;
+			}
+			case MotionEvent.ACTION_SCROLL: {
+				final float x = event.getX();
+				final float y = event.getY();
+				final int buttonsMask = event.getButtonState();
+				final int action = event.getAction();
+				final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+				final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
+				queueEvent(new Runnable() {
+					@Override
+					public void run() {
+						GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask, verticalFactor, horizontalFactor);
+					}
+				});
+			}
+		}
+		return false;
+	}
 }

+ 25 - 13
platform/android/java_godot_lib_jni.cpp

@@ -51,6 +51,7 @@
 #include "string_android.h"
 #include "thread_jandroid.h"
 
+#include <android/input.h>
 #include <unistd.h>
 
 #include <android/native_window_jni.h>
@@ -237,40 +238,51 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jcl
 	}
 }
 
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint count, jintArray positions) {
+void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor) {
 	if (step == 0)
 		return;
 
 	Vector<DisplayServerAndroid::TouchPos> points;
-	for (int i = 0; i < count; i++) {
-		jint p[3];
-		env->GetIntArrayRegion(positions, i * 3, 3, p);
+	for (int i = 0; i < pointer_count; i++) {
+		jfloat p[3];
+		env->GetFloatArrayRegion(positions, i * 3, 3, p);
 		DisplayServerAndroid::TouchPos tp;
 		tp.pos = Point2(p[1], p[2]);
-		tp.id = p[0];
+		tp.id = (int)p[0];
 		points.push_back(tp);
 	}
 
-	DisplayServerAndroid::get_singleton()->process_touch(ev, pointer, points);
+	if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) {
+		DisplayServerAndroid::get_singleton()->process_mouse_event(ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor);
+	} else {
+		DisplayServerAndroid::get_singleton()->process_touch(ev, pointer, points);
+	}
+}
+
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3F(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray position) {
+	touch_preprocessing(env, clazz, input_device, ev, pointer, pointer_count, position);
+}
+
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FI(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray position, jint buttons_mask) {
+	touch_preprocessing(env, clazz, input_device, ev, pointer, pointer_count, position, buttons_mask);
+}
 
-	/*
-	if (os_android)
-		os_android->process_touch(ev,pointer,points);
-	*/
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FIFF(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray position, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor) {
+	touch_preprocessing(env, clazz, input_device, ev, pointer, pointer_count, position, buttons_mask, vertical_factor, horizontal_factor);
 }
 
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jint p_x, jint p_y) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y) {
 	if (step == 0)
 		return;
 
 	DisplayServerAndroid::get_singleton()->process_hover(p_type, Point2(p_x, p_y));
 }
 
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubletap(JNIEnv *env, jclass clazz, jint p_x, jint p_y) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y) {
 	if (step == 0)
 		return;
 
-	DisplayServerAndroid::get_singleton()->process_double_tap(Point2(p_x, p_y));
+	DisplayServerAndroid::get_singleton()->process_double_tap(p_button_mask, Point2(p_x, p_y));
 }
 
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y) {

+ 6 - 3
platform/android/java_godot_lib_jni.h

@@ -44,9 +44,12 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, j
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface, jboolean p_32_bits);
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz);
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint count, jintArray positions);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jint p_x, jint p_y);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubletap(JNIEnv *env, jclass clazz, jint p_x, jint p_y);
+void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask = 0, jfloat vertical_factor = 0, jfloat horizontal_factor = 0);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3F(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FI(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FIFF(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y);
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y);
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed);
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed);

+ 1 - 0
platform/android/os_android.cpp

@@ -153,6 +153,7 @@ void OS_Android::main_loop_begin() {
 bool OS_Android::main_loop_iterate() {
 	if (!main_loop)
 		return false;
+	DisplayServerAndroid::get_singleton()->process_events();
 	return Main::iteration();
 }