Help with GUI scripting

First and foremost, I’d like to say that I absolutely despise Unity’s GUI system. If I start to confuse it with other programming languages’ GUI adaptations, please forgive me, because I highly prefer those over Unity’s (but I don’t have a choice here).

Basically, this is what I’m doing here: I’m making a “developer’s console” akin to that of the Source engine games (think Half-Life 2) for debugging this game after release–seeing as we won’t always have the Unity editor’s output-only debug console to fix problems. Before I can code any commands, functions, etc. for the console, though, there has to be a GUI to work off of.

The current issue is that I need to guarantee the text field consoleEntry gets focus every time the console opens (triggered by the key, which also has a ~ on it if you use a QWERTY keyboard), and when the console window "closes" (also occurring when the user presses once again) the consoleEntry text field loses focus. However, here’s the part I can’t quite explain (surprisingly): The way my code is laid out (being the only way I could think of laying it out), I can’t seem to get the text field to get focus every time.

Also, I read the documentation time and time again, please don’t make this an RTFM topic.

Here’s my current code:

using UnityEngine;
using System.Collections;

public class RedArmConsole : MonoBehaviour {
	
	private Rect consoleWindow;
	private bool consoleShown = false;
	private Vector2 textAreaView = Vector2.zero;
	private string textAreaString = "Operation: Red Arm - Internal Release\nConsole v0.1 / Unity3D Engine v2.6\nReady to initialize.\n";
	private string consoleArea; // the text area for console output.  Not to be confused with consoleEntry.
	private string consoleEntry = "";
	private bool firstAppearance = false;
	
	// initialize the window
	void Start() {
		consoleWindow = new Rect(5, 5, 500, 500);
	}
	
	// register the window
	void OnGUI() {
		if (consoleShown) {
			consoleWindow = GUI.Window (0, consoleWindow, doConsoleWindow, "Developer Console (Press ~ To Close)");
		}
	}
	
	// check to see if the window needs to be shown
	void Update() {
		if (Input.GetKeyDown("`")) {
			if (consoleShown) {
				consoleShown = false;
				consoleEntry = "";
			} else {
				consoleShown = true;
				firstAppearance = true;
			}
		}
	}
	
	// do whatever.
	void doConsoleWindow(int windowID) {
		// just to clarify the "focus" of things
		if( Input.GetMouseButtonDown( 0 )  GUIUtility.hotControl == 0 )
		GUIUtility.keyboardControl = 0; 
		
		// Basically a scrollbar area for the main textarea
		GUILayout.BeginArea(new Rect (5,20,490,450));
		textAreaView = GUILayout.BeginScrollView(textAreaView);
		consoleArea = GUILayout.TextArea(textAreaString);
		GUILayout.EndScrollView();
		GUILayout.EndArea();
		// end the scrollbar area
		
		// process commands from the command prompt
		if (Event.current.type == EventType.KeyDown  Event.current.keyCode == KeyCode.Return) {
			GUI.SetNextControlName("consoleEntry");
			consoleEntry = GUI.TextField(new Rect(9, 473, 485, 20), consoleEntry, 25);
			GUI.FocusControl("consoleEntry");
			processCommand(consoleEntry);
			consoleEntry = "";
		} else {
			GUI.SetNextControlName("consoleEntry");
			consoleEntry = GUI.TextField(new Rect(9, 473, 485, 20), consoleEntry, 25);
			GUI.FocusControl("consoleEntry");
		}
		
		Debug.Log(GUI.GetNameOfFocusedControl());
		
		// call this last
		GUI.DragWindow();
		
		if (firstAppearance) {
			firstAppearance = false;
			GUI.FocusControl("consoleEntry");
		}
	}
	
	// everything globally will have access to this
	public void log(string t) {
		appendToConsole(": " + t);
	}
	
	// this is what actually adds to the text area
	private void appendToConsole(string t) {
		textAreaString += t + "\n";
	}
	
	// this is where the magic happens
	public void processCommand(string c) {
		//appendToConsole(c);
	}
	
}

I really do need help figuring this out, and if anyone can offer a hand, please do.

Regards,
Will

Read The Fucking Manual ? :wink:

I am NOT sure but I think you made a tiny mistake.

         if (consoleShown) {
            consoleShown = false;
            consoleEntry = "";
         } else {
            consoleShown = true;
            firstAppearance = true;
         }

Shouldn’t you move firstAppearance to the top ? :wink:

