godot: Control node "Pass" mousefilter is not passing input

Godot version

3.4.1 rc1

System information

Win64 Nvidea 765M

Issue description

Control node “Pass” mouse filter behaves like “Stop”.

The white Control has mouse_enter, mouse_exit and input_event signals connected. When the mouse hovers over it, it should turn green:

extends ColorRect

func _on_Control_mouse_entered():
	color = Color.green

func _on_Control_mouse_exited():
	color = Color.white

func _on_Control_gui_input(event):
	print(event)

However if there is a Control node above with a “Pass” mouse filter, it will stop the input, instead of passing it through.

https://user-images.githubusercontent.com/47016402/143825790-5d9b7234-adbf-472e-a22a-8c37b9c775e1.mp4

Possibly related: https://github.com/godotengine/godot/issues/55430 https://github.com/godotengine/godot/issues/54529

Steps to reproduce

  1. Add a Control Node and connect input mouse input signals such as mouse_enter, mouse_exit, input_event to a script.
  2. In the script print something or change color when event occurs.
  3. Add another Control node, overlapping the first and set it’s mouse filter to “Pass”
  4. Observe the top Control consuming the input and not passing it on despite being set to “Pass”.

Minimal reproduction project

control_not_passing_input_issue.zip

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 3
  • Comments: 20 (11 by maintainers)

Most upvoted comments

it’s expected

Why would this be expected?

The purpose of the “Pass” mouse filter compared to “Stop” is to handle the input and pass it on. That’s it’s only purpose.

Why would it be expected behaviour to have “Pass” behave like “Stop” in any circumstance? That would not make any sense whatsoever. We already have “Stop” for the stop behaviour!

I’m trying to help out another user on Reddit having the same issue as me in the previous menu example. Here I break it down to it’s essence:

image

A VboxContainer node with two Button nodes as children. When the mouse cursor exits the VboxContainer rect, the Vbox and it’s children should be hidden. Of course the Button mouse_filter default “stop”, stops the mouse event from propagating to the Vbox, so the mouse_exited signal fires. As a result the Vbox is hidden as soon as the user “touches” one of the Buttons.

On first glance the solution seems obvious and simple: just set both Button mouse_filters to “pass”, right?

Well this does not work at all, has the exact same effect as “stop”.

Other configurations I tried which also don’t work:

main2 This is how I previously thought I fixed it: image

main3 Here the first button is totally ignored; as soon as the user touches the second button, again, the mouse_exit signal is fired: image

main4 This just breaks everything, top Button hover is triggered when just entering parent control node rect. All Nodes here have mouse filter set to pass: image

Minimal Project containing these variations:

Godot 3.X: mouse_filter_pass_issue_vbox_and_buttons.zip

Godot 4.0 Alpha11: mouse_filer_pass_issue.zip

I have also spend a few hours today testing any other configuration I could think of. Countless variations, any other property which could only remotely have an influence I tested and run individually. To no avail.

This is especially infuriating to me as I have already solved this, or at least I thought. But whatever I try I can’t replicate that solution anymore.

I can only repeat: mouse filter “pass” feels absolutely broken to me. This is not some obscure usecase either. I think this desperately needs a propper fix.

Control nodes mouse filtering continuously costs me days if not weeks of productive work time. I’ve been working around this as much as I can, but I still get stuck for days at a time. I’m pretty sure I’ve already lost hair and a few years of life-expectancy over this.

“Pass” seems completely broken to me. It does nothing I would expect of it.

For example right now I’m stuck again because it passes mouse_enter and mouse_exit signals on controls that are touching (aka when you typically would not want it to pass) …

https://user-images.githubusercontent.com/47016402/159120229-e1434b43-7d0f-4e41-8a5b-e6265f921680.mp4

Scene Tree: image

Code:

extends Control

func _ready():
	for i in get_tree().get_nodes_in_group("square"):
		i.connect("gui_input", self, "_on_gui_input", [i])
		i.connect("mouse_exited", self, "_on_mouse_exited", [i])

func _on_gui_input(event, emitter_node):
	if Input.is_mouse_button_pressed(BUTTON_LEFT):
		print("left mouse button click registered on: ",emitter_node.name)
		emitter_node.get_node("AnimationPlayer").play("fade")

func _on_mouse_exited(emitter_node):
	print("mouse_exited registered on: ",emitter_node.name)
	emitter_node.get_node("AnimationPlayer").play("fade")

Minimal Project: control_pass_mousefilter_issue.zip

… while it does NOT pass Input events when you really, really do need it to pass, like here: menu_slide_issue

Detailed issue description: Reddit post. Minimal Project: sliding_menu_issue.zip

This is so incredibly frustrating. I’ve lost so much time over this.

The behavior is expected, the problem is that the naming of the mouse filter modes suck and the documentation should be better on what is the premise of how it works. We were debating changing the names for the filters and adding a new skip one that is more akin to what users expect in this situation.

So I encountered a very similar issue and found this bug report. I have a little info I learned about what’s going on that I thought I’d share.

In the first reproduction project, the issue is that you have overlapping siblings. In my experience Control nodes don’t behave nicely when you do that. In this case, the pass filter can only pass the input to an immediate parent control node, so it fails to pass it along to the sibling node that is underneath it. I’ve also learned the pass filter breaks if there is an intermediate non-control parent. So Control->Node->Control will interrupt the pass filter as well. Has to be a stack of control nodes all the way down.

The second reproduction project actually seems like a different issue entirely. It looks like mouse_exited signal is always emitted if the top-most gui changes. Filter settings do not impact this. However the pass filter does influence what receives mouse_entered signals. So evidently if your buttons are set to pass filter, the vbox will receive mouse_exited followed immediately by mouse_entered. So you can workaround your issue by showing the vbox again on it’s own mouse_enter signal (weird, but it works)

As promised, here is a proposal that should shed more detail. https://github.com/godotengine/godot-proposals/issues/3613

Kooha-2023-10-01-01-57-50.webm

image

The Mouse > Filter setting on my Button is set to pass. However, it acts the same as if it as set to stop. I thought I’d add a gif to the issue to at least add some extra context.

This is for the mouse entered and exited signals.

@IceReaper This is more of a “How do I do X in Godot question” than a bug-report, which would be better suited for other Godot User-support community channels. That being said, try ContainerDnD.zip

Joining in. Having a similar problem on a software with a near deadline 😦

Layout is simple:

  • Container element
  • 2 child elements, lets call them B and C

I want to capture MouseDown on B, and set a parent container property (a line2d instance). Then while holding the button, moving the mouse should trigger a mouse move events up to the container. Which should keep drawing a line from original mouse down elements center towards the cursor position. When i get a mouseup, i remove the line. If the mouseup occurs on C, i want to call a function, so i know the user wants to connect B with C. Sadly, even when setting B and C to pass, the GuiInput signal is only received by the node which received the mouse down. Meaning B receives MouseDown, all MouseMove signals, even the ones out of its bounds, and at the end the final MouseUp.

To my understanding, thats actualy what setting the filter to PASS should allow to do properly: Ignore -> no event stop -> always consume pass -> trigger but bubble up (more precise ensure the parent also gets the event, its not the same bubbled up)

When creating my minimal project, I noticed something I overlooked before: The mouse_filter for simple “Control” nodes is set to “stop” by default! 🤨 Since “pass” was the default for all my Containers and TextureRects, it hadn’t occurred to me that it could be “stop” for Control nodes. Is there any good reason for this? Otherwise, I’d suggest to change that. (Once I changed the Control node filter to “pass”, everything worked as expected)