瀏覽代碼

Merge pull request #17196 from RandomShaper/improve-gui-touch

Implement universal translation of touch to mouse (3.1)
Rémi Verschelde 7 年之前
父節點
當前提交
18c28c159d

+ 2 - 1
core/os/input.h

@@ -118,7 +118,8 @@ public:
 
 	void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
 
-	virtual bool is_emulating_touchscreen() const = 0;
+	virtual bool is_emulating_touch_from_mouse() const = 0;
+	virtual bool is_emulating_mouse_from_touch() const = 0;
 
 	virtual CursorShape get_default_cursor_shape() = 0;
 	virtual void set_default_cursor_shape(CursorShape p_shape) = 0;

+ 1 - 1
core/os/os.cpp

@@ -411,7 +411,7 @@ Error OS::set_cwd(const String &p_cwd) {
 bool OS::has_touchscreen_ui_hint() const {
 
 	//return false;
-	return Input::get_singleton() && Input::get_singleton()->is_emulating_touchscreen();
+	return Input::get_singleton() && Input::get_singleton()->is_emulating_touch_from_mouse();
 }
 
 int OS::get_free_static_memory() const {

+ 1 - 1
editor/editor_node.cpp

@@ -4886,7 +4886,7 @@ EditorNode::EditorNode() {
 
 		if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton()) {
 			//only if no touchscreen ui hint, set emulation
-			id->set_emulate_touch(false); //just disable just in case
+			id->set_emulate_touch_from_mouse(false); //just disable just in case
 		}
 		id->set_custom_mouse_cursor(RES());
 	}

+ 106 - 12
main/input_default.cpp

@@ -256,6 +256,11 @@ Vector3 InputDefault::get_gyroscope() const {
 
 void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
 
+	_parse_input_event_impl(p_event, false);
+}
+
+void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
+
 	_THREAD_SAFE_METHOD_
 
 	Ref<InputEventKey> k = p_event;
@@ -279,25 +284,30 @@ void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
 			mouse_button_mask &= ~(1 << (mb->get_button_index() - 1));
 		}
 