Edit :

      if (Event.current.type == EventType.KeyDown  Event.current.keyCode == KeyCode.Return) {
         GUI.SetNextControlName("consoleEntry");
         consoleEntry = GUI.TextField(new Rect(9, 473, 485, 20), consoleEntry, 25);
         GUI.FocusControl("consoleEntry");
         processCommand(consoleEntry);
         consoleEntry = "";
      } else {
         GUI.SetNextControlName("consoleEntry");
         consoleEntry = GUI.TextField(new Rect(9, 473, 485, 20), consoleEntry, 25);
         GUI.FocusControl("consoleEntry");
      }

Couldn’t you simplify it to :

	GUI.SetNextControlName("consoleEntry");
	consoleEntry = GUI.TextField(new Rect(9, 473, 485, 20), consoleEntry, 25);
	GUI.FocusControl("consoleEntry");
	if (Event.current.type == EventType.KeyDown  Event.current.keyCode == KeyCode.Return) {
		processCommand(consoleEntry);
		consoleEntry = "";
	}

I applied the changes you specified (the tiny mistake and the simplification of that one part). Still, when I press the ` key to bring up the console, the text field isn’t focused.

using UnityEngine;
using System.Collections;

public class RedArmConsole : MonoBehaviour {
	
	private Rect consoleWindow;
	private bool consoleShown = false;
	private Vector2 textAreaView = Vector2.zero;
	private string textAreaString = "Operation: Red Arm - Internal Release\nConsole v0.1 / Unity3D Engine v2.6\nReady to initialize.\n";
	private string consoleArea; // the text area for console output.  Not to be confused with consoleEntry.
	private string consoleEntry = "";
	private bool firstAppearance = false;
	
	// initialize the window
	void Start() {
		consoleWindow = new Rect(5, 5, 500, 500);
	}
	
	// register the window
	void OnGUI() {
		if (consoleShown) {
			consoleWindow = GUI.Window (0, consoleWindow, doConsoleWindow, "Developer Console (Press ~ To Close)");
		}
	}
	
	// check to see if the window needs to be shown
	void Update() {
		if (Input.GetKeyDown("`")) {
			if (consoleShown) {
				consoleShown = false;
				consoleEntry = "";
				firstAppearance = true;
			} else {
				consoleShown = true;
			}
		}
		
		//Debug.Log(GUI.GetNameOfFocusedControl());
	}
	
	// do whatever.
	void doConsoleWindow(int windowID) {
		// just to clarify the "focus" of things
		if( Input.GetMouseButtonDown( 0 )  GUIUtility.hotControl == 0 )
		GUIUtility.keyboardControl = 0; 
		
		// Basically a scrollbar area for the main textarea
		GUILayout.BeginArea(new Rect (5,20,490,450));
		textAreaView = GUILayout.BeginScrollView(textAreaView);
		consoleArea = GUILayout.TextArea(textAreaString);
		GUILayout.EndScrollView();
		GUILayout.EndArea();
		// end the scrollbar area
		
		// process commands from the command prompt
		GUI.SetNextControlName("consoleEntry");
		consoleEntry = GUI.TextField(new Rect(9, 473, 485, 20), consoleEntry, 25);
		GUI.FocusControl("consoleEntry");
		if (Event.current.type == EventType.KeyDown  Event.current.keyCode == KeyCode.Return) {
			processCommand(consoleEntry);
			consoleEntry = "";
		}
		
		//Debug.Log(GUI.GetNameOfFocusedControl());
		
		// call this last
		GUI.DragWindow();
		
		if (firstAppearance) {
			firstAppearance = false;
			GUI.FocusControl("consoleEntry");
		}
	}
	
	// everything globally will have access to this
	public void log(string t) {
		appendToConsole(": " + t);
	}
	
	// this is what actually adds to the text area
	private void appendToConsole(string t) {
		textAreaString += t + "\n";
	}
	
	// this is where the magic happens
	public void processCommand(string c) {
		//appendToConsole(c);
	}
	
}

Not in my habit (or is it ?), to randomly suggest things but try this :

      if (Input.GetKeyDown("`")) {
         if (consoleShown) {
            consoleShown = false;
            consoleEntry = "";
         } else {
            firstAppearance = true;
            consoleShown = true;
         }

@The OP: I don’t have an answer to your question, but a possible alternative to consider might be forgoing the text field and instead processing keyboard input manually. That way you’d have complete control over text input in the console. (You can find an example of how to process text input from the Input class here.)

I can’t say for sure whether this would solve your problem, but it might at least be worth looking into.

I’m thinking of simply doing a complete rewrite of the code as it is. It’s not that GUI work is difficult, it’s just that Unity’s implementation of it is particularly awful in my opinion.

Just curious, but what do you find so bad about Unity’s GUI system? (If you can elaborate on that, we might be able to offer some suggestions as to how to make it work better for you.)