input-handling

SKILL.md

Input Handling

Handle keyboard, mouse, gamepad, and touch input with proper buffering and accessibility support.

Available Scripts

input_buffer.gd

Input buffering for responsive controls - buffers actions for 150ms to ensure tight game feel.

input_remapper

Runtime input rebinding with conflict detection and save/load persistence.

MANDATORY - For Responsive Controls: Read input_buffer.gd before implementing jump/dash mechanics.

NEVER Do in Input Handling

  • NEVER poll input in _process() for gameplay actions — Use _physics_process() or _unhandled_input()_process()` = frame-rate dependent, causes input drops at low FPS.
  • NEVER use hardcoded key checks (KEY_W, KEY_SPACE) — Use InputMap actions. Hardcoded keys = no rebinding, breaks non-QWERTY keyboards.
  • NEVER ignore controller deadzones — Stick drift at 0.05 magnitude = character walks alone. ALWAYS implement Input.get_axis() with 0.15-0.2 deadzone.
  • NEVER assume single input device — Player might switch keyboard → gamepad mid-session. Listen to Input.joy_connection_changed and update UI prompts dynamically.
  • NEVER use //_input() for gameplay actions_input() fires for ALL events (including UI). Use _unhandled_input() which only fires if UI didn't consume the event.
  • NEVER forget input buffering for responsive controls — Player presses jump 50ms before landing? Without buffer, jump is lost. Buffer inputs for 100-150ms for tight game-feel.

InputMap Actions

Setup: Project Settings → Input Map → Add action

# Check if action pressed this frame
if Input.is_action_just_pressed("jump"):
    jump()

# Check if action held
if Input.is_action_pressed("fire"):
    shoot()

# Check if action released
if Input.is_action_just_released("jump"):
    release_jump()

# Get axis (-1 to 1)
var direction := Input.get_axis("move_left", "move_right")

# Get vector
var input_vector := Input.get_vector("left", "right", "up", "down")

InputEvent Processing

func _input(event: InputEvent) -> void:
    if event is InputEventKey:
        if event.keycode == KEY_ESCAPE and event.pressed:
            pause_game()
    
    if event is InputEventMouseButton:
        if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
            click_position = event.position

Gamepad Support

# Detect controller connection
func _ready() -> void:
    Input.joy_connection_changed.connect(_on_joy_connection_changed)

func _on_joy_connection_changed(device: int, connected: bool) -> void:
    if connected:
        print("Controller ", device, " connected")

Reference

Weekly Installs
1
GitHub Stars
35
First Seen
Feb 9, 2026
Security Audits
Installed on
amp1
opencode1
kimi-cli1
codex1
github-copilot1
gemini-cli1