-		if (main_loop && emulate_touch && mb->get_button_index() == 1) {
+		Point2 pos = mb->get_global_position();
+		if (mouse_pos != pos) {
+			set_mouse_position(pos);
+		}
+
+		if (main_loop && emulate_touch_from_mouse && !p_is_emulated && mb->get_button_index() == 1) {
 			Ref<InputEventScreenTouch> touch_event;
 			touch_event.instance();
 			touch_event->set_pressed(mb->is_pressed());
 			touch_event->set_position(mb->get_position());
 			main_loop->input_event(touch_event);
 		}
-
-		Point2 pos = mb->get_global_position();
-		if (mouse_pos != pos) {
-			set_mouse_position(pos);
-		}
 	}
 
 	Ref<InputEventMouseMotion> mm = p_event;
 
 	if (mm.is_valid()) {
 
-		if (main_loop && emulate_touch && mm->get_button_mask() & 1) {
+		Point2 pos = mm->get_global_position();
+		if (mouse_pos != pos) {
+			set_mouse_position(pos);
+		}
+
+		if (main_loop && emulate_touch_from_mouse && !p_is_emulated && mm->get_button_mask() & 1) {
 			Ref<InputEventScreenDrag> drag_event;
 			drag_event.instance();
 
@@ -309,6 +319,58 @@ void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
 		}
 	}
 
+	if (emulate_mouse_from_touch) {
+
+		Ref<InputEventScreenTouch> st = p_event;
+
+		if (st.is_valid()) {
+			bool translate = false;
+			if (st->is_pressed()) {
+				if (mouse_from_touch_index == -1) {
+					translate = true;
+					mouse_from_touch_index = st->get_index();
+				}
+			} else {
+				if (st->get_index() == mouse_from_touch_index) {
+					translate = true;
+					mouse_from_touch_index = -1;
+				}
+			}
+
+			if (translate) {
+				Ref<InputEventMouseButton> button_event;
+				button_event.instance();
+
+				button_event->set_position(st->get_position());
+				button_event->set_global_position(st->get_position());
+				button_event->set_pressed(st->is_pressed());
+				button_event->set_button_index(BUTTON_LEFT);
+				if (st->is_pressed()) {
+					button_event->set_button_mask(mouse_button_mask | (1 << BUTTON_LEFT - 1));
+				} else {
+					button_event->set_button_mask(mouse_button_mask & ~(1 << BUTTON_LEFT - 1));
+				}
+
+				_parse_input_event_impl(button_event, true);
+			}
+		}
+
+		Ref<InputEventScreenDrag> sd = p_event;
+
+		if (sd.is_valid() && sd->get_index() == mouse_from_touch_index) {
+			Ref<InputEventMouseMotion> motion_event;
+			motion_event.instance();
+
+			motion_event->set_position(sd->get_position());
+			motion_event->set_global_position(sd->get_position());
+			motion_event->set_relative(sd->get_relative());
+			motion_event->set_speed(sd->get_speed());
+			motion_event->set_button_mask(mouse_button_mask);
+
+			_parse_input_event_impl(motion_event, true);
+		}
+	}
+
 	Ref<InputEventJoypadButton> jb = p_event;
 
 	if (jb.is_valid()) {
@@ -493,14 +555,44 @@ void InputDefault::action_release(const StringName &p_action) {
 	action_state[p_action] = action;
 }
 
-void InputDefault::set_emulate_touch(bool p_emulate) {
+void InputDefault::set_emulate_touch_from_mouse(bool p_emulate) {
+
+	emulate_touch_from_mouse = p_emulate;
+}
+
+bool InputDefault::is_emulating_touch_from_mouse() const {
+
+	return emulate_touch_from_mouse;
+}
+
+// Calling this whenever the game window is focused helps unstucking the "touch mouse"
+// if the OS or its abstraction class hasn't properly reported that touch pointers raised
+void InputDefault::ensure_touch_mouse_raised() {
+
+	if (mouse_from_touch_index != -1) {
+		mouse_from_touch_index = -1;
+
+		Ref<InputEventMouseButton> button_event;
+		button_event.instance();
+
+		button_event->set_position(mouse_pos);
+		button_event->set_global_position(mouse_pos);
+		button_event->set_pressed(false);
+		button_event->set_button_index(BUTTON_LEFT);
+		button_event->set_button_mask(mouse_button_mask & ~(1 << BUTTON_LEFT - 1));
+
+		_parse_input_event_impl(button_event, true);
+	}
+}
+
+void InputDefault::set_emulate_mouse_from_touch(bool p_emulate) {
 
-	emulate_touch = p_emulate;
+	emulate_mouse_from_touch = p_emulate;
 }
 
-bool InputDefault::is_emulating_touchscreen() const {
+bool InputDefault::is_emulating_mouse_from_touch() const {
 
-	return emulate_touch;
+	return emulate_mouse_from_touch;
 }
 
 Input::CursorShape InputDefault::get_default_cursor_shape() {
@@ -537,7 +629,9 @@ void InputDefault::set_mouse_in_window(bool p_in_window) {
 InputDefault::InputDefault() {
 
 	mouse_button_mask = 0;
-	emulate_touch = false;
+	emulate_touch_from_mouse = false;
+	emulate_mouse_from_touch = false;
+	mouse_from_touch_index = -1;
 	main_loop = NULL;
 
 	hat_map_default[HAT_UP].type = TYPE_BUTTON;

+ 12 - 3
main/input_default.h

@@ -60,7 +60,10 @@ class InputDefault : public Input {
 
 	Map<StringName, Action> action_state;
 
-	bool emulate_touch;
+	bool emulate_touch_from_mouse;
+	bool emulate_mouse_from_touch;
+
+	int mouse_from_touch_index;
 
 	struct VibrationInfo {
 		float weak_magnitude;
@@ -176,6 +179,8 @@ private:
 	void _axis_event(int p_device, int p_axis, float p_value);
 	float _handle_deadzone(int p_device, int p_axis, float p_value);
 
+	void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
+
 public:
 	virtual bool is_key_pressed(int p_scancode) const;
 	virtual bool is_mouse_button_pressed(int p_button) const;
@@ -225,8 +230,12 @@ public:
 
 	void iteration(float p_step);
 
-	void set_emulate_touch(bool p_emulate);
-	virtual bool is_emulating_touchscreen() const;
+	void set_emulate_touch_from_mouse(bool p_emulate);
+	virtual bool is_emulating_touch_from_mouse() const;
+	void ensure_touch_mouse_raised();
+
+	void set_emulate_mouse_from_touch(bool p_emulate);
+	virtual bool is_emulating_mouse_from_touch() const;
 
 	virtual CursorShape get_default_cursor_shape();
 	virtual void set_default_cursor_shape(CursorShape p_shape);

+ 9 - 6
main/main.cpp

@@ -1141,13 +1141,16 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 	GLOBAL_DEF("application/config/icon", String());
 	ProjectSettings::get_singleton()->set_custom_property_info("application/config/icon", PropertyInfo(Variant::STRING, "application/config/icon", PROPERTY_HINT_FILE, "*.png,*.webp"));
 
-	if (bool(GLOBAL_DEF("display/window/handheld/emulate_touchscreen", false))) {
-		if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton() && !(editor || project_manager)) {
-			//only if no touchscreen ui hint, set emulation
-			InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
-			if (id)
-				id->set_emulate_touch(true);
+	InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+	if (id) {
+		if (bool(GLOBAL_DEF("input/pointing_devices/emulate_touch_from_mouse", false)) && !(editor || project_manager)) {
+			if (!OS::get_singleton()->has_touchscreen_ui_hint()) {
+				//only if no touchscreen ui hint, set emulation
+				id->set_emulate_touch_from_mouse(true);
+			}
 		}
+
+		id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF("input/pointing_devices/emulate_mouse_from_touch", true)));
 	}
 
 	MAIN_PRINT("Main: Load Remaps");

+ 0 - 49
platform/android/os_android.cpp

@@ -330,17 +330,6 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos>
 
 			if (touch.size()) {
 				//end all if exist
-				{
-					Ref<InputEventMouseButton> ev;
-					ev.instance();
-					ev->set_button_index(BUTTON_LEFT);
-					ev->set_button_mask(BUTTON_MASK_LEFT);
-					ev->set_pressed(false);
-					ev->set_position(touch[0].pos);
-					ev->set_global_position(touch[0].pos);
-					input->parse_input_event(ev);
-				}
-
 				for (int i = 0; i < touch.size(); i++) {
 
 					Ref<InputEventScreenTouch> ev;
@@ -358,21 +347,6 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos>
 				touch[i].pos = p_points[i].pos;
 			}
 
-			{
-				//send mouse
-				Ref<InputEventMouseButton> ev;
-				ev.instance();
-				// ev.type = Ref<InputEvent>::MOUSE_BUTTON;
-				ev->set_button_index(BUTTON_LEFT);
-				ev->set_button_mask(BUTTON_MASK_LEFT);
-				ev->set_pressed(true);
-				ev->set_position(touch[0].pos);
-				ev->set_global_position(touch[0].pos);
-				input->set_mouse_position(Point2(touch[0].pos.x, touch[0].pos.y));
-				last_mouse = touch[0].pos;
-				input->parse_input_event(ev);
-			}
-
 			//send touch
 			for (int i = 0; i < touch.size(); i++) {
 
@@ -387,19 +361,6 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos>
 		} break;
 		case 1: { //motion
 
-			if (p_points.size()) {
-				//send mouse, should look for point 0?
-				Ref<InputEventMouseMotion> ev;
-				ev.instance();
-				ev->set_button_mask(BUTTON_MASK_LEFT);
-				ev->set_position(p_points[0].pos);
-				input->set_mouse_position(Point2(ev->get_position().x, ev->get_position().y));
-				ev->set_speed(input->get_last_mouse_speed());
-				ev->set_relative(p_points[0].pos - last_mouse);
-				last_mouse = p_points[0].pos;
-				input->parse_input_event(ev);
-			}
-
 			ERR_FAIL_COND(touch.size() != p_points.size());
 
 			for (int i = 0; i < touch.size(); i++) {
@@ -432,16 +393,6 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos>
 
 			if (touch.size()) {
 				//end all if exist
-				Ref<InputEventMouseButton> ev;
-				ev.instance();
-				ev->set_button_index(BUTTON_LEFT);
-				ev->set_button_mask(BUTTON_MASK_LEFT);
-				ev->set_pressed(false);
-				ev->set_position(touch[0].pos);
-				ev->set_global_position(touch[0].pos);
-				input->set_mouse_position(Point2(touch[0].pos.x, touch[0].pos.y));
-				input->parse_input_event(ev);
-
 				for (int i = 0; i < touch.size(); i++) {
 
 					Ref<InputEventScreenTouch> ev;

+ 0 - 1
platform/android/os_android.h

@@ -93,7 +93,6 @@ public:
 private:
 	Vector<TouchPos> touch;
 
-	Point2 last_mouse;
 	GFXInitFunc gfx_init_func;
 	void *gfx_init_ud;
 

+ 4 - 5
platform/iphone/gl_view.mm

@@ -497,7 +497,7 @@ static void clear_touches() {
 			int tid = get_touch_id(touch);
 			ERR_FAIL_COND(tid == -1);
 			CGPoint touchPoint = [touch locationInView:self];
-			OSIPhone::get_singleton()->mouse_button(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1, tid == 0);
+			OSIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1);
 		};
 	};
 }
@@ -514,10 +514,9 @@ static void clear_touches() {
 				continue;
 			int tid = get_touch_id(touch);
 			ERR_FAIL_COND(tid == -1);
-			int first = get_first_id(touch);
 			CGPoint touchPoint = [touch locationInView:self];
 			CGPoint prev_point = [touch previousLocationInView:self];
-			OSIPhone::get_singleton()->mouse_move(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, first == tid);
+			OSIPhone::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor);
 		};
 	};
 }
@@ -533,9 +532,9 @@ static void clear_touches() {
 				continue;
 			int tid = get_touch_id(touch);
 			ERR_FAIL_COND(tid == -1);
-			int rem = remove_touch(touch);
+			remove_touch(touch);
 			CGPoint touchPoint = [touch locationInView:self];
-			OSIPhone::get_singleton()->mouse_button(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false, rem == 0);
+			OSIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false);
 		};
 	};
 }

+ 6 - 39
platform/iphone/os_iphone.cpp

@@ -190,7 +190,7 @@ void OSIPhone::key(uint32_t p_key, bool p_pressed) {
 	queue_event(ev);
 };
 
-void OSIPhone::mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick, bool p_use_as_mouse) {
+void OSIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick) {
 
 	if (!GLOBAL_DEF("debug/disable_touch", false)) {
 		Ref<InputEventScreenTouch> ev;
@@ -202,28 +202,10 @@ void OSIPhone::mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_
 		queue_event(ev);
 	};
 
-	mouse_list.pressed[p_idx] = p_pressed;
-
-	if (p_use_as_mouse) {
-
-		Ref<InputEventMouseButton> ev;
-		ev.instance();
-
-		ev->set_position(Vector2(p_x, p_y));
-		ev->set_global_position(Vector2(p_x, p_y));
-
-		//mouse_list.pressed[p_idx] = p_pressed;
-
-		input->set_mouse_position(ev->get_position());
-		ev->set_button_index(BUTTON_LEFT);
-		ev->set_doubleclick(p_doubleclick);
-		ev->set_pressed(p_pressed);
-
-		queue_event(ev);
-	};
+	touch_list.pressed[p_idx] = p_pressed;
 };
 
-void OSIPhone::mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, bool p_use_as_mouse) {
+void OSIPhone::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) {
 
 	if (!GLOBAL_DEF("debug/disable_touch", false)) {
 
@@ -234,21 +216,6 @@ void OSIPhone::mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_
 		ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y));
 		queue_event(ev);
 	};
-
-	if (p_use_as_mouse) {
-		Ref<InputEventMouseMotion> ev;
-		ev.instance();
-
-		ev->set_position(Vector2(p_x, p_y));
-		ev->set_global_position(Vector2(p_x, p_y));
-		ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y));
-
-		input->set_mouse_position(ev->get_position());
-		ev->set_speed(input->get_last_mouse_speed());
-		ev->set_button_mask(BUTTON_LEFT); // pressed
-
-		queue_event(ev);
-	};
 };
 
 void OSIPhone::queue_event(const Ref<InputEvent> &p_event) {
@@ -262,10 +229,10 @@ void OSIPhone::touches_cancelled() {
 
 	for (int i = 0; i < MAX_MOUSE_COUNT; i++) {
 
-		if (mouse_list.pressed[i]) {
+		if (touch_list.pressed[i]) {
 
 			// send a mouse_up outside the screen
-			mouse_button(i, -1, -1, false, false, false);
+			touch_press(i, -1, -1, false, false);
 		};
 	};
 };
@@ -376,7 +343,7 @@ Point2 OSIPhone::get_mouse_position() const {
 
 int OSIPhone::get_mouse_button_state() const {
 
-	return mouse_list.pressed[0];
+	return 0;
 };
 
 void OSIPhone::set_window_title(const String &p_title){};

+ 3 - 3
platform/iphone/os_iphone.h

@@ -106,7 +106,7 @@ private:
 		};
 	};
 
-	MouseList mouse_list;
+	MouseList touch_list;
 
 	Vector3 last_accel;
 
@@ -127,8 +127,8 @@ public:
 
 	uint8_t get_orientations() const;
 
-	void mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick, bool p_use_as_mouse);
-	void mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, bool p_use_as_mouse);
+	void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick);
+	void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y);
 	void touches_cancelled();
 	void key(uint32_t p_key, bool p_pressed);
 	void set_virtual_keyboard_height(int p_height);

