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))