Layered nodes and keyboard accessibility

Godot Version



How do I show a pop up node that has focus neighbours set up on it’s child controls in a way that prevents the buttons on the background view from becoming focused if I were to hit the tab key multiple times?

I have a title screen with the following node hierarchy:

Control (TitleScreen)
- VBoxContainer
  - PlayButton
  - OptionsButton
  - QuitButton

Upon pressing the OptionsButton I run the following:

var options_screen = preload("res://scene/ui/options.tscn").instantiate()

Now the options screen has several buttons on it, one of which grabs focus on _ready and defines it’s neighbours so when I hit the tab key the focus jumps as expected to the neighbouring inputs. However once I’ve hit tab enough times the focus goes to an input on the title screen underneath the options node.

Ideally I want to prevent keyboard and mouse events from bubbling up past the options base node.

I see the PopupPanel but this has too many limitations:

  • It can only be positioned center or absolute
  • It closes when clicking outside of the popup

The ConfirmationDialog provides an option to prevent close when clicking outside of the popup but this also has undesirable behaviour:

  • It can only be positioned center or absolute
  • If the exclusive mode is set I can’t close the game window by clicking the x on the native window if I want to exit the game on the options screen

I’ve thought about pausing the game and keeping the popup node unpaused but how will that work when I have multiple layered popups? Or what if I want to keep my game unpaused while the options screen is displayed in-game?

The only other option I can think of that might work is programmatically turning off focus on the layer (node) before opening the popup node and having a transparent base node on the popup that prevents mouse passthrough.

Has anyone figured out any other way to make this work? I care about making sure my game’s UI can be navigated with a keyboard.

Many thanks!

I’ve not been able to reproduce your issue but in any case you can try setting the Control.focus_mode to FOCUS_NONE of the buttons in your title screen.

Something like:

	var buttons = title_screen.find_children("*", "Button", true, false)
	for button:Button in buttons:
		button.focus_mode = Control.FOCUS_NONE

when showing the options screen and:

	var buttons = title_screen.find_children("*", "Button", true, false)
	for button:Button in buttons:
		button.focus_mode = Control.FOCUS_ALL

when hiding it.

1 Like

Thank you, that’s more succinct than what I was attempting and might be the only way to achieve this for now.

Hopefully this helps get across my issue:

Here’s is a project reproducing the issue.

Any other thoughts or do you think this is the only option for now?

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.