+ 0 - 35
platform/javascript/os_javascript.cpp

@@ -285,23 +285,6 @@ static EM_BOOL _touchpress_callback(int event_type, const EmscriptenTouchEvent *
 
 		_input->parse_input_event(ev);
 	}
-
-	if (touch_event->touches[lowest_id_index].isChanged) {
-
-		Ref<InputEventMouseButton> ev_mouse;
-		ev_mouse.instance();
-		ev_mouse->set_button_mask(_input->get_mouse_button_mask());
-		dom2godot_mod(touch_event, ev_mouse);
-
-		const EmscriptenTouchPoint &first_touch = touch_event->touches[lowest_id_index];
-		ev_mouse->set_position(Point2(first_touch.canvasX, first_touch.canvasY));
-		ev_mouse->set_global_position(ev_mouse->get_position());
-
-		ev_mouse->set_button_index(BUTTON_LEFT);
-		ev_mouse->set_pressed(event_type == EMSCRIPTEN_EVENT_TOUCHSTART);
-
-		_input->parse_input_event(ev_mouse);
-	}
 	return true;
 }
 
@@ -327,24 +310,6 @@ static EM_BOOL _touchmove_callback(int event_type, const EmscriptenTouchEvent *t
 
 		_input->parse_input_event(ev);
 	}
