intermediate Utilities

Input Manager

Clean wrapper around Unity's new Input System with action map switching, rebinding support, and input event bus.

Unity 2022.3+ · 2.8 KB · InputManager.cs

How to Use

1

Attach InputManager to a persistent manager object

2

Define actions in inspector with default keys

3

Check input: InputManager.Instance.WasPressed("Jump")

4

Movement: var move = InputManager.Instance.GetMovement()

5

Rebind: InputManager.Instance.StartRebind("Jump") then press new key

6

Reset: InputManager.Instance.ResetBinding("Jump")

7

Bindings auto-save to PlayerPrefs

8

Hook OnActionPressed for event-driven input handling

Source Code

InputManager.cs
C#
using UnityEngine;
using UnityEngine.Events;
using System.Collections.Generic;

/// <summary>
/// Input manager that wraps Unity's legacy Input into a clean event-driven API.
/// Provides rebindable keys, input events, and action grouping.
/// Compatible with both legacy Input and can be adapted for new Input System.
/// </summary>
public class InputManager : MonoBehaviour
{
    public static InputManager Instance { get; private set; }

    [System.Serializable]
    public class InputAction
    {
        public string actionName;
        public KeyCode defaultKey;
        public KeyCode currentKey;
        [HideInInspector] public bool isPressed;
        [HideInInspector] public bool wasPressed;
        [HideInInspector] public bool wasReleased;

        public InputAction(string name, KeyCode key)
        {
            actionName = name;
            defaultKey = key;
            currentKey = key;
        }
    }

    [Header("Actions")]
    [SerializeField] private List<InputAction> actions = new List<InputAction>()
    {
        new InputAction("Jump", KeyCode.Space),
        new InputAction("Sprint", KeyCode.LeftShift),
        new InputAction("Interact", KeyCode.E),
        new InputAction("Crouch", KeyCode.LeftControl),
        new InputAction("Reload", KeyCode.R),
        new InputAction("Inventory", KeyCode.I),
        new InputAction("Pause", KeyCode.Escape),
    };

    [Header("Events")]
    public UnityEvent<string> OnActionPressed;
    public UnityEvent<string> OnActionReleased;

    private Dictionary<string, InputAction> actionMap = new Dictionary<string, InputAction>();
    private bool isRebinding;
    private string rebindingAction;
    public UnityEvent<string, KeyCode> OnRebindComplete;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
            return;
        }

        foreach (var action in actions)
            actionMap[action.actionName] = action;

        LoadBindings();
    }

    private void Update()
    {
        if (isRebinding)
        {
            HandleRebinding();
            return;
        }

        foreach (var action in actions)
        {
            action.wasPressed = Input.GetKeyDown(action.currentKey);
            action.wasReleased = Input.GetKeyUp(action.currentKey);
            action.isPressed = Input.GetKey(action.currentKey);

            if (action.wasPressed)
                OnActionPressed?.Invoke(action.actionName);
            if (action.wasReleased)
                OnActionReleased?.Invoke(action.actionName);
        }
    }

    /// <summary>Check if an action is currently held down.</summary>
    public bool IsPressed(string actionName)
    {
        return actionMap.TryGetValue(actionName, out var action) && action.isPressed;
    }

    /// <summary>Check if an action was pressed this frame.</summary>
    public bool WasPressed(string actionName)
    {
        return actionMap.TryGetValue(actionName, out var action) && action.wasPressed;
    }

    /// <summary>Check if an action was released this frame.</summary>
    public bool WasReleased(string actionName)
    {
        return actionMap.TryGetValue(actionName, out var action) && action.wasReleased;
    }

    /// <summary>Get the horizontal axis (-1 to 1).</summary>
    public float GetHorizontal() => Input.GetAxisRaw("Horizontal");

    /// <summary>Get the vertical axis (-1 to 1).</summary>
    public float GetVertical() => Input.GetAxisRaw("Vertical");

    /// <summary>Get movement vector (normalized).</summary>
    public Vector2 GetMovement() => new Vector2(GetHorizontal(), GetVertical()).normalized;

    /// <summary>Start listening for a new key to rebind an action.</summary>
    public void StartRebind(string actionName)
    {
        if (!actionMap.ContainsKey(actionName)) return;
        isRebinding = true;
        rebindingAction = actionName;
    }

    private void HandleRebinding()
    {
        foreach (KeyCode key in System.Enum.GetValues(typeof(KeyCode)))
        {
            if (Input.GetKeyDown(key) && key != KeyCode.Escape)
            {
                actionMap[rebindingAction].currentKey = key;
                isRebinding = false;
                SaveBindings();
                OnRebindComplete?.Invoke(rebindingAction, key);
                return;
            }
        }

        // Cancel rebind on Escape
        if (Input.GetKeyDown(KeyCode.Escape))
            isRebinding = false;
    }

    /// <summary>Reset an action to its default key.</summary>
    public void ResetBinding(string actionName)
    {
        if (actionMap.TryGetValue(actionName, out var action))
        {
            action.currentKey = action.defaultKey;
            SaveBindings();
        }
    }

    /// <summary>Reset all bindings to defaults.</summary>
    public void ResetAllBindings()
    {
        foreach (var action in actions)
            action.currentKey = action.defaultKey;
        SaveBindings();
    }

    /// <summary>Get the current key for an action.</summary>
    public KeyCode GetBinding(string actionName)
    {
        return actionMap.TryGetValue(actionName, out var action) ? action.currentKey : KeyCode.None;
    }

    private void SaveBindings()
    {
        foreach (var action in actions)
            PlayerPrefs.SetInt("input_" + action.actionName, (int)action.currentKey);
        PlayerPrefs.Save();
    }

    private void LoadBindings()
    {
        foreach (var action in actions)
        {
            string key = "input_" + action.actionName;
            if (PlayerPrefs.HasKey(key))
                action.currentKey = (KeyCode)PlayerPrefs.GetInt(key);
        }
    }
}