Quick answer: Common causes include missing joypad input bindings in the Input Map, device index mismatch (the controller may be device 1 instead of 0), high deadzone values eating the input, or the controller being connected after the game started without handling the joy_connection_changed signal.

Here is how to fix Godot controller gamepad input not detected. You plug in an Xbox controller, a PlayStation DualSense, or a generic USB gamepad, but your Godot 4 game does not respond to any button presses or stick movement. Keyboard input works fine. The controller works in other applications. The problem is somewhere between Godot's Input Map configuration and how your code reads gamepad events.

The Symptom

Your game runs normally with keyboard and mouse. When you connect a controller, nothing happens. Buttons do not trigger actions, analog sticks produce no movement, and there are no errors in the output console. Alternatively, the controller works initially but stops responding after you disconnect and reconnect it, or it only works for specific buttons while the analog sticks remain dead.

In some cases, the controller works in the Godot editor's input testing dialog but not in your actual game. This is particularly confusing because it proves the engine can see the device, yet your game code never receives the events.

What Causes This

There are four common causes, and you may be hitting more than one simultaneously.

1. Missing joypad bindings in the Input Map. The most frequent cause. When you create an action like "move_right" and add a keyboard key, that action only responds to keyboard input. You must separately add a joypad button or axis event to the same action. Godot does not automatically map keyboard actions to controller equivalents.

2. Deadzone set too high. Each axis action in the Input Map has a deadzone property. The default is 0.5, which means the analog stick must be pushed past 50% of its range before the input registers. For controllers with less range or slightly worn sticks, this threshold is too aggressive and the input never reaches your code.

3. Device index mismatch. If you hardcode device 0 in your input checks but the controller registers as device 1 (which can happen if a virtual device or another peripheral is connected first), your checks will never match the actual device.

4. Hot-plugging not handled. If the controller is connected after the game starts, or disconnected and reconnected, Godot needs to be told to listen for connection changes. Without handling the joy_connection_changed signal, reconnected devices may not be picked up.

The Fix

Step 1: Add joypad bindings to your Input Map. Open Project → Project Settings → Input Map. For each action, click the + button and select Joypad Button or Joypad Axis. For a movement action like "move_right", add the right direction on the left stick axis:

# Your Input Map should have BOTH keyboard and joypad bindings:
# move_right:
#   - Key: D or Right Arrow
#   - Joypad Axis: Left Stick Right (Axis 0, positive)
# jump:
#   - Key: Space
#   - Joypad Button: A / Cross (Button 0)

Step 2: Lower the deadzone. In the Input Map, each axis binding has a deadzone slider. Set it to 0.2 or 0.25 for responsive stick input. You can also set it programmatically:

# Set deadzone programmatically if needed
func _ready():
    # Use Input.get_vector with explicit deadzone
    var direction = Input.get_vector(
        "move_left", "move_right",
        "move_up", "move_down",
        0.2  # deadzone parameter
    )

Step 3: Use generic device input. When using the action system (Input.is_action_pressed()), Godot automatically checks all devices. Do not filter by device index unless you specifically need to. Avoid this pattern:

# Bad: hardcoded device index
var value = Input.get_joy_axis(0, JOY_AXIS_LEFT_X)

# Good: use the action system instead
var direction = Input.get_vector(
    "move_left", "move_right",
    "move_up", "move_down"
)

Step 4: Handle hot-plugging. Connect to the joy_connection_changed signal to respond when controllers are added or removed:

extends Node

func _ready():
    Input.connect("joy_connection_changed", _on_joy_connection_changed)

    # Check for already-connected controllers at startup
    var joypads = Input.get_connected_joypads()
    for id in joypads:
        print("Controller connected: ", Input.get_joy_name(id))

func _on_joy_connection_changed(device_id: int, connected: bool):
    if connected:
        print("Controller ", device_id, " connected: ",
              Input.get_joy_name(device_id))
    else:
        print("Controller ", device_id, " disconnected")

Why This Works

The Godot Input Map is an abstraction layer that sits between hardware events and your game logic. When you add a joypad binding to an action, you are telling Godot to translate that specific hardware event (stick axis movement, button press) into the named action your code checks for. Without this binding, the hardware event still reaches Godot, but no action is generated from it, so is_action_pressed() never returns true.

The deadzone determines the minimum analog value that triggers the action. A deadzone of 0.5 means the stick must be pushed to 50% before it registers. Lowering it to 0.2 means 20% is enough. This is critical because physical controllers have different stick ranges, and a high deadzone can effectively disable input on controllers with shorter throw distances.

Using the action system instead of direct device queries (get_joy_axis) is important because the action system aggregates all devices. If a player has two controllers connected, or if the device index changes, the action system handles it transparently. Direct device queries require you to track which device index belongs to which player, which is only necessary for local multiplayer.

"Always test with at least two different controller brands. What works on an Xbox controller may behave differently on a DualSense or a Switch Pro controller due to axis mapping differences."

Related Issues

Controller input problems often go hand in hand with other input issues. These related guides may help:

Bind it, lower the deadzone, and let the action system do the rest.