Detecting which GUI.Button/GUILayout.Button was clicked

Is there a way to detect which GUI.Button/GUILayout.Button was clicked outside of its enclosing if statement?

I have a script that runs continuously throughout the game and records any user input. It’s easy enough to catch UI Button events and determine which object was the target but I can’t figure if there’s a way to for GUI.Button.

Short background; we have a tonne of legacy debug code that was written using IMGUI. It’s not feasible to move it to the new UI system, nor do I want to be inserting more debug code into every if (GUI.Button…) statement throughout our codebase.

I was thinking somewhere along the lines of in the recording script having the following code:

 private void OnGUI()
{
       if (Event.current != null && Event.current.type == EventType.MouseDown)
       {
            Debug.LogWarning("clicked: " + Event.current);
               
           // determine whether this mousedown was on a GUI.Button or not logic would go here....
        }
  }

There is, to my knowledge, no built-in way to acquire the label of the currently clicked GUI.Button.

You can use GUIUtility.hotControl to determine that some GUI control was just clicked, but it only returns the id of the control that is being clicked, which probably won’t be of any help in your case.

Btw your example wouldn’t work for detecting GUI.Button click events, because when a GUI.Button is clicked, it uses the event, turning its type to EventType.Used. You can use Event.rawType (undocumented property) to get the original type of an event even after it has been used.

I think that the best solution in your case would be to create custom classes that would replicate the functionality of GUI.Button / GUILayout.Button, while also adding the functionality of keeping track of the name of the clicked button. Then you could just search & replace all your GUI.Button / GUILayout.Button calls in your debug code with the new implementation.

Here is an example of such an implementation:

using System;
using UnityEngine;

public static class NamedGUILayout
{
    public static bool ButtonWasJustClicked
    {
        get;
        private set;
    }

    public static string LastClickedButtonName
    {
        get;
        private set;
    }

    public static bool Button(string label)
    {
        return Button(new GUIContent(label), label);
    }

    public static bool Button(GUIContent label, string controlName)
    {
        if(ButtonWasJustClicked)
        {
            if(string.Equals(LastClickedButtonName, controlName, StringComparison.Ordinal))
            {
                ButtonWasJustClicked = false;
            }
        }

        if(GUILayout.Button(label))
        {
            ButtonWasJustClicked = true;
            LastClickedButtonName = controlName;
            return true;
        }
        return false;
    }

    public static bool TryGetNameOfJustClickedButton(out string name)
    {
        if(ButtonWasJustClicked)
        {
            name = LastClickedButtonName;
            return true;
        }

        name = "";
        return false;
    }
}

And a test script to verify that it works as expected:

using UnityEngine;
using UnityEditor;

public class DetectedClickedGUIButtonTestWindow : EditorWindow
{
    [MenuItem("Window/Detect Clicked GUI Button Test Window")]
    private static void Open()
    {
        GetWindow<DetectedClickedGUIButtonTestWindow>();
    }

    private void OnGUI()
    {
        if(NamedGUILayout.Button("Test 1"))
        {
            Debug.Log("Test 1 clicked");
        }

        if(NamedGUILayout.Button("Test 2"))
        {
            Debug.Log("Test 2 clicked");
        }

        string clickedName;
        if(NamedGUILayout.TryGetNameOfJustClickedButton(out clickedName))
        {
            Debug.Log("Detected clicked button: "+clickedName);
        }
    }
}
1 Like

I thought that might be the case. Thank you very much for the code!

1 Like