godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
89.05k stars 20.19k forks source link

Games receive joypad input even if the game window is not focused #16832

Open BeayemX opened 6 years ago

BeayemX commented 6 years ago

Godot version:

3925e6a5431424f422273f3522016a9d6a51a876

OS/device including version:

Tested on Linux Mint 18.3 sylvia

Issue description:

When running multiple Godot games all games will receive the joypad input. It does not matter if the games are started from the editor or if they are run from the commandline.

Steps to reproduce:

  1. Run two godot games at the same time and use a joypad.
  2. See that both games will process the joypad input regardless of the window focus
Ranoller commented 6 years ago

This is not a bug. If this was not intended... well... this bug turns into feature. What is the problem to allow user to play with joypad if focus was lost?. If you want not let user to play when focus was lost, maybe you should pause the game on focus lost.

Playing Ori and the blind forest... on focus lost: Pause. Playing Shadows of war... on focus lost: pause, but if you enter in settings and see control type, if you lost focus with keyboard, game pauses, but if you touch the gamepad, game icon changes, so the game, in pause, is registering gamepad input.

So this is a standard behavior i think.

Ranoller commented 6 years ago

Playing Hyper Light Drifter: On focus lost you can play the game. I´m playing now, and writing text... I open godot project, press play and both, my demo and hyper light drifter uses the joypad. This is expected behavior please.

The stanley parable: if you lost focus on windowed you can change options with gamepad.

BeayemX commented 6 years ago

The problem I had was when testing network functionality of my game (locally) and both the server and client were reacting to the joypad input.

I am not quite convinced that this isn't a bug. Because I think it is strange that the game reacts to joypad input but not to keyboard input when not focused.

Ranoller commented 6 years ago

I put some examples of that. All this games on focus lost don´t react to keyboard but react to gamepad.

Ranoller commented 6 years ago

Why do you not filter joypad input on server?

BeayemX commented 6 years ago

I could do that but the same thing applies when testing with multiple local clients. I could ignore input when not focused, but as I stated I think this is not the desired behavior.

I opened this issue because it was mentioned in #15199 by @akien-mga

The fact that multiple instances of a game all receive joypad events regardless of the focus would likely be worth keeping track of in a new issue (if not done already).

If this really is intended behavior this issue can be closed.

Ranoller commented 6 years ago

I don´t know if is intended, but for me is dessired because is the normal behavior of PC games. Some games pauses in focus lost, others allows you to play with gamepad input. See this, i open stanley parable and don´t starve: gamepadfocuslost Same controler in menu... A workaround for your problem can be an option in settings to only allow one window to handle input in preview... but in release i think that this can be a mistake.

vnen commented 6 years ago

I don't think this has any "intention", it's all based on the underlying OS API. Usually the OS only send key and mouse events to the focused window (or to window directly under the cursor, for mouse wheel events). But gamepad events are usually sent to all windows that are listening to it, regardless of focus.

I don't know if we want to override the system behavior. But maybe there could be an easy way for the game dev to decide whether the input should be stopped or not when the window is out of focus.

Ranoller commented 6 years ago

There are some constants defined in MainLoop called:

NOTIFICATION_WM_MOUSE_ENTER = 2

NOTIFICATION_WM_MOUSE_EXIT = 3

NOTIFICATION_WM_FOCUS_IN = 4

NOTIFICATION_WM_FOCUS_OUT = 5

But there in no notify() method in this class to use that, and i can´t find any documented method that allow to do that... so maybe is needed and easy way to notify focus_lost / focus_gain or something like this...

But for the problem of @BeayemX there is a bool method in Scenetree: Scenetree.is_network_server() that returns true if the scenetree is in server mode, so maybe can incorporate that to _input(event) to filter all the inputs if this is true (Not tested, only an idea)

BeayemX commented 6 years ago

The function you are looking for is this

''' func _notification(what): if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST: get_tree().quit()

'''

Ranoller commented 6 years ago

And works!. So with a little tutorial in docs handle focus in window is easy...

vnen commented 6 years ago

You can use notifications to check the focus change, that is not much the problem. The thing is that if you want to disable input, there's no way to do it globally, so you'd have to add a lot of ifs in every place you are using input.

Ranoller commented 6 years ago

I see... i don´t think in that because i handle all input in unique global script, but is true that if using _input(event) in a lot of scripts this can be cumbersome.

Ranoller commented 6 years ago

If you do a singleton with:

var Unfocused = false

func _notification(what):
    if what == MainLoop.NOTIFICATION_WM_FOCUS_OUT: 
        Unfocused = true
    elif what == MainLoop.NOTIFICATION_WM_FOCUS_IN: 
        Unfocused = false

func _input(event):
if Unfocused: get_tree().set_input_as_handled()

It can handle all input in focus lost?... Other idea (But i agree that this should be more intuitive/friendly to do)

Edit2: Works well, but only with _input(event). It stop propagation to all scripts, but if you use Input in _process or _fixed/physics_process that solution doesn´t work.

Zylann commented 6 years ago

It's a common issue that usually happens with game vs GUI in games. When you poll input using "direct global" functions like Input.get_axis, you explicitely bypass any focus barrier (contrary to event based approach) so it's expected. Solution is indeed either use event approach, or use ifs to filter.

KoBeWi commented 4 years ago

