Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Controls intercept hidden mouse input events #31821

Open
Gibbz opened this issue Aug 31, 2019 · 9 comments
Open

Controls intercept hidden mouse input events #31821

Gibbz opened this issue Aug 31, 2019 · 9 comments

Comments

@Gibbz
Copy link

Gibbz commented Aug 31, 2019

Godot version: 3.2

OS/device including version: Linux

Issue description:
I have some free look camera code which uses Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED);

The problem is this would seemingly "lockup" and become unresponsive. I managed to find that the problem was that the Control elements I had on screen would take the input even when though the mouse was not visible!

Steps to reproduce:
Enable Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED); which will force the mouse to the centre of the viewport.
Then display a control on the centre of the screen that doesn't have mouse_filter set to MOUSE_FILTER_IGNORE

I have worked around the problem for now by ensuring I set mouse filter to MOUSE_FILTER_IGNORE when I go enable Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED);

@KoBeWi
Copy link
Member

KoBeWi commented Sep 5, 2020

Can anyone still reproduce this bug in Godot 3.2.3 rc5 or any later release?

If yes, please ensure that an up-to-date Minimal Reproduction Project (MRP) is included in this report (a MRP is a zipped Godot project with the minimal elements necessary to reliably trigger the bug). You can upload ZIP files in an issue comment with a drag and drop.

@bruvzg
Copy link
Member

bruvzg commented Sep 25, 2020

It's still relevant in both 3.2 and master, if there's a control in the center of the window, it will grab input events.

MRP: _test_mcap.zip - click CheckButton in the center to capture mouse, click again and CheckButton will be toggled again.

@akien-mga
Copy link
Member

This is still reproducible in 4.0 RC 1 with @bruvzg's MRP.

It only happens if the mouse is not moved after hiding it. Any mouse motion before clicking again fixes the issue.

CC @Sauermann

@akien-mga akien-mga modified the milestones: 4.0, 4.x Feb 11, 2023
@Sauermann
Copy link
Contributor

Sauermann commented Feb 11, 2023

This is a tricky problem, because during MOUSE_MODE_CAPTURED basically mouse-events shouldn't have a position, but all InputEventMouse have a position.

Not sure, if this is an appropriate solution and I also didn't test it, but I am putting it here as an idea.
Edit: actually it is not a viable solution, as explained in the posts below.

diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 23b7c072be..13edd17955 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2813,7 +2813,9 @@ void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
        }
 
        if (!is_input_handled()) {
-               _gui_input_event(ev);
+               if (Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED) {
+                       _gui_input_event(ev);
+               }
        } else {
                // Cleanup internal GUI state after accepting event during _input().
                _gui_cleanup_internal_state(ev);

@KoBeWi
Copy link
Member

KoBeWi commented Feb 11, 2023

Note that when you outright remove all events, some things will not work, e.g. SpinBox dragging (because it hides mouse and uses motion events).

@Sauermann
Copy link
Contributor

@KoBeWi oh, thanks, I just looked at your PR and my idea above will also cause the same problems.

@KoBeWi
Copy link
Member

KoBeWi commented Feb 11, 2023

Maybe instead of blocking events, we could change the function that determines whether a cursor is within control's rect and make it always return false when mouse is hidden?
Not sure if that fixes the issue though.

@Sauermann
Copy link
Contributor

Other ideas:

  • use NaN as mouse position
  • Create separate events InputEventNoPositionMouseButton, InputEventNoPositionMouseMotion

@Sauermann
Copy link
Contributor

I have tried the following approach:

diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index e6ebaba79e..e713cf46e1 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1610,6 +1610,11 @@ void Viewport::_gui_call_notification(Control *p_control, int p_what) {
 
 Control *Viewport::gui_find_control(const Point2 &p_global) {
        ERR_MAIN_THREAD_GUARD_V(nullptr);
+
+       if (Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) {
+               return nullptr;
+       }
+
        // Handle subwindows.
        _gui_sort_roots();
 
@@ -2974,7 +2979,7 @@ void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
        }
 
        Ref<InputEventMouse> me = ev;
-       if (me.is_valid()) {
+       if (me.is_valid() && Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED) {
                gui.last_mouse_pos = me->get_position();
        }

I am not yet entirely convinced if this is the correct approach. We would likely need an additional state in the form of gui.last_mouse_pos == invalid, but this would make additional tests in a lot of places necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants