Quick answer: The most common cause of Gamepad.current being null is that Active Input Handling in Edit → Project Settings → Player is still set to Input Manager (Old). Set it to Input System Package (New) or Both. If the gamepad is detected but not responding, verify that your Action Map bindings use the correct control path and that you’ve called Enable() on the action map. On Windows, only XInput controllers are supported natively — DirectInput-only devices require a wrapper.
Unity’s new Input System is a significant improvement over the old Input Manager — it supports rebinding, multiple simultaneous devices, and a clean event-driven API. It’s also a system with a surprisingly steep ramp of configuration gotchas that can leave a plugged-in gamepad completely unrecognised. This post covers every layer of the stack, from Player Settings down to hardware protocols, so you can pin down exactly why your controller isn’t working.
Step 0: Verify Active Input Handling in Player Settings
Before debugging anything else, check Edit → Project Settings → Player → Other Settings → Active Input Handling. This dropdown has three options:
- Input Manager (Old) — the legacy system.
UnityEngine.InputSystemclasses compile but the Input System backend is disabled.Gamepad.currentwill always be null. - Input System Package (New) — only the new system is active.
Input.GetAxis()and friends throw exceptions. - Both — both systems run in parallel. Useful during migration, with a small performance cost.
Set it to Input System Package (New) (or Both if you still have legacy Input calls). Unity will prompt for a domain reload — accept it. After the reload, open the Input Debugger window (Window → Analysis → Input Debugger) and plug in your controller. It should appear under Devices immediately.
Diagnosing with the Input Debugger
The Input Debugger is the single most useful tool for gamepad issues and is often overlooked. It shows every device the Input System has detected, all active controls and their current values, and every action event as it fires in real time. Open it before you write a single line of diagnostic code.
If your gamepad appears in the device list but controls show zero values, the device is detected but input isn’t being read — this points to an action map or binding problem. If the device doesn’t appear at all, the problem is at the OS or hardware protocol level (XInput vs. DirectInput, driver, USB hub power).
// Quick diagnostic: log all connected gamepads at startup
using UnityEngine;
using UnityEngine.InputSystem;
void Start()
{
var gamepads = Gamepad.all;
Debug.Log($"Gamepads detected: {gamepads.Count}");
foreach (var pad in gamepads)
Debug.Log($" {pad.displayName} — layout: {pad.layout}");
if (Gamepad.current == null)
Debug.LogWarning("Gamepad.current is null — no gamepad has sent input yet this session.");
}
Note the distinction: Gamepad.all lists every detected gamepad regardless of whether it has been used. Gamepad.current is only set to a non-null value after the gamepad sends at least one input event. If a player launches your game and immediately uses keyboard before touching the controller, Gamepad.current may be null even with a working gamepad plugged in.
Subscribing to Connect and Disconnect Events
Polling Gamepad.current every frame is fragile. The reliable pattern is to subscribe to InputSystem.onDeviceChange and update your UI and active control scheme whenever a device is added or removed. This also lets you prompt players when they disconnect a gamepad mid-session rather than silently ignoring input.
using UnityEngine;
using UnityEngine.InputSystem;
public class GamepadManager : MonoBehaviour
{
public Gamepad activeGamepad { get; private set; }
void OnEnable()
{
InputSystem.onDeviceChange += OnDeviceChange;
// Pick up any already-connected gamepad
activeGamepad = Gamepad.all.Count > 0 ? Gamepad.all[0] : null;
}
void OnDisable()
{
InputSystem.onDeviceChange -= OnDeviceChange;
}
private void OnDeviceChange(InputDevice device, InputDeviceChange change)
{
if (device is not Gamepad gamepad) return;
switch (change)
{
case InputDeviceChange.Added:
activeGamepad = gamepad;
Debug.Log($"Gamepad connected: {gamepad.displayName}");
// Show controller UI, switch control scheme, etc.
break;
case InputDeviceChange.Removed:
if (activeGamepad == gamepad)
activeGamepad = Gamepad.all.Count > 0 ? Gamepad.all[0] : null;
Debug.Log($"Gamepad disconnected: {gamepad.displayName}");
// Show "controller disconnected" UI if needed
break;
}
}
}
Action Map Bindings: The Wrong Control Path
A gamepad that appears in the Input Debugger with live values but doesn’t trigger your game actions almost always has a binding path mismatch. In the Input Actions editor, each binding has a Path field like <Gamepad>/buttonSouth. If you accidentally bound to <XInputController>/buttonSouth instead, the action will only fire for XInput controllers, not DualShock or generic HID gamepads.
Always use the generic <Gamepad> path prefix rather than a controller-specific one unless you intentionally need device-specific bindings. Enable your action map by calling actions.Enable() — a newly created InputActionAsset does not auto-enable; forgetting this call is an extremely common source of “gamepad does nothing” reports.
void Awake()
{
// playerActions is assigned in the Inspector from a .inputactions asset
playerActions.Enable(); // Without this, no actions fire at all
playerActions.Player.Jump.performed += ctx =>
{
// ctx.control.device tells you which device triggered the action
Debug.Log($"Jump from {ctx.control.device.displayName}");
Jump();
};
}
void OnDestroy()
{
playerActions.Disable();
}
XInput vs. DirectInput on Windows
Unity’s Input System on Windows uses XInput as its primary gamepad API. XInput is the protocol used by Xbox controllers and anything marketed as “Xbox compatible.” DirectInput is the older Windows API used by many legacy gamepads, some fight sticks, and non-Xbox-branded controllers.
If a controller is DirectInput-only, it will not appear in Unity’s Input Debugger at all, even though Windows Device Manager shows it as connected and it works fine in older games. The workaround is either to use a compatibility layer like x360ce (presents DirectInput devices as XInput), or to add the com.unity.inputsystem RawInput/HID backend which can enumerate HID devices that don’t expose XInput. The HID backend requires adding a custom device layout in code — non-trivial but well-documented in the Input System manual.
On macOS and Linux, Unity uses a different backend (IOKit and evdev respectively) that is more permissive about controller protocols, so a controller that fails on Windows may work on macOS without any changes. Always test on Windows specifically if your game targets PC.
“The Input Debugger window has saved me hours of guesswork on every controller issue I’ve ever investigated. Before you write a single Debug.Log, open it — the answer is almost always already there on screen.”
A controller bug report from a player who says “my gamepad doesn’t work” is rarely a Unity bug — it’s almost always a DirectInput-only controller, a missing Enable() call, or a control path set to a specific device type instead of the generic Gamepad.