stickup 0.2.0

A modular input device abstraction layer with HID and virtual device support.
Documentation

StickUp

๐Ÿš€ Update: v0.2.0 is here!
StickUp now supports full per-frame state snapshots, binding resolution ("joy0.axis1"), and cleaner device management via the new DeviceManager.
Built to scale with sim rigs, overlays, game engines, and beyond.

Already passed 500 downloads in 24 hours โ€” thank you to everyone testing and sharing it

Crates.io Downloads Join the Discord Buy Me a Coffee Follow on X


๐Ÿ” Security Note

The name stickup was previously used in 2023 for a malicious crate which has since been removed from crates.io. (I wasn't aware of this at the time of publishing.)

This version โ€” authored by Belegrade Studio โ€” is a clean and fully rewritten project, unrelated to the original.

โœ… No build.rs
โœ… No network activity
โœ… 100% open and auditable

Transparency and trust matter. You're welcome to inspect the source or reach out directly


StickUp is a modular, high-performance input framework for Rust.
It supports both HID and virtual devices with precision, persistence, and clarity.

Created by Belegrade Studio as part of the CelerisTech stack.


โœจ Features

  • ๐Ÿ”Œ Plug-and-play device management via DeviceManager
  • ๐ŸŽฎ Unified Device trait for axis + button input
  • ๐Ÿง  Persistent device identity (hardware fingerprint)
  • ๐Ÿงฐ Binding resolution like "joy0.axis1" โ†’ Option<f32>
  • ๐Ÿ” Per-frame polling and snapshot state tracking
  • ๐Ÿ”ง Hotplug-friendly and fully extendable
  • ๐Ÿ›  Supports hid and virtual backends via features
  • ๐Ÿ’ก Zero magic โ€” minimal, intentional design

๐Ÿ“ฆ Installation

stickup = { version = "0.2.0", features = ["hid", "virtual"] }

๐Ÿš€ Quick Start

use stickup::DeviceManager;

fn main() {
    let mut input = DeviceManager::new();
    input.snapshot(); // poll + build snapshot

    if let Some(throttle) = input.get_axis("joy0.throttle") {
        println!("Throttle: {:.2}", throttle);
    }

    if input.is_pressed("joy1.trigger") {
        println!("Trigger is pressed!");
    }
}

๐Ÿ“‹ Full Snapshot Example

let mut input = DeviceManager::new();
let state = input.snapshot();

for (id, device_state) in state.iter() {
    println!("Device: {id}");

    for (axis, value) in &device_state.axes {
        println!("  Axis {axis}: {value:.2}");
    }

    for (button, pressed) in &device_state.buttons {
        println!("  Button {button}: {}", if *pressed { "Pressed" } else { "Released" });
    }
}

๐Ÿงฌ Device Identity

StickUp assigns a stable, persistent ID to each device:

vendor_id:product_id:serial_number
# Example: 044f:0402:ABCD1234

๐Ÿ” Examples

Run any with:

cargo run --example <name>
  • poll โ€“ Print a full snapshot of all input state
  • virtual_demo โ€“ Feed input into a simulated virtual device

๐Ÿ› ๏ธ Optional Features

Feature Description
hid (default) Enables HID device support via hidapi
virtual Enables manually fed virtual devices

๐Ÿงญ Philosophy

StickUp is about presence, clarity, and persistence.
It doesn't guess. It doesn't simulate. It reflects exactly what your device is doing โ€” no more, no less.


๐Ÿ“œ License

This project is licensed under the Pact of the Amaranth Rite.
See LICENSE for details.

Third-Party Dependencies

StickUp uses the following libraries, each under permissive open source licenses:

  • hidapi โ€” MIT/Apache-2.0 (HID support)
  • serde โ€” MIT/Apache-2.0 (serialization)
  • serde_json โ€” MIT/Apache-2.0 (layout/config IO)
  • toml โ€” MIT/Apache-2.0 (if config parsing used)

๐Ÿ’ฌ Connect