Godot Input System: How Input Mapping and Event Processing Work
Godot's input system uses the InputMap singleton to bind physical input events to named actions, while the Input singleton processes raw OS events, updates action states, and provides cached queries for game scripts.
The Godot input system provides a flexible, data-driven architecture that decouples physical input devices from game logic. By mapping hardware events to abstract actions, developers can support multiple control schemes without hardcoding device-specific checks. This article examines the core implementation in the Godot Engine source code, tracing the path from OS-level events to script-accessible action queries.
Core Architecture of the Godot Input System
Godot's input subsystem is built around two complementary singleton classes that separate configuration from runtime processing.
InputMap: The Action Registry
The InputMap singleton serves as the central registry for action definitions. According to the source code in core/input/input_map.h, each action is stored as an Action struct containing a unique ID, deadzone value, and a list of bound InputEvent objects.
When you define an action in the Project Settings or via code, InputMap::add_action() (implemented in core/input/input_map.cpp at line 17) creates this registry entry. The deadzone parameter (default 0.5) filters noise on analog inputs like joystick axes.
Input: The Runtime Event Processor
While InputMap stores static definitions, the Input singleton (declared in core/input/input.h) handles dynamic event processing. This class maintains the runtime state of all input devices and computes action states each frame.
The implementation in core/input/input.cpp manages several critical data structures:
- Pressed key sets and mouse button masks
- Current mouse position and velocity
- Per-device
ActionStatecaches containingpressed,strength, andraw_strengthvalues
Input Event Processing Pipeline
The Godot input system processes events through a four-stage pipeline that transforms raw OS signals into queryable action states.
Step 1: OS Event Capture
Platform-specific display servers capture hardware events and convert them to Godot InputEvent objects. In platform/windows/display_server_windows.cpp, platform/linuxbsd/display_server_x11.cpp, and similar files, the display server creates concrete event subclasses like InputEventKey or InputEventMouseButton and forwards them to Input::parse_input_event().
Step 2: Event Parsing and State Updates
Inside core/input/input.cpp at line 792, Input::_parse_input_event_impl() performs several tasks:
- Updates the internal pressed key set or mouse button mask
- Adjusts mouse position and velocity tracking
- Generates emulated events for mouse-to-touch or touch-to-mouse conversion (marked with
DEVICE_ID_EMULATIONto prevent infinite loops)
Step 3: Action Matching and State Caching
The event then flows to InputMap::event_is_action() in core/input/input_map.cpp (lines 46-57). This method searches the action's inputs list using _find_event() to detect matches. For analog events like InputEventJoypadMotion, the deadzone threshold is applied during matching (see InputEventJoypadMotion::action_match in core/input/input_event.cpp, lines 122-145).
When a match is found, Input updates the per-device ActionState::DeviceState and triggers Input::_update_action_cache() (lines 48-63 in input.cpp). This aggregates all device states and API overrides (such as action_press() calls from scripts) into the cached pressed, strength, and raw_strength values.
Step 4: Querying Action States
Game scripts query the cached state through methods declared in core/input/input.h. Input::is_action_pressed() simply returns ActionState::cache.pressed, while Input::get_action_strength() returns the analog strength value. These queries have minimal overhead since they read pre-computed cache values rather than iterating through events.
Input Mapping Configuration
Understanding how to configure the Godot input system requires examining the binding mechanisms between events and actions.
Defining Actions and Deadzones
Actions are created using InputMap.add_action() with an optional deadzone parameter. In the engine source, InputMap::add_action() (line 17 in core/input/input_map.cpp) initializes the Action struct with a unique ID and stores it in the internal map. The deadzone value (default 0.5) filters low-intensity analog inputs.
Binding Events to Actions
Events are bound to actions through InputMap.action_add_event() (lines 201-224 in core/input/input_map.cpp). This method normalizes the device ID (converting legacy 0 to DEVICE_ID_KEYBOARD or DEVICE_ID_MOUSE) and appends the event to the action's inputs vector. You can bind multiple events to a single action, enabling simultaneous keyboard and controller support.
Built-in Default Actions
Godot provides default UI actions through InputMap.load_default() (line 527 in core/input/input_map.cpp). This method constructs actions like ui_left, ui_accept, and ui_cancel with predefined key bindings. Platform-specific overrides (e.g., ui_accept.macos) are applied via get_builtins_with_feature_overrides_applied() (lines 883-924), which checks OS::has_feature() to determine active variants.
Practical Code Examples
The following examples demonstrate how to interact with the Godot input system in GDScript, corresponding to the underlying C++ implementations.
Defining a Custom Action and Binding Keys
# Create a new action called "jump" with default deadzone
InputMap.add_action("jump")
# Bind the Space key
var ev = InputEventKey.new()
ev.keycode = Key.SPACE
InputMap.action_add_event("jump", ev)
# Bind the gamepad "A" button
ev = InputEventJoypadButton.new()
ev.button_index = JoyButton.A
InputMap.action_add_event("jump", ev)
This corresponds to InputMap::add_action() (line 17 of input_map.cpp) and InputMap::action_add_event() (lines 201-224).
Querying an Action in Game Logic
if Input.is_action_pressed("jump"):
$Player.jump()
Under the hood, Input::is_action_pressed() reads ActionState::cache.pressed, which is updated by _update_action_cache() (lines 48-63 in core/input/input.cpp) whenever a bound event occurs.
Simulating Input Events Programmatically
var ev = InputEventKey.new()
ev.keycode = Key.SPACE
ev.pressed = true
Input.parse_input_event(ev) # Triggers the same path as a real key press
parse_input_event() routes the event through _parse_input_event_impl() (line 792 in core/input/input.cpp), updates the key-set, finds matching actions via InputMap::event_is_action(), and refreshes the action cache.
Adjusting Action Deadzones at Runtime
InputMap.action_set_deadzone("ui_up", 0.3) # Higher deadzone for joystick axis
This calls InputMap::action_set_deadzone() (line 48 of core/input/input_map.cpp). The new deadzone is used the next time an axis event is matched (InputEventJoypadMotion::action_match in core/input/input_event.cpp, lines 122-145).
Reloading Default Actions
# Force a reload (useful after changing project settings)
InputMap.load_default()
This invokes InputMap::load_default() (line 527 in core/input/input_map.cpp), which iterates over the built-in map returned by get_builtins_with_feature_overrides_applied() (lines 883-924).
Summary
- InputMap (
core/input/input_map.cpp) stores action definitions and event bindings, handling deadzones and platform-specific overrides. - Input (
core/input/input.cpp) processes raw OS events throughparse_input_event(), maintains device state, and caches action states for fast queries. - The pipeline flows from platform display servers →
Input::_parse_input_event_impl()→InputMap::event_is_action()→Input::_update_action_cache()→ script queries likeis_action_pressed(). - Emulated input (mouse/touch conversion) is handled at the parsing stage with
DEVICE_ID_EMULATIONto prevent feedback loops. - Built-in actions are loaded via
load_default()with feature overrides applied for platform-specific variants.
Frequently Asked Questions
What is the difference between Input and InputMap in Godot?
InputMap is a singleton that stores static action definitions and their associated input events, acting as a registry that maps physical inputs to logical action names. Input is the runtime singleton that processes raw OS events, updates the state of pressed keys and buttons, and evaluates which actions are currently active based on the definitions stored in InputMap.
How does Godot handle input events from different platforms?
Platform-specific display servers (such as display_server_windows.cpp or display_server_x11.cpp) capture OS-specific input and construct Godot InputEvent objects. These are passed to Input::parse_input_event(), which processes them through the same unified pipeline regardless of origin. Platform-specific action overrides (like ui_accept.macos) are applied via get_builtins_with_feature_overrides_applied(), which checks OS::has_feature() to determine active variants.
What is the deadzone in Godot's input system and how is it applied?
The deadzone is a threshold value (default 0.5) stored per action in InputMap that filters out low-intensity analog noise from joystick axes. When an InputEventJoypadMotion is evaluated against an action, the action_match method (lines 122-145 in core/input/input_event.cpp) applies the deadzone to determine if the event counts as "pressed" and calculates the final strength value, effectively ignoring input below the threshold.
How can I simulate input events programmatically in Godot?
You can create InputEvent objects in GDScript (such as InputEventKey or InputEventJoypadButton), configure their properties like keycode or pressed, and pass them to Input.parse_input_event(). This method routes the synthetic event through the same internal pipeline as real hardware input, updating internal state and action caches via _parse_input_event_impl() and triggering any bound actions exactly as if the input originated from the OS.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →