【问题标题】:Get currently pressed keys in inspector在检查器中获取当前按下的键
【发布时间】:2020-02-17 15:55:09
【问题描述】:

我目前正在为我的 Unity 项目构建一个简单的快捷方式系统。

目前我正在通过字符串在检查器中插入快捷方式,例如:“Control+Alt+A”。但是每次都写太烦了。

所以我考虑为它创建一个自定义编辑器,文本框将自动填充用户按下的键。不幸的是,我发现获取此信息的唯一方法是使用 OnSceneGUI 函数,但它需要场景窗口具有焦点,如果在 Unity 中定义了快捷方式,它将触发。

总而言之,我如何读取当前按下的键并使用编辑器脚本显示它们¿

编辑:this link 几乎可以满足我的需要,但它只检测到一个键(没有组合),并且根本没有检测到 Shift 键

【问题讨论】:

标签: c# unity3d unity3d-editor


【解决方案1】:

很大程度上取决于您以后如何存储和检查热键,但您可以创建自定义的 EditorWindow 弹出窗口。

首先我会存储我的快捷方式,例如喜欢

[Serializable]
public struct ShortCut
{
    public bool Ctrl;
    public bool Alt;
    public bool Shift;

    public KeyCode Key;

    public ShortCut(KeyCode key, bool ctrl, bool alt, bool shift)
    {
        Key = key;
        Ctrl = ctrl;
        Alt = alt;
        Shift = shift;
    }

    public override string ToString()
    {
        var builder = new StringBuilder();
        if (Ctrl) builder.Append("CTRL + ");
        if (Alt) builder.Append("ALT + ");
        if (Shift) builder.Append("SHIFT + ");

        builder.Append(Key.ToString());

        return builder.ToString();
    }

    public bool IsDown => IsCtrlDown && IsAltDown && IsShiftDown && Input.GetKeyDown(Key);

    private bool IsCtrlDown => !Ctrl || Input.GetKey(KeyCode.RightControl) || Input.GetKey(KeyCode.LeftControl);
    private bool IsAltDown => !Alt || Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt);
    private bool IsShiftDown => !Shift || Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
}

您可以在脚本中等待它,例如

public class ShortCutTester : MonoBehaviour
{
    // This youc an now call via the context menu of the someShortCut field in the Inspector
    [ContextMenuItem("Set Shortcut", nameof(SetSomeShortCut))]
    public ShortCut someShortCut;

    private void SetSomeShortCut()
    {
        ShortKeyDialog.ShowDialog(someShortCut, result =>
        {
            // mark as dirty and provide undo/redo funcztionality
            Undo.RecordObject(this, "Change someShortCut");
            someShortCut = result;
        });
    }

    private void Update()
    {
        if (someShortCut.IsDown)
        {
            Debug.Log("Hello!");
        }
    }

    #if UNITY_EDITOR
    // in order to catch all editor own key events on runtime
    // you will still get the warning "You have to exit playmode in order to save"
    // but at least this makes the Hello print anyway. Couldn't figure out how to catch the key completely before Unity handles it
    private void OnGUI()
    {
        var e = Event.current;
        e.Use();
    }
    #endif
}

并通过弹出对话框进行设置

public class ShortKeyDialog : EditorWindow
{
    private ShortCut keys;
    private ShortCut newKeys;
    private Action<ShortCut> callback;
    private bool changed;

    public static void ShowDialog( ShortCut currentShortcut, Action<ShortCut> onDone)
    {
        var dialog = GetWindow<ShortKeyDialog>();
        dialog.keys = currentShortcut;
        dialog.newKeys = currentShortcut;
        dialog.callback = onDone;
        dialog.minSize = new Vector2(300, 200);
        dialog.position = new Rect(Screen.width / 2f + 150, Screen.height / 2f + 100, 300, 200);
        dialog.ShowModalUtility();
    }

