godot: "mouse_entered" and "mouse_exited" signals are broken while holding down a mouse button

Godot version: fbb5ca4

OS/device including version: Linux Manjaro

Issue description: The “mouse_entered” and “mouse_exited” signals of control nodes don’t get fired while holding any mouse button down when the click (any mouse button down) started on a control that does not ignore the mouse.

it’s actually because in viewport.cpp in line 1843 to 1850 “over” get’s set to the mouse_focus

if (gui.mouse_focus) {
	over = gui.mouse_focus;
	//recompute focus_inv_xform again here
} else {
	over = _gui_find_control(mpos);
}

and shortly after ( line 1884 to 1893 ) the mouse_exited and mouse_entered signals get not fired because the gui.mouse_focus and the gui.mouse_over are the same

if (over != gui.mouse_over) {

	if (gui.mouse_over)
		gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT);

	_gui_cancel_tooltip();

	if (over)
		over->notification(Control::NOTIFICATION_MOUSE_ENTER);
}

This may be a desired behavior, for a lot of cases. But there are also cases where it is very useful to send those signals. (I’ll update this post soon to show such a case)

Steps to reproduce:

  1. Connect the “mouse_entered” or “mouse_exited” signal of any control node
  2. add another control node, that does not ignore the mouse
  3. start your drag on the control element of point 2 and drag over the control element from point 1
  4. notice that no “mouse_entered” and no “mouse_exited” signals get fired

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 32
  • Comments: 41 (15 by maintainers)

Most upvoted comments

Wasted hours thinking it was my code 😦 v3.3.1 Appreciate the work around but hoping this gets a fix/resolution

One workaround is to toggle the visibility of the clicked Control immediately after being pressed:

func _gui_input(event):
	if event is InputEventMouseButton and event.pressed:
		visible = false
		visible = true

Another hacky workaround:

get_viewport().notification(NOTIFICATION_WM_FOCUS_OUT)

This is probably related to a common UI behavior, which I saw called “mouse capture” on Windows. The idea is to make it easier to implement exclusive dragging logic, by making the control receive mouse events and appear pressed as long as the mouse was pressed inside and remains pressed even if it exits the area of the control. I would not be surprised if this wasnt documented because it’s a subtle behavior happening with many widgets, and has no associated option.

For example, take a scrollbar. Press it, keep the mouse held, and move away from it. It will remain pressed, and will still respond to your movements, while every other control will ignore the mouse. You can reproduce this behavior on non-Godot UIs as well, even sometimes on controls that are not usually draggable (see how some buttons remain pressed when you do this too). Things can differ a bit though, because there are many UI systems around. Sometimes hover effects don’t follow this, while pressed effects do. Godot happens to do both, including enter/exit.

About mouse_entered and mouse_exited: arguably, many widgets probably don’t need mouse capture. But if these were changed to always fire when the mouse goes in and out of the control’s area, regardless of what’s actually happening, then likely a bunch of existing code might need to be fixed somehow (if they rely on it), without being able to rely on them. Or maybe controls can have an option to turn off mouse capture.

Confirmed on my master build too. Note: if you set mouse filter to “ignore” on the parent control the color rectangle signals works as expected.

any movement on this issue?

better yet could we have some access to some sort of function that could just query the screen at a certain position… then people who rely on this unexpected behaviour wouldn’t be affected

as it stands you need to come up with your own BSP/ReportingGrid… check every control over and over each frame etc… surely i cannot be the only person that wants to drag one control to another and detect i’m hovering over a different control… if you reproduce windows you need to drag items to the recycle bin… if you create a drag drop equiping screen you need to drag inventory items to other ones

this limitation is highly impractical for what to me seems a common thing in video game UIs

@MadDogMayCry0 it seems to me that we don’t understand each other. The single line trick you used event.pressed = false, fixes this issue, but creates at least 3 more issues. Add an AcceptDialog in your test project, see that you can’t drag the window anymore. Add a TextEdit and see you can’t click to focus in it anymore. Add you trick to a drad’n drop test, see it breaks too.

If you look at the code further than that piece you refer to all the time, you will probably see that there is a fork from the native functions and of course all the approaches you listed like drag and drop and other nonsense you need to add yourself. This works for about 10 minutes of time. I have not argued or asserted that my approach is universal, I will repeat myself once again - this is a demonstration of solving a problem, a demonstration that allows you to bypass native logic and build your own.

Out of curiosity, does this behavior happen with CollisionObject2D/3D’s mouse_enter/mouse_exit signals too?

Thanks for that, makes sense. If this is the case then I would def upvote an option to switch it off for certain scenarios.

Feel free to open a pull request to do this 🙂

The property should be added to Control and the default behavior should be kept as it is now.

managed to get around this by making my own _input(event:InputEventMouseButton) function. I then had to make sure these two lines were executed as part of the code when the mouse is clicked down:

event.set_pressed(false)
set("mouse_filter", Control.MOUSE_FILTER_STOP)

I then reset the mouse_filter to …_PASS on the mouse release. This only worked with an _input() function, not a _gui_input() function

Still in 3.2.4RC2. Try to click on bottom element. With out releasing it move cursor away from element! New Game Project.zip UPD Works with some fixes from code. https://github.com/godotengine/godot/issues/20881#issuecomment-822360392