Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Author: [email protected]
- // Unlicensed: this code is explicitly placed into the public domain.
- using UnityEngine;
- using UnityEngine.InputSystem;
- using System;
- using System.Collections.Generic;
- using UnityEngine.Events;
- #if UNITY_EDITOR
- using UnityEditor;
- using System.Linq;
- #endif
- public class InputControlBindingBehaviour : MonoBehaviour {
- public InputControlBinding input = new InputControlBinding();
- private void Reset() {
- input.Binding = new List<InputControlBindInfo>{
- new InputControlBindInfo("jump", "<Keyboard>/space", this, DefaultInputListener),
- new InputControlBindInfo("attack", "<Mouse>/leftButton", this, DefaultInputListener)
- };
- }
- private void Start() { input.Init(); input.Enable(); }
- private void OnEnable() => input.Enable();
- private void OnDisable() => input.Disable();
- private void OnDestroy() => input.Destroy();
- public void DefaultInputListener(InputAction.CallbackContext context) {
- Debug.Log(context.action.name + " -> input " + (context.canceled ? "released" : "pressed") + ": " + context.control.ToString());
- }
- }
- [Serializable] public class InputControlBinding {
- public List<InputControlBindInfo> Binding = new List<InputControlBindInfo>();
- [SerializeField] protected List<InputAction> ActionsRuntime;
- public void Init() {
- Disable();
- Destroy();
- ActionsRuntime = new List<InputAction>(Binding.Count);
- for (int i = 0; i < Binding.Count; i++) {
- Debug.Log(Binding[i].name);
- InputAction inputAction = new InputAction(Binding[i].name, InputActionType.Button);
- InputControlBindInfo binding = Binding[i];
- inputAction.AddBinding(binding.key);
- inputAction.started += binding.onPress.Invoke;
- inputAction.canceled += binding.onRelease.Invoke;
- ActionsRuntime.Add(inputAction);
- }
- }
- public void Enable() {
- ActionsRuntime.ForEach(inputAction => inputAction.Enable());
- }
- public void Disable() {
- ActionsRuntime.ForEach(inputAction => inputAction.Disable());
- }
- public void Destroy() {
- for (int i = 0; i < ActionsRuntime.Count; i++) {
- InputAction action = ActionsRuntime[i];
- InputControlBindInfo info = Binding.Find(info => info.name == action.name);
- if (info != null) {
- action.started -= info.onPress.Invoke;
- action.canceled -= info.onRelease.Invoke;
- }
- }
- }
- }
- [Serializable] public class InputControlBindInfo {
- [Serializable] public class UnityEvent_CallbackContext : UnityEvent<InputAction.CallbackContext> { }
- public string name;
- [InputControlPath] public string key;
- public UnityEvent_CallbackContext onPress = new UnityEvent_CallbackContext();
- public UnityEvent_CallbackContext onRelease = new UnityEvent_CallbackContext();
- public InputControlBindInfo(string name, string key, UnityEngine.Object target, Action<InputAction.CallbackContext> action) {
- this.name = name; this.key = key;
- #if UNITY_EDITOR
- var unityAction = (UnityAction<InputAction.CallbackContext>)Delegate.CreateDelegate(
- typeof(UnityAction<InputAction.CallbackContext>), target, action.Method);
- UnityEditor.Events.UnityEventTools.AddPersistentListener(onPress, unityAction);
- #else
- onPress.AddListener(new UnityAction<InputAction.CallbackContext>(action));
- #endif
- }
- }
- public class InputControlPathAttribute : PropertyAttribute {
- public bool includeKeyboard = true, includeMouse = true, includeGamepad = true;
- public InputControlPathAttribute(bool keyboard = true, bool mouse = true, bool gamepad = true) {
- includeKeyboard = keyboard; includeMouse = mouse; includeGamepad = gamepad;
- }
- }
- #if UNITY_EDITOR
- [CustomPropertyDrawer(typeof(InputControlBindInfo))]
- public class InputBindInfoDrawer : PropertyDrawer {
- public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
- EditorGUI.BeginProperty(position, label, property);
- var nameProperty = property.FindPropertyRelative(nameof(InputControlBindInfo.name));
- var keyProperty = property.FindPropertyRelative(nameof(InputControlBindInfo.key));
- var onPressProperty = property.FindPropertyRelative(nameof(InputControlBindInfo.onPress));
- var onReleaseProperty = property.FindPropertyRelative(nameof(InputControlBindInfo.onRelease));
- var firstLineRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
- var nameRect = new Rect(firstLineRect.x, firstLineRect.y, firstLineRect.width * 0.4f, firstLineRect.height);
- var keyRect = new Rect(firstLineRect.x + firstLineRect.width * 0.4f + 5f, firstLineRect.y, firstLineRect.width * 0.6f - 5f, firstLineRect.height);
- EditorGUI.PropertyField(nameRect, nameProperty, GUIContent.none);
- EditorGUI.PropertyField(keyRect, keyProperty, GUIContent.none);
- var onPressRect = new Rect(
- position.x,
- position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing,
- position.width,
- EditorGUI.GetPropertyHeight(onPressProperty, true)
- );
- EditorGUI.PropertyField(onPressRect, onPressProperty, true);
- var onReleaseRect = new Rect(
- position.x,
- position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing + EditorGUI.GetPropertyHeight(onPressProperty, true),
- position.width,
- EditorGUI.GetPropertyHeight(onReleaseProperty, true)
- );
- EditorGUI.PropertyField(onReleaseRect, onReleaseProperty, true);
- EditorGUI.EndProperty();
- }
- public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
- var onPressProperty = property.FindPropertyRelative(nameof(InputControlBindInfo.onPress));
- var onReleaseProperty = property.FindPropertyRelative(nameof(InputControlBindInfo.onRelease));
- return EditorGUIUtility.singleLineHeight +
- EditorGUIUtility.standardVerticalSpacing +
- EditorGUI.GetPropertyHeight(onPressProperty, true) +
- EditorGUI.GetPropertyHeight(onReleaseProperty, true);
- }
- }
- [CustomPropertyDrawer(typeof(InputControlPathAttribute))]
- public class InputControlPathDrawer : PropertyDrawer {
- private static Dictionary<string, string> allControlPaths;
- private static Dictionary<string, string> keyboardPaths;
- private static Dictionary<string, string> mousePaths;
- private static Dictionary<string, string> gamepadPaths;
- static InputControlPathDrawer() {
- RefreshControlPaths();
- }
- private static void RefreshControlPaths() {
- allControlPaths = new Dictionary<string, string>();
- keyboardPaths = new Dictionary<string, string>();
- mousePaths = new Dictionary<string, string>();
- gamepadPaths = new Dictionary<string, string>();
- try {
- var keyboardLayout = InputSystem.LoadLayout("Keyboard");
- foreach (var control in keyboardLayout.controls) {
- var path = $"<Keyboard>/{control.name}";
- var displayName = $"Keyboard: {control.displayName ?? control.name}";
- keyboardPaths[path] = displayName;
- allControlPaths[path] = displayName;
- }
- } catch {
- var commonKeysFallbackIfLoadingFails = new[] {
- "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
- "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
- "1", "2", "3", "4", "5", "6", "7", "8", "9", "0",
- "space", "enter", "escape", "tab", "shift", "ctrl", "alt",
- "leftArrow", "rightArrow", "upArrow", "downArrow"
- };
- foreach (var key in commonKeysFallbackIfLoadingFails) {
- var path = $"<Keyboard>/{key}";
- var displayName = $"Keyboard: {key}";
- keyboardPaths[path] = displayName;
- allControlPaths[path] = displayName;
- }
- }
- var mouseControls = new Dictionary<string, string> {
- { "<Mouse>/leftButton", "Mouse: Left Button" },
- { "<Mouse>/rightButton", "Mouse: Right Button" },
- { "<Mouse>/middleButton", "Mouse: Middle Button" },
- { "<Mouse>/forwardButton", "Mouse: Forward Button" },
- { "<Mouse>/backButton", "Mouse: Back Button" },
- { "<Mouse>/scroll/up", "Mouse: Scroll Up" },
- { "<Mouse>/scroll/down", "Mouse: Scroll Down" }
- };
- foreach (var kvp in mouseControls) {
- mousePaths[kvp.Key] = kvp.Value;
- allControlPaths[kvp.Key] = kvp.Value;
- }
- var gamepadControls = new Dictionary<string, string> {
- { "<Gamepad>/buttonSouth", "Gamepad: A/Cross" },
- { "<Gamepad>/buttonEast", "Gamepad: B/Circle" },
- { "<Gamepad>/buttonWest", "Gamepad: X/Square" },
- { "<Gamepad>/buttonNorth", "Gamepad: Y/Triangle" },
- { "<Gamepad>/leftShoulder", "Gamepad: Left Bumper" },
- { "<Gamepad>/rightShoulder", "Gamepad: Right Bumper" },
- { "<Gamepad>/leftTrigger", "Gamepad: Left Trigger" },
- { "<Gamepad>/rightTrigger", "Gamepad: Right Trigger" },
- { "<Gamepad>/leftStickPress", "Gamepad: Left Stick Click" },
- { "<Gamepad>/rightStickPress", "Gamepad: Right Stick Click" },
- { "<Gamepad>/start", "Gamepad: Start/Options" },
- { "<Gamepad>/select", "Gamepad: Select/Share" },
- { "<Gamepad>/dpad/up", "Gamepad: D-Pad Up" },
- { "<Gamepad>/dpad/down", "Gamepad: D-Pad Down" },
- { "<Gamepad>/dpad/left", "Gamepad: D-Pad Left" },
- { "<Gamepad>/dpad/right", "Gamepad: D-Pad Right" }
- };
- foreach (var kvp in gamepadControls) {
- gamepadPaths[kvp.Key] = kvp.Value;
- allControlPaths[kvp.Key] = kvp.Value;
- }
- }
- private Dictionary<string, string> GetFilteredPaths() {
- var attr = (InputControlPathAttribute)attribute;
- var filteredPaths = new Dictionary<string, string>();
- if (attr.includeKeyboard) {
- foreach (var kvp in keyboardPaths) { filteredPaths[kvp.Key] = kvp.Value; }
- }
- if (attr.includeMouse) {
- foreach (var kvp in mousePaths) { filteredPaths[kvp.Key] = kvp.Value; }
- }
- if (attr.includeGamepad) {
- foreach (var kvp in gamepadPaths) { filteredPaths[kvp.Key] = kvp.Value; }
- }
- return filteredPaths;
- }
- private string GetDisplayName(string controlPath) {
- if (string.IsNullOrEmpty(controlPath)) { return "None"; }
- if (allControlPaths.TryGetValue(controlPath, out string displayName)) { return displayName; }
- // Fallback: try to make a readable name from the path
- var parts = controlPath.Split('/');
- if (parts.Length >= 2) {
- var device = parts[0].Trim('<', '>');
- var control = parts[1];
- return $"{device}: {control}";
- }
- return controlPath;
- }
- public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
- EditorGUI.BeginProperty(position, label, property);
- var filteredPaths = GetFilteredPaths();
- var attr = (InputControlPathAttribute)attribute;
- var pathsWithNone = new Dictionary<string, string> { { "", "None" } };
- foreach (var kvp in filteredPaths) {
- pathsWithNone[kvp.Key] = kvp.Value;
- }
- var currentPath = property.stringValue ?? "";
- var currentDisplayName = GetDisplayName(currentPath);
- // If current path is not in filtered results, show it but mark as filtered
- if (!pathsWithNone.ContainsKey(currentPath) && !string.IsNullOrEmpty(currentPath)) {
- currentDisplayName += " (filtered)";
- }
- var rect = EditorGUI.PrefixLabel(position, label);
- if (EditorGUI.DropdownButton(rect, new GUIContent(currentDisplayName), FocusType.Keyboard)) {
- var menu = new GenericMenu();
- menu.AddItem(new GUIContent("None"),
- string.IsNullOrEmpty(currentPath),
- () => SetPropertyValue(property, ""));
- menu.AddSeparator("");
- // Group by device type and add appropriate sections
- if (attr.includeKeyboard && keyboardPaths.Count > 0) {
- foreach (var kvp in keyboardPaths.OrderBy(x => x.Value)) {
- var menuPath = $"Keyboard/{ExtractControlName(kvp.Value)}";
- menu.AddItem(new GUIContent(menuPath),
- currentPath == kvp.Key,
- () => SetPropertyValue(property, kvp.Key));
- }
- }
- if (attr.includeMouse && mousePaths.Count > 0) {
- if (attr.includeKeyboard) menu.AddSeparator("Mouse/");
- foreach (var kvp in mousePaths.OrderBy(x => x.Value)) {
- var menuPath = $"Mouse/{ExtractControlName(kvp.Value)}";
- menu.AddItem(new GUIContent(menuPath),
- currentPath == kvp.Key,
- () => SetPropertyValue(property, kvp.Key));
- }
- }
- if (attr.includeGamepad && gamepadPaths.Count > 0) {
- if (attr.includeKeyboard || attr.includeMouse) menu.AddSeparator("Gamepad/");
- foreach (var kvp in gamepadPaths.OrderBy(x => x.Value)) {
- var menuPath = $"Gamepad/{ExtractControlName(kvp.Value)}";
- menu.AddItem(new GUIContent(menuPath),
- currentPath == kvp.Key,
- () => SetPropertyValue(property, kvp.Key));
- }
- }
- menu.ShowAsContext();
- }
- EditorGUI.EndProperty();
- }
- private string ExtractControlName(string displayName) {
- var colonIndex = displayName.IndexOf(": ");
- return colonIndex >= 0 ? displayName.Substring(colonIndex + 2) : displayName;
- }
- private void SetPropertyValue(SerializedProperty property, string value) {
- property.stringValue = value;
- property.serializedObject.ApplyModifiedProperties();
- }
- }
- #endif
Advertisement
Add Comment
Please, Sign In to add comment