I don't think this has any "intention", it's all based on the underlying OS API. Usually the OS only send key and mouse events to the focused window (or to window directly under the cursor, for mouse wheel events). But gamepad events are usually sent to all windows that are listening to it, regardless of focus.

Worth to mention that this is optional. Unfocused/minimized windows can get keyboard input too if they want so (I don't know the exact details, but that's e.g. how keyloggers work :P). So it would make sense if the unfocused window receiving gamepad was optional too, even if it has to be filtered by the engine.

Still valid in 58034f3 btw.

brianwinterpixel commented 2 years ago

This should absolutely be a project setting that can be toggled.

In games that have interactions with real consequences such as making purchases in-game, modifying settings, or joining online matches, handling joypad inputs while the game is running in the background out-of-sight can cause real consequences for players and developers.

Requiring developers to implement their own system for blocking joypad input while the window is out of focus is error prone and hacky.

mischiefaaron commented 2 years ago

This should absolutely be a project setting that can be toggled.

In games that have interactions with real consequences such as making purchases in-game, modifying settings, or joining online matches, handling joypad inputs while the game is running in the background out-of-sight can cause real consequences for players and developers.

Requiring developers to implement their own system for blocking joypad input while the window is out of focus is error prone and hacky.

Having an option is definitely the ideal even just for me alone. I have gamepad visualizer application I'd like it to work out of focus and my games which I'd like to stop taking gamepad input when work out of focus.

atngames commented 2 years ago

I support the "project setting" idea ! I try to develop a game launcher and definitely need to tackle this problem.

Calinou commented 2 years ago

I started working on adding a setting to adjust this behavior: https://github.com/Calinou/godot/tree/input-joypad-ignore-when-unfocused

This also involves readding an equivalent to OS.is_window_focused() in 4.0, which was removed as part of the DisplayServer refactoring.

czlowiekimadlo commented 1 year ago

Any news on this one? Today I noticed, that on Steam Deck, when you open the system menu over the game, it still captures all the input underneath while you try to navigate it, making it a real problem on this platform.

Calinou commented 1 year ago

Note that a script-based workaround is now documented in Controllers, gamepads and joysticks. This change was done by https://github.com/godotengine/godot-docs/pull/7292 and https://github.com/godotengine/godot-docs/pull/7313.

A PR to implement this toggle as a built-in project setting is still welcome (for both 4.x and 3.x), but I don't have time to work on it currently.

Any news on this one? Today I noticed, that on Steam Deck, when you open the system menu over the game, it still captures all the input underneath while you try to navigate it, making it a real problem on this platform.

Don't a lot of non-Godot games run into this issue too? This sounds like something Valve should resolve on their end.

joemicmc commented 1 year ago

Note that a script-based workaround is now documented in Controllers, gamepads and joysticks. This change was done by godotengine/godot-docs#7292 and godotengine/godot-docs#7313.

@Calinou was that just a change to the documentation? The notifications listed in the documentation don't seem to be available in 4.0.2-stable.

Edit: Ah. I wasn't extending a Node, but a RefCounted so had to access constant via Node.NOTIFICATION...

Calinou commented 1 year ago

Edit: Ah. I wasn't extending a Node, but a RefCounted so had to access constant via Node.NOTIFICATION...

The _notification() virtual method is part of Node, so a script that extends RefCounted won't work as the method will never be called.

joemicmc commented 1 year ago

Ah interesting, this page says every Object implements _notification() https://docs.godotengine.org/en/stable/tutorials/best_practices/godot_notifications.html

Calinou commented 1 year ago

Ah interesting, this page says every Object implements _notification() docs.godotengine.org/en/stable/tutorials/best_practices/godot_notifications.html

Nevermind, I read the editor help tree wrong. Every Object indeed calls _notification().

joemicmc commented 1 year ago

One thing I've picked up on with the script-based workaround is that you'll get problems with the built-in UI actions (e.g. ui_left, ui_right etc.). I've added my own UI actions (so they are only processed when the window is focused) and then fire the built-in action using documentation at https://docs.godotengine.org/en/stable/tutorials/inputs/inputevent.html#actions:

var ev = InputEventAction.new()
# Set as ui_down, pressed.
ev.action = "ui_down"
ev.pressed = true
# Feedback.
Input.parse_input_event(ev)
ssokolow commented 11 months ago

Can we also get something in the docs to encourage that the choice be exposed to the user and providing some example code for how to manipulate the setting programmatically?

Being able to use a gamepad to control an unfocused game is such a desired behaviour for me that, if a game pauses on loss of focus and it can't be disabled, I'll force the issue by removing the game's ability detect loss of focus by either running it in Wine in Virtual Desktop mode or running it on my dedicated Win7 gaming machine and then using either my KVM switch and an extra Linux-only mouse or the monitor's internal input selector to merge that into my three-monitor spread as if it were fullscreened on my Linux machine's centre monitor.

Gatada commented 10 months ago

Currently I can enable "No Focus" in advanced Project Settings, so the running game does not steal focus away from the editor—allowing me to playtest with the controller while modifying the script in the editor.

This is a very welcome productivity boost for me.

I would hate if any solution to this "bug" breaks this workflow.

Calinou commented 10 months ago

I would hate if any solution to this "bug" breaks this workflow.

We don't intend to disable unfocused gamepad events by default – the current behavior will remain the default. This behavior is desired for things like Nucleus Coop after all :slightly_smiling_face: