Search Unity

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

Discussion in 'Scripting' started by ianmccleary, Sep 25, 2015.

  1. ianmccleary

    ianmccleary

    Joined:
    Oct 8, 2012
    Posts:
    31
    I'm using this bit of code:

    Code (csharp):
    1.  
    2. [InitializeOnLoad]
    3. public static class VisibilityManager
    4. {
    5.  
    6.    static VisibilityManager()
    7.    {
    8.      EditorApplication.modifierKeysChanged += KeysChanged;
    9.    }
    10.    
    11.    private static void KeysChanged()
    12.    {
    13.      Debug.Log("abcd");
    14.    }
    15. }
    16.  
    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?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,726
    I see this too. Here's my codelet:

    Code (csharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections;
    4.  
    5. [InitializeOnLoad]
    6. public static class VisibilityManager
    7. {
    8.     static int counter;
    9.  
    10.     static VisibilityManager()
    11.     {
    12.         EditorApplication.modifierKeysChanged += KeysChanged;
    13.     }
    14.  
    15.     private static void KeysChanged()
    16.     {
    17.         counter++;
    18.         Debug.Log(
    19.             counter.ToString () +
    20.             "   Lalt:" + Input.GetKey (KeyCode.LeftAlt) +
    21.             "   Ralt:" + Input.GetKey (KeyCode.RightAlt) +
    22.             "");
    23.     }
    24. }
    Both ALTs are always false, running on a Mac.
     
  3. ianmccleary

    ianmccleary

    Joined:
    Oct 8, 2012
    Posts:
    31
    Bump. A related question, I haven't been able to detect input in EditorApplication.update either. Is it possible in either function?
     
  4. ianmccleary

    ianmccleary

    Joined:
    Oct 8, 2012
    Posts:
    31
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,726
    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...
     
  6. NoUJoe

    NoUJoe

    Joined:
    Mar 7, 2014
    Posts:
    30
    Not the cleanest as it requires using reflection, but this should get you what you want.

    Code (CSharp):
    1. [InitializeOnLoadMethod]
    2.     static void EditorInit ()
    3.     {
    4.         System.Reflection.FieldInfo info = typeof (EditorApplication).GetField ("globalEventHandler", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
    5.  
    6.         EditorApplication.CallbackFunction value = (EditorApplication.CallbackFunction)info.GetValue (null);
    7.  
    8.         value += EditorGlobalKeyPress;
    9.  
    10.         info.SetValue (null, value);
    11.     }
    12.  
    13.  
    14.     static void EditorGlobalKeyPress ()
    15.     {
    16.         Debug.Log ("KEY CHANGE " + Event.current.keyCode);
    17.     }
    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 https://docs.unity3d.com/ScriptReference/MenuItem.html, 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!
     
  7. SarfaraazAlladin

    SarfaraazAlladin

    Joined:
    Dec 20, 2013
    Posts:
    280
    This is awesome! Tried it out and it works like a charm, other than the shift keys which is a little curious.
     
    NoUJoe likes this.
  8. Shrubokrant

    Shrubokrant

    Joined:
    Oct 2, 2016
    Posts:
    80
    Hi!
    I just came across that answer, pretty cool!
    I am also wondering why the shift key isn't working: any idea?
     
  9. Shrubokrant

    Shrubokrant

    Joined:
    Oct 2, 2016
    Posts:
    80
    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.
     
    Vedran_M and SarfaraazAlladin like this.
  10. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Six years later and we still need this, right?

    Here is a little error resistent version I use:
    Code (CSharp):
    1. /// <summary>
    2. /// Thanks to https://forum.unity.com/threads/4-6-editorapplication-modifierkeyschanged-how-to-find-out-which-key-was-pressed.357367/#post-2705846
    3. /// </summary>
    4. [InitializeOnLoad]
    5. public static class GlobalKeyEventHandler
    6. {
    7.     public static event Action<Event> OnKeyEvent;
    8.     public static bool RegistrationSucceeded = false;
    9.  
    10.     static GlobalKeyEventHandler()
    11.     {
    12.         RegistrationSucceeded = false;
    13.         string msg = "";
    14.         try
    15.         {
    16.             System.Reflection.FieldInfo info = typeof(EditorApplication).GetField(
    17.                 "globalEventHandler",
    18.                 System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic
    19.                 );
    20.             if (info != null)
    21.             {
    22.                 EditorApplication.CallbackFunction value = (EditorApplication.CallbackFunction)info.GetValue(null);
    23.  
    24.                 value -= onKeyPressed;
    25.                 value += onKeyPressed;
    26.  
    27.                 info.SetValue(null, value);
    28.  
    29.                 RegistrationSucceeded = true;
    30.             }
    31.             else
    32.             {
    33.                 msg = "globalEventHandler not found";
    34.             }
    35.         }
    36.         catch (Exception e)
    37.         {
    38.             msg = e.Message;
    39.         }
    40.         finally
    41.         {
    42.             if (!RegistrationSucceeded)
    43.             {
    44.                 Debug.LogWarning("GlobalKeyEventHandler: error while registering for globalEventHandler: " + msg);
    45.             }
    46.         }
    47.     }
    48.  
    49.     private static void onKeyPressed()
    50.     {
    51.         OnKeyEvent?.Invoke(Event.current);
    52.     }
    53. }
    Usage:
    Code (CSharp):
    1. GlobalKeyEventHandler.OnKeyEvent += handleKeyPressEvents;
    2.  
    3. if (!GlobalKeyEventHandler.RegistrationSucceeded)
    4.     Debug.Log("Welp, it didn't work.")
    5.  
    6. public void handleKeyPressEvents(Event current)
    7. {
    8.     // do your stuff
    9. }
     
    Last edited: May 31, 2022
  11. lilith_unity25

    lilith_unity25

    Joined:
    Feb 8, 2023
    Posts:
    2
    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
     
  12. lilith_unity25

    lilith_unity25

    Joined:
    Feb 8, 2023
    Posts:
    2
    I found a problem. The shortcut key I set is Ctrl+1, which is occupied by Unity.