0 votes

I have two separate Control nodes that function as two separate UI elements (of which the child nodes are a viewport to the 3D worldspace and a TextEdit node, respectively), both of which respond to keyboard inputs, some of which overlap (the arrow keys for now, but later on this will be the case for hotkeys as well).

Currently, both Control nodes react to inputs (the left arrow key will move both the 3D character and the caret in the TextEdit node, for example). I'd like to disable keypress detection on one of them at a time, with the ability to switch between the two with a toggle key. I've experimented with grabfocus() as well as gettree().paused = true and messing with pause modes, but no dice.

Any hints as to how I should go about this? I apologise in advance if I've overlooked something obvious.

asked Aug 14 in Engine by vivavovuve (15 points)

2 Answers

+1 vote
Best answer

There is something like
set_processing( bool )
There are a couple of methods that turn on or off various proceesings in node.
One of them is responsible for managing input. Search documentation.

answered Aug 15 by bad_exception (55 points)
selected 5 days ago by vivavovuve

Thank you! Using setprocessinginput( bool ) worked.
Posting the working code for posterity:

#When this is true, the focus is on the TextInput node (should start out at false):
var focus_input = false

#Path to node with the script that accepts input for player movement:
onready var player_script = $[Path]

#Path to TextEdit node:
onready var textedit = $[Path]

#Toggle between player movement and TextEdit node with "ui_toggle":
func _input(event):
if Input.is_action_pressed("ui_toggle"):
    focus_input = not focus_input
    if focus_input:
        player_script.set_process_input(false)
        textedit.set_process_input(true)
        textedit.grab_focus()
        textedit.set_editable(true)
    elif not focus_input:
        player_script.set_process_input(true)
        textedit.clear()
        textedit.set_editable(false)
        textedit.set_process_input(false)
+1 vote

Hi,

You could try using a variable in an autoload script to keep track of which node you want active, and then set each nodes func _input() to only be active if that global variable says the node is active.

For example (quick pseudo code as on my phone);
If toggle_node is a button such as escape key.
In the autoload script (called Global.gd here);

var active_node = "3d"
func _input(event):
   if Input.is_action_just_pressed("toggle_node")
      if active_node == "3d":
         active_node = "text"
      elif active_node == "text":
         active_node = "3d"

In 3d world node;

func _input(event):
   if Global.active_node == "3d":
      Normal controls for this node
   else:
      pass

In text editor node;

func _input(event):
   if Global.active_node == "text":
      Normal controls for this node
   else:
      pass

That's one way I can think of to control active bodes, but I have little experience with trying to achieve a setup such as yours, mine is mainly used for setting up menus and some UI elements.

Hope this helps.

answered Aug 14 by DamonR (37 points)

Thanks! This solution would work as well (I assume), but the above solution seems cleaner and more flexible in the event that I want to add more elements to toggle between.

Glad you found something that works. There are usually multiple ways to solve something. When I read the above solution I realised that it is what I used to prevent some nodes running code while another is meant to be as well.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.