Input Handling & the Input Map
*Project Settings → Input Map*: define named actions (e.g., move_left, jump, shoot) and bind keys, mouse buttons, gamepad buttons and axes to them.
19.1 The Input Map
*Project Settings → Input Map*: define named actions (e.g., move_left, jump, shoot) and bind keys, mouse buttons, gamepad buttons and axes to them. Code checks actions, not keys, so players can rebind and gamepads work automatically. Built-in ui_* actions (ui_accept, ui_left, ui_cancel) drive UI navigation.
19.2 Polling with the Input singleton
func _physics_process(delta: float) -> void:
var dir := Input.get_vector("move_left", "move_right", "move_up", "move_down") # normalized, deadzone-aware
var axis := Input.get_axis("move_left", "move_right") # -1..1
if Input.is_action_pressed("run"): pass # held
if Input.is_action_just_pressed("jump"): pass # pressed this frame
if Input.is_action_just_released("jump"): pass
var strength := Input.get_action_strength("accelerate") # analog 0..1
if Input.is_key_pressed(KEY_SHIFT): pass # raw key (avoid for gameplay)
if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): pass
var mouse_pos := get_global_mouse_position() # CanvasItem method (world coords)19.3 Event-based input
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("pause"):
toggle_pause()
get_viewport().set_input_as_handled() # stop propagation
if event is InputEventMouseButton and event.pressed:
match event.button_index:
MOUSE_BUTTON_LEFT: shoot_at(event.position)
MOUSE_BUTTON_WHEEL_UP: zoom_in()
if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
rotate_camera(event.relative)
if event is InputEventKey and event.pressed and not event.echo:
if event.keycode == KEY_F11:
toggle_fullscreen()
if event is InputEventScreenTouch and event.pressed:
print("touch at ", event.position)19.4 Input propagation order
Use _unhandled_input for gameplay so clicks on UI don't also fire your gun.
Event → _input() on all nodes (reverse tree order)
→ Control GUI (_gui_input on the focused/hovered Control)
→ _shortcut_input()
→ _unhandled_key_input()
→ _unhandled_input()
→ physics picking (CollisionObject input_event, if enabled)19.5 Rebinding at runtime
Save bindings with ConfigFile (Chapter 27) and re-apply them at startup.
func rebind(action: StringName, new_event: InputEvent) -> void:
InputMap.action_erase_events(action)
InputMap.action_add_event(action, new_event)
func add_action_in_code() -> void:
if not InputMap.has_action("dash"):
InputMap.add_action("dash")
var ev := InputEventKey.new()
ev.physical_keycode = KEY_SPACE # physical: same position on any keyboard layout
InputMap.action_add_event("dash", ev)19.6 Mouse modes and misc
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED # FPS games (hidden & locked)
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
Input.set_custom_mouse_cursor(preload("res://cursor.png"))
Input.start_joy_vibration(0, 0.5, 0.8, 0.3) # device, weak, strong, duration
Input.joy_connection_changed.connect(func(device, connected): print(device, connected))