-
-	if (touch_event->touches[lowest_id_index].isChanged) {
-
-		Ref<InputEventMouseMotion> ev_mouse;
-		ev_mouse.instance();
-		dom2godot_mod(touch_event, ev_mouse);
-		ev_mouse->set_button_mask(_input->get_mouse_button_mask());
-
-		const EmscriptenTouchPoint &first_touch = touch_event->touches[lowest_id_index];
-		ev_mouse->set_position(Point2(first_touch.canvasX, first_touch.canvasY));
-		ev_mouse->set_global_position(ev_mouse->get_position());
-
-		ev_mouse->set_relative(ev_mouse->get_position() - _input->get_mouse_position());
-		_input->set_mouse_position(ev_mouse->get_position());
-		ev_mouse->set_speed(_input->get_last_mouse_speed());
-
-		_input->parse_input_event(ev_mouse);
-	}
 	return true;
 }
 

+ 38 - 45
platform/uwp/app.cpp

@@ -85,8 +85,7 @@ App::App() :
 		mWindowHeight(0),
 		mEglDisplay(EGL_NO_DISPLAY),
 		mEglContext(EGL_NO_CONTEXT),
-		mEglSurface(EGL_NO_SURFACE),
-		number_of_contacts(0) {
+		mEglSurface(EGL_NO_SURFACE) {
 }
 
 // The first method called when the IFrameworkView is being created.
@@ -271,48 +270,44 @@ void App::pointer_event(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Cor
 		last_touch_y[screen_touch->get_index()] = pos.Y;
 
 		os->input_event(screen_touch);
-		if (number_of_contacts > 1)
-			return;
+	} else {
 
-	}; // fallthrought of sorts
-
-	Ref<InputEventMouseButton> mouse_button;
-	mouse_button.instance();
-	mouse_button->set_device(0);
-	mouse_button->set_pressed(p_pressed);
-	mouse_button->set_button_index(but);
-	mouse_button->set_position(Vector2(pos.X, pos.Y));
-	mouse_button->set_global_position(Vector2(pos.X, pos.Y));
-
-	if (p_is_wheel) {
-		if (point->Properties->MouseWheelDelta > 0) {
-			mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_UP);
-		} else if (point->Properties->MouseWheelDelta < 0) {
-			mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_LEFT : BUTTON_WHEEL_DOWN);
+		Ref<InputEventMouseButton> mouse_button;
+		mouse_button.instance();
+		mouse_button->set_device(0);
+		mouse_button->set_pressed(p_pressed);
+		mouse_button->set_button_index(but);
+		mouse_button->set_position(Vector2(pos.X, pos.Y));
+		mouse_button->set_global_position(Vector2(pos.X, pos.Y));
+
+		if (p_is_wheel) {
+			if (point->Properties->MouseWheelDelta > 0) {
+				mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_UP);
+			} else if (point->Properties->MouseWheelDelta < 0) {
+				mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_LEFT : BUTTON_WHEEL_DOWN);
+			}
 		}
