Is there a way to prevent input focus loss to a neighbor, or in other words, implement sticky input focus?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Genji
:warning: Old Version Published before Godot 3 was released.

I’m wondering if it’s possible to prevent a Control from losing focus when a direction (“up”, “down”, “left”, or “right”) is pressed.

Problem: I’ve made a console GUI with an InputField and I’d like the KEY_UP and KEY_DOWN event scancodes to replace its text with the next element from the command history, while retaining the input focus. The problem is that pressing a direction transfers the input focus to a neighbor Control node in the scene.

Failed Attempt: I tried forcing focus back on the InputField when a direction was pressed, but the transfer seems to happen after the InputField processes the event. For example, the following code does not maintain the input focus:

func _input(event):
    if ( <KEY_UP is pressed, etc.> ):
        var inp = get_node("InputField")
        inp.grab_focus()

# The neighbor above the "InputField" is still selected afterward

Is it possible to make Controls opt out of being selected due to direction input?

I realize it’s possible to bounce back focus to the InputField by adding a script to its neighbors, but I’d rather not have to do this for each of a given Control’s neighbors every time I’d like to implement a “sticky” input focus behavior.

        
:bust_in_silhouette: Reply From: Genji

Update: I was able to achieve “sticky” input focus by simply setting the Control’s Focus Neighbours to itself. This can be done in a couple of ways:

  • Inspector: Control > Neighbour Focus > … and assign each neighbour to itself
  • or, with gdscript:
    var sticky_node = get_node("StickyInputNode")
    var node_path = sticky_node.get_path()
    sticky_node.set_focus_neighbour(MARGIN_TOP, node_path)
    sticky_node.set_focus_neighbour(MARGIN_BOTTOM, node_path)
    sticky_node.set_focus_neighbour(MARGIN_LEFT, node_path)
    sticky_node.set_focus_neighbour(MARGIN_RIGHT, node_path)

I tried your solution and it’s not working.

guddulol | 2020-09-25 14:41

Which Control type did you use to implement your command line? I’d like to do the same.

I’m also trying to use arrow keys to move through command line history, but I ran into a different problem.

I’m using a LineEdit (inherits from Control). Instead of losing focus, pressing Up moves the cursor to the beginning of the text in the LineEdit, and pressing Down moves it to the end.

I tried shortcut_keys_enabled=false but it has no effect on the behavior of the arrow keys.

For now I’m using Alt+P and Alt+N as my history previous/next.

sustainablelab | 2021-05-08 19:49