From f757460ec819aeb2a9d1c21e3ba02b4925f0cac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Sat, 9 Mar 2019 22:03:27 +0100 Subject: [PATCH] Fix fake null-motion mouse event flood This commit also improves a bit the code quality by making the intent of fake events (and themselves) more explicit. Fixes #26460. --- core/os/input_event.cpp | 3 +++ core/os/input_event.h | 3 +++ main/input_default.cpp | 6 +++--- scene/main/viewport.cpp | 31 ++++++++++++++++++------------- scene/main/viewport.h | 2 +- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index 40308f4f7dd..25a5c2afebf 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -33,6 +33,9 @@ #include "core/input_map.h" #include "core/os/keyboard.h" +const int InputEvent::DEVICE_ID_TOUCH_MOUSE = -1; +const int InputEvent::DEVICE_ID_INTERNAL = -2; + void InputEvent::set_device(int p_device) { device = p_device; } diff --git a/core/os/input_event.h b/core/os/input_event.h index 47f9293a7f4..ba01516519e 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -165,6 +165,9 @@ protected: static void _bind_methods(); public: + static const int DEVICE_ID_TOUCH_MOUSE; + static const int DEVICE_ID_INTERNAL; + void set_device(int p_device); int get_device() const; diff --git a/main/input_default.cpp b/main/input_default.cpp index 65910b34bce..e9f1eeff6aa 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -355,7 +355,7 @@ void InputDefault::_parse_input_event_impl(const Ref &p_event, bool Ref button_event; button_event.instance(); - button_event->set_device(-1); + button_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE); button_event->set_position(st->get_position()); button_event->set_global_position(st->get_position()); button_event->set_pressed(st->is_pressed()); @@ -384,7 +384,7 @@ void InputDefault::_parse_input_event_impl(const Ref &p_event, bool Ref motion_event; motion_event.instance(); - motion_event->set_device(-1); + motion_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE); motion_event->set_position(sd->get_position()); motion_event->set_global_position(sd->get_position()); motion_event->set_relative(sd->get_relative()); @@ -602,7 +602,7 @@ void InputDefault::ensure_touch_mouse_raised() { Ref button_event; button_event.instance(); - button_event->set_device(-1); + button_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE); button_event->set_position(mouse_pos); button_event->set_global_position(mouse_pos); button_event->set_pressed(false); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 4f1330ee36e..c1afe30a18e 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -232,16 +232,16 @@ void Viewport::update_worlds() { find_world()->_update(get_tree()->get_frame()); } -void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape, bool p_discard_empty_motion) { +void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) { Transform object_transform = p_object->get_global_transform(); Transform camera_transform = p_camera->get_global_transform(); ObjectID id = p_object->get_instance_id(); - if (p_discard_empty_motion) { - //avoid sending the event unnecessarily if nothing really changed in the context + //avoid sending the fake event unnecessarily if nothing really changed in the context + if (object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) { Ref mm = p_input_event; - if (mm.is_valid() && object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) { + if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) { return; //discarded } } @@ -397,8 +397,6 @@ void Viewport::_notification(int p_what) { PhysicsDirectSpaceState::RayResult result; Physics2DDirectSpaceState *ss2d = Physics2DServer::get_singleton()->space_get_direct_state(find_world_2d()->get_space()); - bool discard_empty_motion = false; - if (physics_has_last_mousepos) { // if no mouse event exists, create a motion one. This is necessary because objects or camera may have moved. // while this extra event is sent, it is checked if both camera and last object and last ID did not move. If nothing changed, the event is discarded to avoid flooding with unnecessary motion events every frame @@ -414,6 +412,7 @@ void Viewport::_notification(int p_what) { if (!has_mouse_event) { Ref mm; mm.instance(); + mm->set_device(InputEvent::DEVICE_ID_INTERNAL); mm->set_global_position(physics_last_mousepos); mm->set_position(physics_last_mousepos); mm->set_alt(physics_last_mouse_state.alt); @@ -422,7 +421,6 @@ void Viewport::_notification(int p_what) { mm->set_metakey(physics_last_mouse_state.meta); mm->set_button_mask(physics_last_mouse_state.mouse_mask); physics_picking_events.push_back(mm); - discard_empty_motion = true; } } @@ -470,7 +468,7 @@ void Viewport::_notification(int p_what) { physics_last_mouse_state.mouse_mask &= ~(1 << (mb->get_button_index() - 1)); // If touch mouse raised, assume we don't know last mouse pos until new events come - if (mb->get_device() == -1) { + if (mb->get_device() == InputEvent::DEVICE_ID_TOUCH_MOUSE) { physics_has_last_mousepos = false; } } @@ -525,18 +523,25 @@ void Viewport::_notification(int p_what) { if (res[i].collider_id && res[i].collider) { CollisionObject2D *co = Object::cast_to(res[i].collider); if (co) { - + bool send_event = true; if (is_mouse) { Map::Element *F = physics_2d_mouseover.find(res[i].collider_id); + if (!F) { F = physics_2d_mouseover.insert(res[i].collider_id, frame); co->_mouse_enter(); } else { F->get() = frame; + // It was already hovered, so don't send the event if it's faked + if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) { + send_event = false; + } } } - co->_input_event(this, ev, res[i].shape); + if (send_event) { + co->_input_event(this, ev, res[i].shape); + } } } } @@ -573,7 +578,7 @@ void Viewport::_notification(int p_what) { CollisionObject *co = Object::cast_to(ObjectDB::get_instance(physics_object_capture)); if (co) { - _collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0, discard_empty_motion); + _collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0); captured = true; if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) { physics_object_capture = 0; @@ -591,7 +596,7 @@ void Viewport::_notification(int p_what) { if (last_id) { if (ObjectDB::get_instance(last_id) && last_object) { //good, exists - _collision_object_input_event(last_object, camera, ev, result.position, result.normal, result.shape, discard_empty_motion); + _collision_object_input_event(last_object, camera, ev, result.position, result.normal, result.shape); if (last_object->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) { physics_object_capture = last_id; } @@ -614,7 +619,7 @@ void Viewport::_notification(int p_what) { CollisionObject *co = Object::cast_to(result.collider); if (co) { - _collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape, discard_empty_motion); + _collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape); last_object = co; last_id = result.collider_id; new_collider = last_id; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 28a52ac4b68..831c2855178 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -221,7 +221,7 @@ private: } physics_last_mouse_state; - void _collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape, bool p_discard_empty_motion); + void _collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape); bool handle_input_locally; bool local_input_handled;