-	}
 
-	last_touch_x[31] = pos.X;
-	last_touch_y[31] = pos.Y;
+		last_touch_x[31] = pos.X;
+		last_touch_y[31] = pos.Y;
 
-	os->input_event(mouse_button);
-
-	if (p_is_wheel) {
-		// Send release for mouse wheel
-		mouse_button->set_pressed(false);
 		os->input_event(mouse_button);
+
+		if (p_is_wheel) {
+			// Send release for mouse wheel
+			mouse_button->set_pressed(false);
+			os->input_event(mouse_button);
+		}
 	}
 };
 
 void App::OnPointerPressed(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::PointerEventArgs ^ args) {
 
-	number_of_contacts++;
 	pointer_event(sender, args, true);
 };
 
 void App::OnPointerReleased(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::PointerEventArgs ^ args) {
 
-	number_of_contacts--;
 	pointer_event(sender, args, false);
 };
 
@@ -351,7 +346,7 @@ void App::OnPointerMoved(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Co
 	Windows::UI::Input::PointerPoint ^ point = args->CurrentPoint;
 	Windows::Foundation::Point pos = _get_pixel_position(window, point->Position, os);
 
-	if (point->IsInContact && _is_touch(point)) {
+	if (_is_touch(point)) {
 
 		Ref<InputEventScreenDrag> screen_drag;
 		screen_drag.instance();
@@ -361,25 +356,23 @@ void App::OnPointerMoved(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Co
 		screen_drag->set_relative(Vector2(screen_drag->get_position().x - last_touch_x[screen_drag->get_index()], screen_drag->get_position().y - last_touch_y[screen_drag->get_index()]));
 
 		os->input_event(screen_drag);
-		if (number_of_contacts > 1)
-			return;
-
-	}; // fallthrought of sorts
+	} else {
 
-	// In case the mouse grabbed, MouseMoved will handle this
-	if (os->get_mouse_mode() == OS::MouseMode::MOUSE_MODE_CAPTURED)
-		return;
+		// In case the mouse grabbed, MouseMoved will handle this
+		if (os->get_mouse_mode() == OS::MouseMode::MOUSE_MODE_CAPTURED)
+			return;
 
-	Ref<InputEventMouseMotion> mouse_motion;
-	mouse_motion.instance();
-	mouse_motion->set_device(0);
-	mouse_motion->set_position(Vector2(pos.X, pos.Y));
-	mouse_motion->set_global_position(Vector2(pos.X, pos.Y));
-	mouse_motion->set_relative(Vector2(pos.X - last_touch_x[31], pos.Y - last_touch_y[31]));
+		Ref<InputEventMouseMotion> mouse_motion;
+		mouse_motion.instance();
+		mouse_motion->set_device(0);
+		mouse_motion->set_position(Vector2(pos.X, pos.Y));
+		mouse_motion->set_global_position(Vector2(pos.X, pos.Y));
+		mouse_motion->set_relative(Vector2(pos.X - last_touch_x[31], pos.Y - last_touch_y[31]));
 
-	last_mouse_pos = pos;
+		last_mouse_pos = pos;
 
-	os->input_event(mouse_motion);
+		os->input_event(mouse_motion);
+	}
 }
 
 void App::OnMouseMoved(MouseDevice ^ mouse_device, MouseEventArgs ^ args) {

+ 0 - 1
platform/uwp/app.h

@@ -107,7 +107,6 @@ namespace GodotUWP
 
 		int last_touch_x[32]; // 20 fingers, index 31 reserved for the mouse
 		int last_touch_y[32];
-		int number_of_contacts;
 		Windows::Foundation::Point last_mouse_pos;
 	};
 }