    private void OnGUI()
    {
        //Get pressed keys
        var e = Event.current;
        if (e?.isKey == true)
        {
            switch (e.type)
            {
                case EventType.KeyDown:
                    switch (e.keyCode)
                    {
                        // Here you will need all allowed keycodes
                        case KeyCode.A:
                        case KeyCode.B:
                        case KeyCode.C:
                        case KeyCode.D:
                        case KeyCode.E:
                        case KeyCode.F:
                        case KeyCode.G:
                        case KeyCode.H:
                        case KeyCode.I:
                        case KeyCode.J:
                        case KeyCode.K:
                        case KeyCode.L:
                        case KeyCode.M:
                        case KeyCode.N:
                        case KeyCode.O:
                        case KeyCode.P:
                        case KeyCode.Q:
                        case KeyCode.R:
                        case KeyCode.S:
                        case KeyCode.T:
                        case KeyCode.U:
                        case KeyCode.V:
                        case KeyCode.W:
                        case KeyCode.X:
                        case KeyCode.Y:
                        case KeyCode.Z:
                        case KeyCode.F1:
                        case KeyCode.F2:
                        case KeyCode.F3:
                        case KeyCode.F4:
                        case KeyCode.F5:
                        case KeyCode.F6:
                        case KeyCode.F7:
                        case KeyCode.F8:
                        case KeyCode.F9:
                        case KeyCode.F10:
                        case KeyCode.F11:
                        case KeyCode.F12:
                        case KeyCode.F13:
                        case KeyCode.F14:
                        case KeyCode.F15:
                        case KeyCode.Comma:
                        case KeyCode.Plus:
                        case KeyCode.Minus:
                        case KeyCode.Period:
                            // etc depends on your needs I guess
                            changed = true;
                            newKeys = new ShortCut (e.keyCode, e.control, e.alt, e.shift);

                            // Refresh the EditorWindow
                            Repaint();
                            break;
                    }
                    break;
            }

            // Use all key presses so nothing else handles them 
            // e.g. also not the Unity editor itself like e.g. for CTRL + S
            e.Use();
        }

        EditorGUILayout.LabelField("Current Shortcut");
        EditorGUILayout.HelpBox(keys.ToString(), MessageType.None);

        EditorGUILayout.Space();

        EditorGUILayout.LabelField("Press buttons to assign a new shortcut", EditorStyles.textArea);

        EditorGUILayout.HelpBox(newKeys.ToString(), MessageType.None);

        EditorGUILayout.Space();

        EditorGUILayout.BeginHorizontal();
        {
            if (GUILayout.Button("Cancel"))
            {
                Close();
            }
            EditorGUI.BeginDisabledGroup(!changed);
            {
                if (GUILayout.Button("Save"))
                {
                    callback?.Invoke(newKeys);
                    Close();
                }
            }
            EditorGUI.EndDisabledGroup();
        }
        EditorGUILayout.EndHorizontal();
    }
}

请注意:在智能手机上输入,因此目前没有机会测试和纠正问题,但我希望这个想法变得清晰

回到 PC 后会尽快测试和更新

【讨论】:

  • 效果很好,但我有 2 个问题; 1) 什么是 dialog.ShowModalUtility(),它不能编译。 2)有没有办法取消Unity中的快捷键,因为像Ctrl+S这样的快捷键也和Unity有关
  • 没关系,我已经用我在问题中链接的脚本解决了这些问题。我会尽快更新我的问题以包含正确和完整的代码。非常感谢,您总是给出最好最详细的答案
  • 嘿,我刚刚修正了所有的错别字和东西;)现在再试一次
  • 完美运行,但 dialog.ShowModalUtility() 仍然无法编译。
  • 附注如果我想要快捷方式列表而不仅仅是一个,它还能工作吗?
猜你喜欢
  • 1970-01-01
  • 2022-01-03
  • 2010-11-09
  • 1970-01-01
  • 1970-01-01
  • 2021-07-12
  • 2021-12-20
  • 1970-01-01
相关资源
最近更新 更多