Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Toggle lights on/off hotkey

Discussion in 'Immediate Mode GUI (IMGUI)' started by FeastSC2, Jun 24, 2017.

  1. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    978
    I'd like to have a hotkey for toggling the light diplay on/off in the scene view, there's a button in the upper left corner of the Scene View that does this (in between the 2d and sound toggle). It'd also be nice if that button got pressed/unpressed when the hotkey is called. Is there a way to access this button programmatically?

    I could find all lights and turn them off but that wouldn't achieve the same result of course, as that would make a big mess of the scene.
     
  2. shawn

    shawn

    Unity Technologies

    Joined:
    Aug 4, 2007
    Posts:
    552
    Dump this into a file in an Editor folder. :)

    Disclaimer: This requires reflecting and using undocumented and internal API. This API can and will change at anytime without any backwards compatibility support. Use at your own risk.

    Code (CSharp):
    1. using System;
    2. using System.Reflection;
    3. using UnityEngine;
    4. using UnityEditor;
    5.  
    6. [InitializeOnLoad]
    7. public class SceneViewToggler
    8. {
    9.     public const KeyCode kLightToggleKeyCode = KeyCode.L;
    10.     public static SceneViewToggler instance;
    11.  
    12.     static SceneViewToggler()
    13.     {
    14.         instance = new SceneViewToggler ();
    15.     }
    16.  
    17.     public SceneViewToggler()
    18.     {
    19.         FieldInfo globalEventHandlerInfo = typeof(EditorApplication).GetField ("globalEventHandler", BindingFlags.NonPublic | BindingFlags.Static);
    20.         globalEventHandlerInfo.SetValue(this, Delegate.CreateDelegate(globalEventHandlerInfo.FieldType, this, "EventHandler"));
    21.     }
    22.  
    23.     public void EventHandler()
    24.     {
    25.         switch (Event.current.type)
    26.         {
    27.         case EventType.KeyDown:
    28.             if (Event.current.keyCode == kLightToggleKeyCode)
    29.             {
    30.                 SceneView.lastActiveSceneView.m_SceneLighting = !SceneView.lastActiveSceneView.m_SceneLighting;
    31.                 SceneView.lastActiveSceneView.Repaint ();
    32.                 Event.current.Use ();
    33.             }
    34.             break;
    35.         }
    36.     }
    37. }
     
    FeastSC2 likes this.
  3. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    978
    Great, thanks for the help Shawn!
     
  4. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    978
    Hey Shawn, I've been using your code for all sorts of different hotkeys not just for switching lights on/off.
    It worked like a charm in v2017 but it's been causing some trouble since version 2018: at some point, a bug comes along when using Unity and the normal Unity shortcuts stop being called anymore (things like ctrl+z undo, or W for translate tool, ...). Recompiling makes this bug stop but it's really tedious.

    I know that Unity 2019 is just around the corner with a hotkey overhaul but I don't believe it would allow me to call a hotkey continually as long as the key is pressed unlike your code. Do you know how I can implement hotkeys like that in 2018 and 2019 without the bug I mentioned above?

    Been stuck on this for quite some time, hope you got can help me out!
     
  5. shawn

    shawn

    Unity Technologies

    Joined:
    Aug 4, 2007
    Posts:
    552
    So I suspect the problem is that this code is directly setting the value of the EditorApplication.globalEventHandler delegate, which the new Shortcut Manager system is using too (the backend changes for the new shortcut manager have been trickling in throughout 2018.) So if this code happens to run after the Shortcut Manager's code, it'll stomp on Shortcut Manager being able to receive/handle events.

    I believe making the reflection look like this should fix the issue. I haven't tested extensively though.
    Code (CSharp):
    1.     public SceneViewToggler()
    2.     {
    3.         FieldInfo globalEventHandlerInfo = typeof(EditorApplication).GetField ("globalEventHandler", BindingFlags.NonPublic | BindingFlags.Static);
    4.         var newDelegate = Delegate.Combine((Delegate)globalEventHandlerInfo.GetValue(this), Delegate.CreateDelegate(globalEventHandlerInfo.FieldType, this, "EventHandler"));
    5.         globalEventHandlerInfo.SetValue(this, newDelegate);
    6.     }
     
    FeastSC2 likes this.
  6. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    978
    I've been testing it and I believe it's working :) Thanks again, great help!