+ 15 - 24
platform/windows/os_windows.cpp

@@ -342,6 +342,14 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 		} break;
 		case WM_MOUSEMOVE: {
 
+			if (input->is_emulating_mouse_from_touch()) {
+				// Universal translation enabled; ignore OS translation
+				LPARAM extra = GetMessageExtraInfo();
+				if (IsPenEvent(extra)) {
+					break;
+				}
+			}
+
 			if (outside) {
 				//mouse enter
 
@@ -367,18 +375,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 			// Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
 			if (!window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED)
 				break;
-			/*
-			LPARAM extra = GetMessageExtraInfo();
-			if (IsPenEvent(extra)) {
-
-				int idx = extra & 0x7f;
-				_drag_event(idx, uMsg, wParam, lParam);
-				if (idx != 0) {
-					return 0;
-				};
-				// fallthrough for mouse event
-			};
-			*/
 
 			Ref<InputEventMouseMotion> mm;
 			mm.instance();
@@ -448,18 +444,13 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 			/*case WM_XBUTTONDOWN:
 		case WM_XBUTTONUP: */ {
 
-				/*
-			LPARAM extra = GetMessageExtraInfo();
-			if (IsPenEvent(extra)) {
-
-				int idx = extra & 0x7f;
-				_touch_event(idx, uMsg, wParam, lParam);
-				if (idx != 0) {
-					return 0;
-				};
-				// fallthrough for mouse event
-			};
-			*/
+				if (input->is_emulating_mouse_from_touch()) {
+					// Universal translation enabled; ignore OS translation
+					LPARAM extra = GetMessageExtraInfo();
+					if (IsPenEvent(extra)) {
+						break;
+					}
+				}
 
 				Ref<InputEventMouseButton> mb;
 				mb.instance();

+ 17 - 0
platform/x11/os_x11.cpp

@@ -1690,6 +1690,11 @@ void OS_X11::process_xevents() {
 							if (touch.state.has(index)) // Defensive
 								break;
 							touch.state[index] = pos;
+							if (touch.state.size() == 1) {
+								// X11 may send a motion event when a touch gesture begins, that would result
+								// in a spurious mouse motion event being sent to Godot; remember it to be able to filter it out
+								touch.mouse_pos_to_filter = pos;
+							}
 							input->parse_input_event(st);
 						} else {
 							if (!touch.state.has(index)) // Defensive
@@ -1896,6 +1901,18 @@ void OS_X11::process_xevents() {
 				// to be able to send relative motion events.
 				Point2i pos(event.xmotion.x, event.xmotion.y);
 
+				// Avoidance of spurious mouse motion (see handling of touch)
+				bool filter = false;
+				// Adding some tolerance to match better Point2i to Vector2
+				if (touch.state.size() && Vector2(pos).distance_squared_to(touch.mouse_pos_to_filter) < 2) {
+					filter = true;
+				}
+				// Invalidate to avoid filtering a possible legitimate similar event coming later
+				touch.mouse_pos_to_filter = Vector2(1e10, 1e10);
+				if (filter) {
+					break;
+				}
+
 				if (mouse_mode == MOUSE_MODE_CAPTURED) {
 
 					if (pos == Point2i(current_videomode.width / 2, current_videomode.height / 2)) {

+ 1 - 0
platform/x11/os_x11.h

@@ -127,6 +127,7 @@ class OS_X11 : public OS_Unix {
 		Vector<int> devices;
 		XIEventMask event_mask;
 		Map<int, Vector2> state;
+		Vector2 mouse_pos_to_filter;
 	} touch;
 #endif
 

+ 8 - 0
scene/main/scene_tree.cpp

@@ -33,6 +33,7 @@
 #include "editor/editor_node.h"
 #include "io/marshalls.h"
 #include "io/resource_loader.h"
+#include "main/input_default.h"
 #include "message_queue.h"
 #include "node.h"
 #include "os/keyboard.h"
@@ -620,6 +621,13 @@ void SceneTree::_notification(int p_notification) {
 		case NOTIFICATION_WM_FOCUS_IN:
 		case NOTIFICATION_WM_FOCUS_OUT: {
 
+			if (p_notification == NOTIFICATION_WM_FOCUS_IN) {
+				InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+				if (id) {
+					id->ensure_touch_mouse_raised();
+				}
+			}
+
 			get_root()->propagate_notification(p_notification);
 		} break;
 		case NOTIFICATION_TRANSLATION_CHANGED: {