Up to date

This page is up to date for Godot 4.0. If you still find outdated information, please open an issue.

Controllers, gamepads, and joysticks

Godot supports hundreds of controller models thanks to the community-sourced SDL game controller database.

Controllers are supported on Windows, macOS, Linux, Android, iOS, and HTML5.

Note that more specialized devices such as steering wheels, rudder pedals and HOTAS are less tested and may not always work as expected. Overriding force feedback for those devices is also not implemented yet. If you have access to one of those devices, don't hesitate to report bugs on GitHub.

In this guide, you will learn:

  • How to write your input logic to support both keyboard and controller inputs.

  • How controllers can behave differently from keyboard/mouse input.

  • Troubleshooting issues with controllers in Godot.

Supporting universal input

Thanks to Godot's input action system, Godot makes it possible to support both keyboard and controller input without having to write separate code paths. Instead of hardcoding keys or controller buttons in your scripts, you should create input actions in the Project Settings which will then refer to specified key and controller inputs.

Input actions are explained in detail on the Using InputEvent page.


Unlike keyboard input, supporting both mouse and controller input for an action (such as looking around in a first-person game) will require different code paths since these have to be handled separately.

Which Input singleton method should I use?

There are 3 ways to get input in an analog-aware way:

  • When you have two axes (such as joystick or WASD movement) and want both axes to behave as a single input, use Input.get_vector():

# `velocity` will be a Vector2 between `Vector2(-1.0, -1.0)` and `Vector2(1.0, 1.0)`.
# This handles deadzone in a correct way for most use cases.
# The resulting deadzone will have a circular shape as it generally should.
var velocity = Input.get_vector("move_left", "move_right", "move_forward", "move_back")

# The line below is similar to `get_vector()`, except that it handles
# the deadzone in a less optimal way. The resulting deadzone will have
# a square-ish shape when it should ideally have a circular shape.
var velocity = Vector2(
        Input.get_action_strength("move_right") - Input.get_action_strength("move_left"),
        Input.get_action_strength("move_back") - Input.get_action_strength("move_forward")