This page documents the input system in Godot Engine: the Input singleton, the InputEvent class hierarchy, the InputMap action system, and how input is collected from platform drivers and dispatched through the engine.
For how input events propagate through the scene tree (e.g., _input, _unhandled_input, accept_event), see Scene System (4) and Viewport System (4.3). For the DisplayServer layer that feeds raw OS input into this system, see Display Server (7.6).
The input system consists of three cooperating singletons and a class hierarchy of event objects:
| Component | Class | File |
|---|---|---|
| Global input state | Input | core/input/input.h |
| Named action registry | InputMap | core/input/input_map.h |
| Event base class | InputEvent | core/input/input_event.h |
| SDL joypad driver | JoypadSDL | drivers/sdl/joypad_sdl.h |
Input tracks the current pressed/released state of all devices and is polled directly by game logic. InputMap maps named string actions (e.g., "jump") to sets of InputEvent descriptors. InputEvent subclasses carry the data for a single hardware event and flow through the engine via Input::_parse_input_event_impl.
All input events are Resource subclasses. The hierarchy adds progressively more data at each level.
InputEvent class hierarchy
Sources: core/input/input_event.h core/input/input_event.cpp
InputEvent::device uses reserved ID ranges to identify the source of an event:
| Constant | Value | Meaning |
|---|---|---|
DEVICE_ID_EMULATION | -1 | Synthesized event (e.g., touch-from-mouse) |
DEVICE_ID_KEYBOARD | 16 | Physical keyboard |
DEVICE_ID_MOUSE | 32 | Physical mouse |
| 0–15 | — | Joypad slots |
Sources: core/input/input_event.h64-67
InputEventKey carries three distinct keycode fields, each suited to a different use case:
| Property | Use Case | Example (on AZERTY keyboard, pressing the A key) |
|---|---|---|
keycode | Shortcuts (layout-aware Latin key) | Key::Q (because AZERTY maps A→Q in Latin) |
physical_keycode | Game input (physical US-QWERTY location) | Key::A (left side, home row) |
key_label | Key prompts (what the key is labeled) | Key::A (the letter printed on the key) |
is_echo is true for repeated events the OS sends while a key is held.
Sources: core/input/input_event.h150-206 doc/classes/InputEventKey.xml
Input is the central runtime class. It maintains pressed-state sets for every input device, tracks action states, buffers incoming events, and forwards them to the scene tree.
Input singleton internal state
Sources: core/input/input.h107-302 core/input/input.cpp
Mouse behavior is controlled via static function pointers that are set by the DisplayServer implementation at startup:
set_mouse_mode_func, get_mouse_mode_func
set_custom_mouse_cursor_func, get_current_cursor_shape_func
warp_mouse_func
The MouseMode enum values are:
| Value | Behavior |
|---|---|
MOUSE_MODE_VISIBLE | Normal cursor, visible |
MOUSE_MODE_HIDDEN | Cursor hidden, movement reported |
MOUSE_MODE_CAPTURED | Cursor hidden and locked to window, relative movement reported |
MOUSE_MODE_CONFINED | Cursor visible but locked inside window |
MOUSE_MODE_CONFINED_HIDDEN | Cursor hidden and locked inside window |
Sources: core/input/input.h44-52 core/input/input.cpp86-94
Input event pipeline
Sources: core/input/input.cpp793-1050 core/input/input.h300-306 drivers/sdl/joypad_sdl.cpp85-287
Incoming events are appended to buffered_events by parse_input_event(). They are not immediately processed. Two mechanisms control when they are flushed:
use_accumulated_input = true by default): Consecutive InputEventMouseMotion events are merged via InputEvent::accumulate() before dispatch, reducing callback frequency.agile_input_event_flushing): When enabled, events are flushed at more points during the frame loop, reducing latency. Controlled by ProjectSettings.input_devices/buffering/agile_event_flushing.flush_buffered_events() can also be called manually for fine-grained timing control.
Sources: core/input/input.h158-161 core/input/input.cpp doc/classes/Input.xml50-56
_parse_input_event_impl synthesizes cross-device events to ease portability:
| Setting | Trigger | Synthesized Event |
|---|---|---|
emulate_touch_from_mouse | Left InputEventMouseButton press | InputEventScreenTouch |
emulate_touch_from_mouse | InputEventMouseMotion with left button held | InputEventScreenDrag |
emulate_mouse_from_touch | First InputEventScreenTouch press | InputEventMouseButton |
emulate_mouse_from_touch | InputEventScreenDrag for tracked touch index | InputEventMouseMotion |
Synthesized events have device = DEVICE_ID_EMULATION (-1) and are flagged p_is_emulated = true when re-routed through _parse_input_event_impl to prevent infinite loops.
Sources: core/input/input.cpp842-967
InputMap is a singleton that maps StringName action names to lists of InputEvent triggers.
InputMap action lookup
Sources: core/input/input_map.h49-53 core/input/input_map.cpp147-165
Actions are populated from two sources:
load_from_project_settings(), which reads all input/* keys from project.godot and calls add_action / action_add_event for each. The InputMap emits project_settings_loaded when done.load_default() / get_builtins(), which returns hardcoded ui_* actions (navigation, text editing, clipboard, etc.).Sources: core/input/input_map.cpp325-358 core/input/input_map.cpp452-700
| Action | Default Binding(s) |
|---|---|
ui_accept | Enter, KP Enter, Space |
ui_cancel | Escape |
ui_left | Left arrow, Joypad DPAD_LEFT, Left stick X− |
ui_right | Right arrow, Joypad DPAD_RIGHT, Left stick X+ |
ui_up | Up arrow, Joypad DPAD_UP, Left stick Y− |
ui_down | Down arrow, Joypad DPAD_DOWN, Left stick Y+ |
ui_copy | Ctrl+C, Ctrl+Insert |
ui_paste | Ctrl+V, Shift+Insert |
ui_undo | Ctrl+Z |
ui_redo | Ctrl+Shift+Z, Ctrl+Y |
Sources: core/input/input_map.cpp365-438
Each action has a deadzone (default 0.2f). When InputMap::_find_event() evaluates an InputEventJoypadMotion against an action, the axis value must exceed the deadzone for the action to be considered pressed. Toggle actions (those where an axis maps to a press/release, like ui_left) use DEFAULT_TOGGLE_DEADZONE = 0.5f.
Sources: core/input/input_map.h55-57 core/input/input_map.cpp147-165
When _parse_input_event_impl runs, it iterates all actions in InputMap to check if the event matches any. On a match, it updates the ActionState for that action:
struct ActionState {
uint64_t pressed_physics_frame // Engine::get_physics_frames() when pressed
uint64_t pressed_process_frame // Engine::get_process_frames() when pressed
uint64_t released_physics_frame
uint64_t released_process_frame
ObjectID pressed_event_id // instance ID of the triggering event
ObjectID released_event_id
HashMap<int, DeviceState> device_states // per-device pressed/strength
ActionStateCache cache // aggregate: pressed, strength, raw_strength
}
is_action_just_pressed(action) returns true only if pressed_physics_frame (or pressed_process_frame) matches the current frame counter. This means the result is valid for exactly one frame.
is_action_just_pressed_by_event(action, event) additionally requires that the pressed_event_id matches the given event's instance ID — useful inside _input() handlers.
Sources: core/input/input.h129-153 core/input/input.cpp411-435 core/input/input.cpp437-466
| Method | Description |
|---|---|
get_axis(neg, pos) | strength(pos) - strength(neg), range −1..1 |
get_vector(neg_x, pos_x, neg_y, pos_y) | 2D vector with circular deadzone and length clamping |
get_vector uses the average deadzone of all four actions when no explicit deadzone is given, and scales the vector so that the deadzone edge maps to 0.0 and the maximum maps to 1.0.
Sources: core/input/input.cpp563-591
On platforms that support it, JoypadSDL (drivers/sdl/joypad_sdl.cpp) handles device lifecycle and event polling using SDL3. Godot uses only SDL's joystick and gamepad subsystems (video, audio, and other subsystems are disabled via SDL_build_config_private.h).
JoypadSDL → Input pipeline
Sources: drivers/sdl/joypad_sdl.cpp64-287 drivers/sdl/joypad_sdl.h
When a joypad connects, Input::joy_connection_changed looks up the device GUID in the map_db vector (populated by parse_mapping / add_joy_mapping from default_controller_mappings.h, which is the SDL gamepad DB embedded in source). A JoyDeviceMapping stores JoyBinding entries that translate raw hardware axis/button/hat events to Godot's canonical JoyButton and JoyAxis values.
If the SDL driver is used and the device is an SDL gamepad (SDL_IsGamepad), mapping is marked as "mapping_handled" and Godot's remapping layer is bypassed — SDL has already remapped the device.
Sources: core/input/input.h244-286 core/input/input.cpp675-743 drivers/sdl/joypad_sdl.cpp139-213
Input::JoypadFeatures is a virtual interface that joypad drivers implement to expose optional hardware capabilities:
class JoypadFeatures {
virtual bool has_joy_vibration() const
virtual bool has_joy_light() const
virtual void set_joy_light(const Color&)
virtual bool has_joy_motion_sensors() const
virtual void set_joy_motion_sensors_enabled(bool)
}
JoypadSDL::Joypad implements this interface. The Input singleton stores a pointer to the features object per device in the Joypad::features field and delegates capability queries to it.
Sources: core/input/input.h90-101 drivers/sdl/joypad_sdl.h48-68
For controllers with IMU sensors (accelerometer + gyroscope), Input maintains a MotionInfo per device, backed by the GamepadMotion library (thirdparty/gamepadmotionhelpers/GamepadMotion.hpp). When sensors are enabled, joy_motion_sensors(device, accel, gyro) feeds sensor data into the GamepadMotion helper, which computes gravity-separated acceleration and corrects gyroscope drift.
Calibration is a multi-frame process managed through start_joy_motion_sensors_calibration / stop_joy_motion_sensors_calibration, storing a gyroscope offset in the MotionInfo::calibrated flag and reusable via get_joy_motion_sensors_calibration / set_joy_motion_sensors_calibration.
Sources: core/input/input.h173-188 core/input/input.cpp
Vibration state is stored in HashMap<int, VibrationInfo> joy_vibration. The SDL driver polls Input::get_joy_vibration_timestamp each process_events() call and only sends SDL_RumbleJoystick when the timestamp has advanced (i.e., a new vibration request was made). get_joy_vibration_remaining_duration() computes the remaining time from the OS tick counter.
Sources: core/input/input.h164-171 drivers/sdl/joypad_sdl.cpp87-123
On Android and iOS, the OS or DisplayServer implementation calls:
Input::set_gravity(Vector3)
Input::set_accelerometer(Vector3)
Input::set_magnetometer(Vector3)
Input::set_gyroscope(Vector3)
These store the values in thread-safe members and are read back via get_gravity(), get_accelerometer(), etc. In debug builds on Android, reading a sensor value without enabling it in ProjectSettings.input_devices/sensors/* triggers a warning.
Sources: core/input/input.cpp745-791 core/input/input.h116-123
VelocityTrack computes a smoothed velocity from accumulated position deltas. It maintains a time-windowed accumulator:
accum / screen_accum over time accum_t.accum_t >= min_ref_frame (0.1 s), velocity is computed as accum / accum_t and the accumulator resets.delta_t > max_ref_frame (3.0 s), the tracker resets to handle large gaps between movements.One VelocityTrack exists for the mouse (mouse_velocity_track) and one per active touch index (touch_velocity_track).
Sources: core/input/input.h190-203 core/input/input.cpp261-306
Shortcut (core/input/shortcut.h) wraps a single Ref<InputEvent> and provides a human-readable description for use in UI. It is a Resource so it can be serialized and shared.
Two mechanisms exist:
Input::action_press(action, strength) / action_release(action) — Directly sets action state without creating an InputEvent. Does not trigger _input() callbacks on nodes. Useful for polling-based checks only.
Input::parse_input_event(event) — Routes an InputEvent through the full pipeline (buffer → _parse_input_event_impl → event_dispatch_function → SceneTree). This triggers Node::_input on all nodes that receive it.
Sources: core/input/input.cpp196-197 doc/classes/Input.xml16-25
| File | Contents |
|---|---|
| core/input/input.h | Input class declaration, ActionState, Joypad, VelocityTrack, JoypadFeatures |
| core/input/input.cpp | Input implementation: event parsing, action state, joypad mapping |
| core/input/input_event.h | Full InputEvent hierarchy declarations |
| core/input/input_event.cpp | InputEvent hierarchy implementation, action_match() logic |
| core/input/input_map.h | InputMap class, Action struct |
| core/input/input_map.cpp | Action loading from ProjectSettings, built-in ui_* actions |
| core/input/input_enums.h | JoyButton, JoyAxis, HatDir, HatMask enumerations |
| core/input/default_controller_mappings.h | Embedded SDL gamepad database |
| drivers/sdl/joypad_sdl.h | JoypadSDL class declaration |
| drivers/sdl/joypad_sdl.cpp | SDL3 event polling and Godot Input integration |
| drivers/sdl/SDL_build_config_private.h | SDL subsystem configuration (disables unused subsystems) |
| thirdparty/gamepadmotionhelpers/GamepadMotion.hpp | IMU sensor fusion library for joypad motion |
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.