Open-Source Wikis

/

Bevy

/

Features

/

Input

bevyengine/bevy

Input

How keyboard, mouse, touch, and gamepad data flow from the OS to your systems.

Path overview

graph LR
    OS -->|events| W[bevy_winit]
    OS -->|gamepads| G[bevy_gilrs]
    W -->|KeyboardInput, MouseButtonInput, MouseMotion, MouseWheel, TouchInput| Events
    G -->|GamepadConnection, GamepadButton, GamepadAxis| Events
    Events --> P[bevy_input::ButtonInput / Axis update]
    P --> User[User systems]
    Events --> Focus[bevy_input_focus]
    Focus --> User
    Events --> Picking[bevy_picking]
    Picking --> User

The data crate is bevy_input. Backends are bevy_winit (windowing/keyboard/mouse/touch) and bevy_gilrs (gamepads).

Reading input

Two patterns:

Per-frame state

fn move_player(
    keys: Res<ButtonInput<KeyCode>>,
    mouse: Res<ButtonInput<MouseButton>>,
) {
    if keys.pressed(KeyCode::KeyW) { /* … */ }
    if keys.just_pressed(KeyCode::Space) { /* … */ }
    if mouse.just_released(MouseButton::Left) { /* … */ }
}

ButtonInput<T> is updated each frame by bevy_input from the raw events. pressed, just_pressed, just_released are the canonical API.

Raw events

fn on_keystrokes(mut events: EventReader<KeyboardInput>) {
    for event in events.read() { /* … */ }
}

Use raw events when you need character data (text input), repeat-rate handling, or precise temporal ordering. The KeyboardInput event carries both KeyCode (physical key, position-independent) and Key (logical key, layout-dependent).

Mouse

  • Res<ButtonInput<MouseButton>> for buttons.
  • EventReader<MouseMotion> for relative motion (delta).
  • EventReader<MouseWheel> for scroll deltas.
  • Window::cursor_position() for absolute position within a window.

Touch

Res<Touches> collates active touches keyed by ID. EventReader<TouchInput> gets per-event detail (start, move, end, cancel).

Gamepads

Gamepads are entities, not resources. When bevy_gilrs detects a connection, it spawns a Gamepad entity with GamepadInfo and per-button/axis components.

fn read_pads(
    pads: Query<(&Gamepad, &GamepadInfo)>,
    buttons: Query<&ButtonInput<GamepadButton>>,
) {
    for (pad, info) in &pads {
        let pressed = buttons.get(pad.entity).unwrap().pressed(GamepadButton::South);
        // …
    }
}

This entity-based design supports multiple controllers natively — each pad is a different entity.

Focus

bevy_input_focus decides which entity receives keyboard input. UI widgets register Observer<KeyboardInput> on themselves; the dispatch system bubbles events up the focus chain. See UI for the widget angle.

Picking

bevy_picking translates pointer position + camera into entity hits and dispatches Pointer<Click> / Pointer<Drag> / Pointer<Hover> events. See Picking.

Common pitfalls

  • KeyCode vs Key — use KeyCode for "the W key" semantics (physical layout-independent) and Key for "the character was 'a'" (layout-aware text input).
  • mouse.just_pressed returns nothing — check that no RunCondition is filtering the system out and that bevy_input::InputPlugin is in your plugin chain.
  • Multiple gamepads but only one responding — your code is reading from Gamepad::new(0) instead of querying all Gamepad entities.
  • Text input lossy — you're reading KeyCode. Use KeyboardInput::logical_key (which is Key) for text.

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Input – Bevy wiki | Factory