angx1/bevy_apple_gamepad

Rust

2

5 commits

updated Oct 9, 2026

See the code

See what people are saying

README

⠀⠀⠀⠀⠀⠀⢸⡆⠀⣇⠀⣷⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠀⠀⠀⠀⠀⠀⠀⢻⣧⣄⠀⠀⠀⠀⠀⠀⠀⢠⣼⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣧⡀⠀⠀⠀⠀⠀⠀⠀⢰⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⢠⣼⠀⢸⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢸⣇⡀⣿⡆⠘⢻⣧⡄⠀⠀⠀⠀⠀⠀⠀⢸⡏⠀⠀⠀⠀⠀⠀⠀⠈⠹⢿⣧⡄⠀⠀⠀⠀⢠⣼⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢻⣧⡄⠀⠀⠀⠀⠀⢰⡿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⡇⠀⢠⣼⡏⠀⣸⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠘⢻⡇⢸⡇⠀⠘⢻⣷⡄⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣿⣦⡀⠀⢠⣾⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣧⡄⠀⠀⠀⢸⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣧⢀⣼⡏⠁⢰⣿⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣧⣼⡇⠀⠀⠀⠹⢿⣆⡀⠀⠀⠀⢀⣼⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢻⣷⣤⣾⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣧⡄⠀⣸⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣸⡟⠃⠀⢸⡇⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣿⣧⠀⠀⠀⠀⠘⢻⣧⡄⠀⠀⢸⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣤⣴⣿⣿⣿⣿⣿⣿⣿⣷⣶⣶⣶⣦⣤⣤⣤⣤⣤⣤⣤⣤⣈⣹⣧⣸⣟⣣⣤⣤⣤⣤⣤⣤⣴⣶⣶⣾⣿⣿⣿⣿⣿⡇⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢿⣿⠀⠀⠀⠀⠀⠈⢻⣷⡆⠀⢸⡇⠀⠀⠀⠀⢀⣠⣤⣴⣶⣿⣿⡿⠟⠛⠋⢹⣧⡈⠉⠉⠉⠙⠛⠛⠛⠛⠛⠛⠛⠻⠿⠿⠿⠿⣿⣿⣿⣿⣿⡿⠿⠿⠿⠟⠛⠛⠛⠛⠛⠋⠉⢩⣽⡟⠸⢿⡆⢠⣾⡇⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⠀⠀⠀⠸⢿⣧⣸⣇⣠⣤⣴⣾⣿⣿⠿⠛⠛⠋⠁⠀⠀⠀⠀⠈⢻⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣼⡿⠋⢹⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣼⡟⠁⠀⠸⢿⣾⡟⠀⠀⠀⠀⠀⠀⠀
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣀⣠⣤⣤⣤⣤⣤⣤⣾⣿⣿⣿⣿⡟⠛⠋⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣰⣾⡟⠋⠁⠀⠘⢻⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣾⠏⠀⠀⠀⠀⣸⣿⡇⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡿⠿⠟⠛⠛⠛⠛⠛⢻⣿⢿⣿⣧⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣾⡟⠋⠁⠀⠀⠀⠀⠸⣷⡄⠀⠀⠀⠀⠀⠀⢀⣸⡿⠃⠀⠀⢠⣴⣾⣿⠟⠃⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠻⢿⣧⣄⠀⠀⠀⠀⠀⠘⢻⡇⠘⠛⠻⢿⣷⣦⣤⡄⠀⠀⠀⠀⠀⠀⠀⠀⢸⣧⡀⠀⠀⠀⠀⠀⠀⢠⣴⣾⡟⠋⠀⠀⠀⠀⠀⠀⠀⠀⢸⣧⡀⠀⠀⠀⠀⢠⣼⡟⠃⢀⣠⣼⣿⡿⠟⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠹⢿⣧⣄⡀⠀⠀⠀⢸⣷⡄⠀⠀⠀⠙⠛⠻⣿⣷⣦⣤⡀⠀⠀⠀⠀⠈⢻⡇⠀⠀⠀⠀⢠⣴⣾⡟⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⡇⠀⠀⠀⢠⣼⡟⢡⣴⣾⣿⡿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⢻⣷⣄⡀⠀⠀⢸⣧⡀⠀⠀⠀⠀⠀⠈⠙⠛⢻⣿⣷⣦⣄⡀⠀⢸⣧⠀⠀⢠⣼⣿⡟⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢿⡆⠀⢰⣾⣯⣼⣿⣿⡿⠏⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⢻⣷⣦⡀⠘⢻⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠻⢿⣿⣷⣮⣿⣠⣼⣿⡟⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣧⣸⣿⣿⣿⣿⡿⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢻⣷⣦⡜⢿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣬⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢻⣿⣾⣧⠀⠀⢀⣠⣤⣤⣴⣾⣿⣿⡿⠿⠟⠛⠋⠉⠸⣷⡆⠈⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⢉⣩⣽⣿⣿⡟⣻⣿⣿⡟⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠻⣿⣾⣿⣿⣿⣿⣟⡛⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠸⢿⣆⠀⠀⠀⠀⠀⠀⠀⢀⣠⣴⣾⣿⣿⣿⣯⣥⣼⣿⡟⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠛⠛⠻⠿⢿⣿⣿⣿⣷⣶⣦⣤⣤⣤⣄⡀⠀⠀⠘⢿⣇⡀⠀⢀⣠⣤⣼⣿⣿⣿⣿⣿⣿⡿⠿⠟⠛⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠙⠛⠛⠻⠿⢿⣿⣿⣿⣷⣶⣾⣿⣧⣴⣿⣿⣿⣿⡿⠟⠛⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠙⠛⠛⠛⠿⠛⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

