godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.14k stars 96 forks source link

Add mouse mode to disable mouse events for the whole project #1171

Closed pouleyKetchoupp closed 4 years ago

pouleyKetchoupp commented 4 years ago

Describe the project you are working on: Fighting game

Describe the problem or limitation you are having in your project: I need to disable mouse controls globally, because keyboard and game pads are the only supported controllers.

Input.set_mouse_mode() would be a nice way to achieve that easily, but there's no option to disable mouse events completely. https://docs.godotengine.org/en/stable/classes/class_input.html?#enum-input-mousemode MOUSE_MODE_HIDDEN still registers button clicks and scrolling using mouse wheel.

Describe the feature / enhancement and how it helps to overcome the problem or limitation: This case can be solved by adding a new mouse mode: MOUSE_MODE_DISABLED: hide the mouse cursor and disable all mouse input events

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams: This new mouse mode needs to be implemented in OS specific code, to disable mouse events for the entire engine.

I've already implemented this new mouse mode on Windows, Linux & Mac on my personal branch (based on 3.1), so I can easily make a PR for 3.2 and port it to 4.0 if there's an interest in this feature.

If this enhancement will not be used often, can it be worked around with a few lines of script?: It can't be worked around with a few lines of script afaik. There are possible hacky workarounds, like adding an invisible panel on top of all game UI to catch mouse events and ignore them, but that doesn't handle all cases for the whole project (e.g mouse scrolling would still be registered).

Is there a reason why this should be core and not an add-on in the asset library?: This feature would disable mouse events on the OS level to make sure it affects everything in the engine, so it has to be part of core.

Calinou commented 4 years ago

What are some practical use cases for this? I don't see why disabling mouse input in menus is a desirable feature. Personally, I dislike it when a game forces me to use a keyboard or controller to navigate its menus. It's not the 90s anymore :slightly_smiling_face:

Of course, if you don't implement any mouse inputs in your game, then your game won't be playable using a mouse. This is perfectly understandable though. I'm just worried about adding features that lets developers intentionally decrease the accessibility level of their games.

pouleyKetchoupp commented 4 years ago

As clearly explained, the practical use case is a game with no mouse inputs in menus. It should be a choice based on ux needs rather than engine limitations.

My game is meant for game pads and supports keyboard as an alternative. In order to make ux consistent, I need menus to follow the same rules. The opinion that this functionality would be specific to 90s games (or that you personally wouldn't use it) is not basis for a sound decision.

This is a common issue. When I first asked on Godot Discord if anybody had a solution for this use case, other members have expressed the need for this feature and stated they are currently using hacks that don't work well.

KoBeWi commented 4 years ago

You can just set mouse_filter to Ignore on all Control nodes and it will effectively disable all mouse input. I had similar problem with ScrollBars and almost made a proposal, but setting the filter resolved it.

pouleyKetchoupp commented 4 years ago

@KoBeWi I agree this workaround can be useful in the context of a simple game (or simple UI), but it doesn't scale well for larger projects because:

You can possibly alleviate some of these issues by implementing a global script to manage all of your controls, but that seems way over-complicated, and would end up with an unnecessary extra performance cost.

KoBeWi commented 4 years ago

It's tedious to set by hand for every single control

You need to do it only for parent controls, then all children controls ignore mouse too.

pouleyKetchoupp commented 4 years ago

@KoBeWi Is there anything else to do to make it work? I've just tried in a simple scene with a parent control and a button, and disabling the mouse doesn't seem to work unless I specifically set the button itself to ignore mouse. mouse-disable.zip

KoBeWi commented 4 years ago

Ok, nevermind me. Turns out I actually have a Control over my scene that blocks mouse input. So yeah, you have to use the some workarounds you mentioned.

Still, the "invisible covering rectangle" seems like viable option. You have to put it as the last child in the scene tree and set mouse_filter to "stop". It seems to block everything.

jonbonazza commented 4 years ago

While I agree that allowing your UI be operated keyboard-only is great from a UX standpoint (especially when gaming on laptops), I don't see why you wouldn't also allow mouse as an option for players. If you really did want to though, it's easy enough to just set the root of all of your UI scenes to have Mouse: Ignore set.

KoBeWi commented 4 years ago

it's easy enough to just set the root of all of your UI scenes to have Mouse: Ignore set.

I said few comments further up that it doesn't actually work and you'd have to set ALL controls to ignore.

I don't see why you wouldn't also allow mouse as an option for players

Here's an example from my game: image I use scrollbars as visual element, because they are easy to style and convenient to use instead of custom scrollbars. Mouse input makes no sense in this case (scrolling wouldn't even do anything). So there are cases where disabling mouse input in controls is necessary. (but I still think that Godot already provides enough options to achieve it)

pouleyKetchoupp commented 4 years ago

Still, the "invisible covering rectangle" seems like viable option. You have to put it as the last child in the scene tree and set mouse_filter to "stop". It seems to block everything.

@KoBeWi Yes, it does work in lots of cases, but some events like mouse wheel are still registered, for example in a focused slider or scrollbar. There might be some other corner cases I haven't run into in my project.

So this feature is not strictly necessary, since a combination of a hack and settings on specific controls can do the trick. Although a MOUSE_DISABLED mode would make an easy and well documented option to handle this case, and its implementation takes only a few lines of code for each platform. It's still a nice alternative if more people run into issues with disabling mouse controls in the future.

Jummit commented 4 years ago

Does get_tree().root.propagate_call("set_mouse_filter", Control.MOUSE_FILTER_IGNORE) work?

You'd have to do this as well:

func _ready():
    get_tree().connect("node_added", self, "_on_SceneTree_node_added")

func _on_SceneTree_node_added(node):
    if node is Control:
        node.mouse_filter = Control.MOUSE_FILTER_IGNORE
pouleyKetchoupp commented 4 years ago

@Jummit Yes, that works well!

Just a little fix in your script, the second argument is an array, so the correct line is: get_tree().root.propagate_call("set_mouse_filter", [Control.MOUSE_FILTER_IGNORE])

Now I agree there's an easy script workaround to solve this problem :)

KoBeWi commented 4 years ago

Yes, it does work in lots of cases, but some events like mouse wheel are still registered, for example in a focused slider or scrollbar. There might be some other corner cases I haven't run into in my project.

Weird, because for me it blocks the wheel too. I wonder if I accidentally did something too xd

Now I agree there's an easy script workaround to solve this problem :)

Doesn't this resolve the issue?

pouleyKetchoupp commented 4 years ago

Weird, because for me it blocks the wheel too. I wonder if I accidentally did something too xd

The mouse wheel is used only when focused, so you might not have had this issue but I bumped into it because I use focus for gamepad and keyboard inputs.

Doesn't this resolve the issue?

Yes, closing!