[4.6] EditorApplication.modifierKeysChanged, how to find out which key was pressed

I’m using this bit of code:

[InitializeOnLoad]
public static class VisibilityManager
{

   static VisibilityManager()
   {
     EditorApplication.modifierKeysChanged += KeysChanged;
   }
   
   private static void KeysChanged()
   {
     Debug.Log("abcd");
   }
}

This correctly outputs “abcd” to the console whenever a key is pressed. However, how do I find out which key has been pressed/released? I’ve tried using Input.GetKeyDown, Input.GetKey and Event.current. None of those worked, and Event.current is always null. Is there another way of getting the keys that I don’t know about?

I see this too. Here’s my codelet:

using UnityEngine;
using UnityEditor;
using System.Collections;

[InitializeOnLoad]
public static class VisibilityManager
{
    static int counter;

    static VisibilityManager()
    {
        EditorApplication.modifierKeysChanged += KeysChanged;
    }
  
    private static void KeysChanged()
    {
        counter++;
        Debug.Log(
            counter.ToString () +
            "   Lalt:" + Input.GetKey (KeyCode.LeftAlt) +
            "   Ralt:" + Input.GetKey (KeyCode.RightAlt) +
            "");
    }
}

Both ALTs are always false, running on a Mac.

Bump. A related question, I haven’t been able to detect input in EditorApplication.update either. Is it possible in either function?

Bump.

Try maybe throwing your question over in the Editor and General Help area… they might do better. You can put my code in too, I don’t mind, whatever gets you a good answer. It seems like a bug here…

Not the cleanest as it requires using reflection, but this should get you what you want.

[InitializeOnLoadMethod]
    static void EditorInit ()
    {
        System.Reflection.FieldInfo info = typeof (EditorApplication).GetField ("globalEventHandler", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

        EditorApplication.CallbackFunction value = (EditorApplication.CallbackFunction)info.GetValue (null);

        value += EditorGlobalKeyPress;

        info.SetValue (null, value);
    }


    static void EditorGlobalKeyPress ()
    {
        Debug.Log ("KEY CHANGE " + Event.current.keyCode);
    }

EditorGlobalKeyPress () will be called every time a key is pressed in the editor. During this callback, Event.current will be valid so you can read Event.current.KeyCode and go from there. You do not have to be focused on any particular window/GUI for it to work. This is how Unity internally handle Hot Keys for changing tools (move, rotate, scale etc).

Features like frame selected, duplicate, copy paste etc that have hotkeys are all handled by Unity - Scripting API: MenuItem, and shortcuts like 2D mode, the first person controls in scene view, maximise window (shift + space, i didnt know about this one until the other day, its a good one!) are all handled per EditorWindow in the OnGUI callbacks.

So the callback we’re hooking into for this “global” event is a delegate; EditorApplication.globalEventHandler, but it’s marked as internal so we have to use reflection to get and set it. As far as I can tell (and I’ve looked into it myself a few times now) this is the only way to get a “global editor key press” and it’s bloody internal… Honestly they should just make it public, the implementation is nothing complex, they wouldn’t need to change anything to make it safe to use publicly, you only get KeyUp and KeyDown events during the callback so you can’t mess anything up by trying to draw GUI elements.

Hope this helps anyone who may stumble here needing to know how to do this!

8 Likes

This is awesome! Tried it out and it works like a charm, other than the shift keys which is a little curious.

1 Like

Hi!
I just came across that answer, pretty cool!

I am also wondering why the shift key isn’t working: any idea?

Found the solution for anyone coming here later:

Event.current.shift will be true if shift is pressed while any other key is also pressed: in other words the even does not get called when shift alone is pressed, but you can get the information when any other key is.

2 Likes

Six years later and we still need this, right?

Here is a little error resistent version I use:

/// <summary>
/// Thanks to https://discussions.unity.com/t/599061/6
/// </summary>
[InitializeOnLoad]
public static class GlobalKeyEventHandler
{
    public static event Action<Event> OnKeyEvent;
    public static bool RegistrationSucceeded = false;

    static GlobalKeyEventHandler()
    {
        RegistrationSucceeded = false;
        string msg = "";
        try
        {
            System.Reflection.FieldInfo info = typeof(EditorApplication).GetField(
                "globalEventHandler",
                System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic
                );
            if (info != null)
            {
                EditorApplication.CallbackFunction value = (EditorApplication.CallbackFunction)info.GetValue(null);

                value -= onKeyPressed;
                value += onKeyPressed;

                info.SetValue(null, value);

                RegistrationSucceeded = true;
            }
            else
            {
                msg = "globalEventHandler not found";
            }
        }
        catch (Exception e)
        {
            msg = e.Message;
        }
        finally
        {
            if (!RegistrationSucceeded)
            {
                Debug.LogWarning("GlobalKeyEventHandler: error while registering for globalEventHandler: " + msg);
            }
        }
    }

    private static void onKeyPressed()
    {
        OnKeyEvent?.Invoke(Event.current);
    }
}

Usage:

GlobalKeyEventHandler.OnKeyEvent += handleKeyPressEvents;

if (!GlobalKeyEventHandler.RegistrationSucceeded)
    Debug.Log("Welp, it didn't work.")

public void handleKeyPressEvents(Event current)
{
    // do your stuff
}
6 Likes

Guys, how do you handle composite buttons? I tested this code and when I pressed Ctrl and then another key, the entire event call was interrupted and cannot continue capturing

I found a problem. The shortcut key I set is Ctrl+1, which is occupied by Unity.