Gamepad support for Bevy on macOS through Apple's Game Controller framework.

Use it if your controller shows up as connected in Bevy on macOS but nothing happens when you press buttons or move the sticks (typical with Xbox controllers on macOS 14+):

INFO bevy_input::gamepad: Gamepad 450v0 connected.
WARN gilrs::gamepad: No mapping found for UUID 03000000-5e04-0000-ea02-000014050000

Why this happens

  • Bevy reads gamepads with gilrs, which on macOS uses the low-level IOKit HID API.
  • Since macOS 14, controllers handled by Apple's Game Controller framework (e.g. Xbox controllers) don't deliver input through IOKit. gilrs sees the device connect, but never receives events (see gilrs issues #148 and #150).
  • Apple provides a compatibility layer ("Increase controller compatibility" in System Settings → Game Controllers, per app) that exposes a synthetic Xbox 360 HID device (Apple docs), but gilrs 0.11 / gilrs-core 0.6.8 skips it: the synthetic device has no LocationID (Failed to get location id of device … Skipping).

This crate reads controllers with the Game Controller framework (the API Apple recommends, and the one browsers use, which is why the web gamepad viewer works while the native one doesn't) and feeds them into Bevy's standard gamepad pipeline: it writes the same raw events bevy_gilrs writes. So everything else works unchanged: the Gamepad component, GamepadSettings dead zones, pressed / just_pressed, left_stick(), etc.

No app bundle and no system setting is needed.

Usage

[dependencies]
bevy = "0.20"
bevy_apple_gamepad = { path = "crates/bevy_apple_gamepad" } # or git / crates.io once published
use bevy::prelude::*;
use bevy_apple_gamepad::AppleGamepadPlugin;

fn main() {
    let mut app = App::new();

    // On macOS, replace gilrs (otherwise you get a second gamepad that never moves).
    #[cfg(target_os = "macos")]
    app.add_plugins(DefaultPlugins.build().disable::<bevy::gilrs::GilrsPlugin>());
    #[cfg(not(target_os = "macos"))]
    app.add_plugins(DefaultPlugins);

    // No-op on other platforms, so it's safe to add unconditionally.
    app.add_plugins(AppleGamepadPlugin::default());
    app.run();
}

Then read gamepads the usual Bevy way:

fn read_gamepads(gamepads: Query<&Gamepad>) {
    for gamepad in &gamepads {
        let movement = gamepad.left_stick();
        if gamepad.just_pressed(GamepadButton::South) {
            // jump!
        }
    }
}

Options

AppleGamepadPlugin {
    // macOS only delivers controller input to the focused app; set this to keep reading it
    // while the window is in the background.
    monitor_background_events: true,
}

Button mapping

Bevy names buttons by position. With Xbox labels:

ControllerBevy GamepadButton / GamepadAxis
A / B / X / YSouth / East / West / North
LB / RBLeftTrigger / RightTrigger
LT / RT (analog)LeftTrigger2 / RightTrigger2
View / Menu / XboxSelect / Start / Mode
Stick clicksLeftThumb / RightThumb
D-padDPadUp / DPadDown / DPadLeft / DPadRight
SticksLeftStickX/Y, RightStickX/Y (up = positive Y)

Tested with an Xbox controller over USB on macOS 15 (Sequoia). Any controller the framework exposes with the standard "extended gamepad" layout (PlayStation, Switch Pro, MFi…) should work the same way, mapped by position, but hasn't been tested yet: reports welcome.

How it works

One system runs every frame in PreUpdate (before InputSystems, like bevy_gilrs) on the main thread (NonSendMarker):

  1. Reads GCController.controllers().
  2. New controllers → spawns an entity and writes GamepadConnectionEvent::Connected.
  3. For each button / axis whose value changed → writes RawGamepadButtonChangedEvent / RawGamepadAxisChangedEvent (also wrapped in RawGamepadEvent).
  4. Controllers that disappeared → GamepadConnectionEvent::Disconnected.

Bevy's own gamepad_event_processing_system turns those into the Gamepad component.

Limitations

  • macOS only (other Apple platforms aren't wired up yet).
  • No rumble / haptics, battery, lights, touchpad or motion sensors yet.
  • vendor_id / product_id are None (the framework doesn't expose them).
  • Only controllers with the extended gamepad profile are reported.

Compatibility

bevy_apple_gamepadBevy
0.10.20

License

Dual-licensed under MIT or Apache-2.0, at your option (same as Bevy).

angx1/bevy_apple_gamepad

Rust

2

5 commits

updated Oct 9, 2026

See the code

See what people are saying

README

⠀⠀⠀⠀⠀⠀⢸⡆⠀⣇⠀⣷⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠀⠀⠀⠀⠀⠀⠀⢻⣧⣄⠀⠀⠀⠀⠀⠀⠀⢠⣼⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣧⡀⠀⠀⠀⠀⠀⠀⠀⢰⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⢠⣼⠀⢸⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢸⣇⡀⣿⡆⠘⢻⣧⡄⠀⠀⠀⠀⠀⠀⠀⢸⡏⠀⠀⠀⠀⠀⠀⠀⠈⠹⢿⣧⡄⠀⠀⠀⠀⢠⣼⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢻⣧⡄⠀⠀⠀⠀⠀⢰⡿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⡇⠀⢠⣼⡏⠀⣸⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠘⢻⡇⢸⡇⠀⠘⢻⣷⡄⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣿⣦⡀⠀⢠⣾⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣧⡄⠀⠀⠀⢸⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣧⢀⣼⡏⠁⢰⣿⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣧⣼⡇⠀⠀⠀⠹⢿⣆⡀⠀⠀⠀⢀⣼⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢻⣷⣤⣾⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣧⡄⠀⣸⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣸⡟⠃⠀⢸⡇⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣿⣧⠀⠀⠀⠀⠘⢻⣧⡄⠀⠀⢸⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣤⣴⣿⣿⣿⣿⣿⣿⣿⣷⣶⣶⣶⣦⣤⣤⣤⣤⣤⣤⣤⣤⣈⣹⣧⣸⣟⣣⣤⣤⣤⣤⣤⣤⣴⣶⣶⣾⣿⣿⣿⣿⣿⡇⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢿⣿⠀⠀⠀⠀⠀⠈⢻⣷⡆⠀⢸⡇⠀⠀⠀⠀⢀⣠⣤⣴⣶⣿⣿⡿⠟⠛⠋⢹⣧⡈⠉⠉⠉⠙⠛⠛⠛⠛⠛⠛⠛⠻⠿⠿⠿⠿⣿⣿⣿⣿⣿⡿⠿⠿⠿⠟⠛⠛⠛⠛⠛⠋⠉⢩⣽⡟⠸⢿⡆⢠⣾⡇⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⠀⠀⠀⠸⢿⣧⣸⣇⣠⣤⣴⣾⣿⣿⠿⠛⠛⠋⠁⠀⠀⠀⠀⠈⢻⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣼⡿⠋⢹⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣼⡟⠁⠀⠸⢿⣾⡟⠀⠀⠀⠀⠀⠀⠀
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣀⣠⣤⣤⣤⣤⣤⣤⣾⣿⣿⣿⣿⡟⠛⠋⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣰⣾⡟⠋⠁⠀⠘⢻⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣾⠏⠀⠀⠀⠀⣸⣿⡇⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡿⠿⠟⠛⠛⠛⠛⠛⢻⣿⢿⣿⣧⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣾⡟⠋⠁⠀⠀⠀⠀⠸⣷⡄⠀⠀⠀⠀⠀⠀⢀⣸⡿⠃⠀⠀⢠⣴⣾⣿⠟⠃⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠻⢿⣧⣄⠀⠀⠀⠀⠀⠘⢻⡇⠘⠛⠻⢿⣷⣦⣤⡄⠀⠀⠀⠀⠀⠀⠀⠀⢸⣧⡀⠀⠀⠀⠀⠀⠀⢠⣴⣾⡟⠋⠀⠀⠀⠀⠀⠀⠀⠀⢸⣧⡀⠀⠀⠀⠀⢠⣼⡟⠃⢀⣠⣼⣿⡿⠟⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠹⢿⣧⣄⡀⠀⠀⠀⢸⣷⡄⠀⠀⠀⠙⠛⠻⣿⣷⣦⣤⡀⠀⠀⠀⠀⠈⢻⡇⠀⠀⠀⠀⢠⣴⣾⡟⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⡇⠀⠀⠀⢠⣼⡟⢡⣴⣾⣿⡿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⢻⣷⣄⡀⠀⠀⢸⣧⡀⠀⠀⠀⠀⠀⠈⠙⠛⢻⣿⣷⣦⣄⡀⠀⢸⣧⠀⠀⢠⣼⣿⡟⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢿⡆⠀⢰⣾⣯⣼⣿⣿⡿⠏⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⢻⣷⣦⡀⠘⢻⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠻⢿⣿⣷⣮⣿⣠⣼⣿⡟⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣧⣸⣿⣿⣿⣿⡿⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢻⣷⣦⡜⢿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣬⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢻⣿⣾⣧⠀⠀⢀⣠⣤⣤⣴⣾⣿⣿⡿⠿⠟⠛⠋⠉⠸⣷⡆⠈⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⢉⣩⣽⣿⣿⡟⣻⣿⣿⡟⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠻⣿⣾⣿⣿⣿⣿⣟⡛⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠸⢿⣆⠀⠀⠀⠀⠀⠀⠀⢀⣠⣴⣾⣿⣿⣿⣯⣥⣼⣿⡟⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠛⠛⠻⠿⢿⣿⣿⣿⣷⣶⣦⣤⣤⣤⣄⡀⠀⠀⠘⢿⣇⡀⠀⢀⣠⣤⣼⣿⣿⣿⣿⣿⣿⡿⠿⠟⠛⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠙⠛⠛⠻⠿⢿⣿⣿⣿⣷⣶⣾⣿⣧⣴⣿⣿⣿⣿⡿⠟⠛⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠙⠛⠛⠛⠿⠛⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

Gamepad support for Bevy on macOS through Apple's Game Controller framework.

Use it if your controller shows up as connected in Bevy on macOS but nothing happens when you press buttons or move the sticks (typical with Xbox controllers on macOS 14+):

INFO bevy_input::gamepad: Gamepad 450v0 connected.
WARN gilrs::gamepad: No mapping found for UUID 03000000-5e04-0000-ea02-000014050000

Why this happens

  • Bevy reads gamepads with gilrs, which on macOS uses the low-level IOKit HID API.
  • Since macOS 14, controllers handled by Apple's Game Controller framework (e.g. Xbox controllers) don't deliver input through IOKit. gilrs sees the device connect, but never receives events (see gilrs issues #148 and #150).
  • Apple provides a compatibility layer ("Increase controller compatibility" in System Settings → Game Controllers, per app) that exposes a synthetic Xbox 360 HID device (Apple docs), but gilrs 0.11 / gilrs-core 0.6.8 skips it: the synthetic device has no LocationID (Failed to get location id of device … Skipping).

This crate reads controllers with the Game Controller framework (the API Apple recommends, and the one browsers use, which is why the web gamepad viewer works while the native one doesn't) and feeds them into Bevy's standard gamepad pipeline: it writes the same raw events bevy_gilrs writes. So everything else works unchanged: the Gamepad component, GamepadSettings dead zones, pressed / just_pressed, left_stick(), etc.

No app bundle and no system setting is needed.

Usage

[dependencies]
bevy = "0.20"
bevy_apple_gamepad = { path = "crates/bevy_apple_gamepad" } # or git / crates.io once published
use bevy::prelude::*;
use bevy_apple_gamepad::AppleGamepadPlugin;

fn main() {
    let mut app = App::new();

    // On macOS, replace gilrs (otherwise you get a second gamepad that never moves).
    #[cfg(target_os = "macos")]
    app.add_plugins(DefaultPlugins.build().disable::<bevy::gilrs::GilrsPlugin>());
    #[cfg(not(target_os = "macos"))]
    app.add_plugins(DefaultPlugins);

    // No-op on other platforms, so it's safe to add unconditionally.
    app.add_plugins(AppleGamepadPlugin::default());
    app.run();
}

Then read gamepads the usual Bevy way:

fn read_gamepads(gamepads: Query<&Gamepad>) {
    for gamepad in &gamepads {
        let movement = gamepad.left_stick();
        if gamepad.just_pressed(GamepadButton::South) {
            // jump!
        }
    }
}

Options

AppleGamepadPlugin {
    // macOS only delivers controller input to the focused app; set this to keep reading it
    // while the window is in the background.
    monitor_background_events: true,
}

Button mapping

Bevy names buttons by position. With Xbox labels:

ControllerBevy GamepadButton / GamepadAxis
A / B / X / YSouth / East / West / North
LB / RBLeftTrigger / RightTrigger
LT / RT (analog)LeftTrigger2 / RightTrigger2
View / Menu / XboxSelect / Start / Mode
Stick clicksLeftThumb / RightThumb
D-padDPadUp / DPadDown / DPadLeft / DPadRight
SticksLeftStickX/Y, RightStickX/Y (up = positive Y)

Tested with an Xbox controller over USB on macOS 15 (Sequoia). Any controller the framework exposes with the standard "extended gamepad" layout (PlayStation, Switch Pro, MFi…) should work the same way, mapped by position, but hasn't been tested yet: reports welcome.

How it works

One system runs every frame in PreUpdate (before InputSystems, like bevy_gilrs) on the main thread (NonSendMarker):

  1. Reads GCController.controllers().
  2. New controllers → spawns an entity and writes GamepadConnectionEvent::Connected.
  3. For each button / axis whose value changed → writes RawGamepadButtonChangedEvent / RawGamepadAxisChangedEvent (also wrapped in RawGamepadEvent).
  4. Controllers that disappeared → GamepadConnectionEvent::Disconnected.

Bevy's own gamepad_event_processing_system turns those into the Gamepad component.

Limitations

  • macOS only (other Apple platforms aren't wired up yet).
  • No rumble / haptics, battery, lights, touchpad or motion sensors yet.
  • vendor_id / product_id are None (the framework doesn't expose them).
  • Only controllers with the extended gamepad profile are reported.

Compatibility

bevy_apple_gamepadBevy
0.10.20

License

Dual-licensed under MIT or Apache-2.0, at your option (same as Bevy).