Skip to main content

fly-stick

一个基于 Rust 和 PyO3 构建的高性能 Python 库,专门用于处理游戏控制器(操纵杆/手柄)输入设备。该库使用 Linux evdev 接口提供低延迟的设备监控和状态读取能力,特别适用于飞行模拟器等实时输入场景。

特性

  • 🎮 多设备支持 - 同时监控多个游戏控制器设备
  • 高性能核心 - Rust 底层实现,提供毫秒级响应
  • 🔄 异步/非阻塞双模式 - 支持 await fetch()fetch_nowait()
  • 📊 设备池管理 - 统一管理多设备,读取逻辑设备状态
  • 🛠️ TOML 配置 - 基于 TOML 的设备描述文件
  • 🐍 完整 Python API - 直接从 fly_stick 包导入核心类型
  • 🎯 按钮模式控制 - 支持 triggerhold 两种按钮处理模式
  • 📈 实时状态监控 - 轴、按钮、帽子开关状态实时更新

安装

系统要求

  • Linux 系统(依赖 evdev)
  • Python 3.10+
  • Rust(仅开发或源码构建时需要)

从源码构建

# 克隆仓库
git clone https://github.com/WindLX/fly_stick.git
cd fly_stick

# 安装构建依赖
pip install maturin

# 构建并安装到当前 Python 环境
maturin develop

使用 uv(推荐)

uv sync
uv run maturin develop

快速开始

单设备监控

import asyncio
import fly_stick


async def monitor_single_device():
    devices = fly_stick.fetch_connected_joysticks()
    if not devices:
        print("未找到设备")
        return

    dev = devices[0]
    joystick = fly_stick.PyJoystick(dev.path)

    print(f"监控设备: {dev.name} @ {dev.path}")

    while True:
        try:
            state = joystick.get_state()
            print(state.to_dict())
            await asyncio.sleep(0.01)
        except KeyboardInterrupt:
            break


asyncio.run(monitor_single_device())

设备池异步监控

import asyncio
from fly_stick import PyDevicePool, DeviceDescription, DeviceButtonMode


async def monitor_device_pool():
    pool = PyDevicePool(
        device_descs={
            "ta320": DeviceDescription.from_toml("devices/Thrustmaster/ta320.toml"),
            "twcs": DeviceDescription.from_toml("devices/Thrustmaster/twcs.toml"),
        },
        debounce_seconds=0.1,
        btn_mode=DeviceButtonMode.hold(),
    )

    # 使用设备池前先初始化监控
    await pool.reset()

    print("开始监控设备池...")

    while True:
        try:
            states = await pool.fetch(timeout_seconds=1.0)
            for device_name, state in states.items():
                print(f"{device_name}: {state.to_dict()}")
        except KeyboardInterrupt:
            print("停止监控")
            await pool.stop()
            break


asyncio.run(monitor_device_pool())

设备池非阻塞读取

import asyncio
from fly_stick import PyDevicePool, DeviceDescription


async def monitor_nowait():
    pool = PyDevicePool(
        device_descs={
            "ta320": DeviceDescription.from_toml("devices/Thrustmaster/ta320.toml"),
            "twcs": DeviceDescription.from_toml("devices/Thrustmaster/twcs.toml"),
        },
        debounce_seconds=0.1,
    )

    await pool.reset()

    try:
        while True:
            states = pool.fetch_nowait()
            for name, state in states.items():
                print(f"{name}: 轴={state.axes}, 按钮={state.buttons}, 帽子={state.hats}")
            await asyncio.sleep(0.01)
    except KeyboardInterrupt:
        await pool.stop()


asyncio.run(monitor_nowait())

设备配置

DevicePool 的设备配置使用 TOML 格式描述,此描述文件约束了哪些按键才会被监控和记录数据。例如 devices/Thrustmaster/ta320.toml

device_name = "Thrustmaster T.A320 Copilot"
author = "WindLX"
created = "2025-01-14"
description = "Thrustmaster T.A320 Copilot Device Description File"

[[axes]]
code = 0
alias = "ABS_X"

[[axes]]
code = 1
alias = "ABS_Y"

[[buttons]]
code = 288
alias = "BTN_TRIGGER"

[[hats]]
code = 16
alias = "ABS_HAT0X"

配置文件说明

  • device_name: 设备显示名称(用于匹配系统设备名)
  • author: 配置文件作者(可选)
  • created: 创建日期(可选)
  • description: 设备描述(可选)
  • axes: 轴配置列表,包含 codealias
  • buttons: 按钮配置列表,包含 codealias
  • hats: 帽子开关配置列表,包含 codealias

API 参考

核心函数

  • fetch_connected_joysticks() - 获取当前连接的输入设备列表

核心类

  • PyJoystick(device_path)
  • PyJoystick.get_state()
  • PyDevicePool(device_descs, debounce_seconds=0.1, btn_mode=DeviceButtonMode.hold())
  • PyDevicePool.reset()
  • PyDevicePool.fetch(timeout_seconds=None)
  • PyDevicePool.fetch_nowait()
  • PyDevicePool.stop()
  • PyDevicePool.devices(属性)
  • PyDevicePool.debounce_time(属性)
  • PyDevicePool.button_mode(属性,可读写)

数据结构

  • JoystickInfopath, name
  • JoystickStateaxes, buttons, hats
  • JoystickState.to_dict()
  • JoystickState.to_alias_dict(desc)
  • JoystickState.get_alias_axes(desc)
  • JoystickState.get_alias_buttons(desc)
  • JoystickState.get_alias_hats(desc)
  • DeviceDescription
  • DeviceDescription.from_toml(toml_file)
  • DeviceDescription.build_state()
  • DeviceItem
  • DeviceButtonMode.trigger()
  • DeviceButtonMode.hold()

注意:使用 PyDevicePool.fetch()fetch_nowait() 前,需先调用 await reset()

示例

项目包含多个示例文件:

  • examples/single_device.py - 单设备异步监控
  • examples/multi_device.py - 多设备异步监控
  • examples/device_pool.py - 设备池非阻塞读取
  • examples/device_pool_block.py - 设备池阻塞读取
  • examples/alias.py - 按别名读取轴状态
  • examples/btn_mode.py - 按钮触发模式示例

支持的设备

目前仓库内提供了以下设备描述文件:

  • devices/Thrustmaster/ta320.toml
  • devices/Thrustmaster/twcs.toml
  • devices/Thrustmaster/t16000m.toml
  • devices/Thrustmaster/tca_qeng.toml
  • devices/Thrustmaster/twcs_with_tfrp.toml
  • devices/Microsoft X-Box 360/pad.toml
  • devices/Microsoft X-Box 360/series_sx.toml

设备映射图

项目提供了设备按键映射图:

  • figures/Thrustmaster_TA320_Copilot.drawio.png
  • figures/Thrustmaster_TWCS_Throttle.drawio.png
  • figures/Thrustmaster T.16000M.drawio.png
  • figures/Thrustmaster T.Flight Rudder Pedals.drawio.png
  • figures/Thrustmaster TCA Q-Eng 1&2.drawio.png

开发

项目结构

fly_stick/
├── src/
│   ├── lib.rs
│   ├── utils.rs
│   ├── inner/
│   │   ├── description.rs
│   │   ├── device_pool.rs
│   │   ├── joystick.rs
│   │   └── mod.rs
│   ├── wrapper/
│   │   ├── device_pool_wrapper.rs
│   │   ├── joystick_wrapper.rs
│   │   └── mod.rs
│   └── fly_stick/
│       ├── __init__.py
│       └── _core.pyi
├── examples/
├── devices/
├── figures/
├── Cargo.toml
└── pyproject.toml

构建与测试

# Rust 单元测试
cargo test

# Python 测试(如项目中提供测试用例)
pytest

# 构建发布 wheel
maturin build --release

性能特性

  • 低延迟: Rust 核心实现,输入处理延迟低
  • 按钮模式控制: 支持 Trigger/Hold 两种按钮语义
  • 非阻塞读取: 可使用 fetch_nowait() 做高频轮询
  • 内存安全: Rust 提供内存安全保障

TODO

  • alias 支持
  • 按钮触发逻辑优化

许可证

本项目采用 MIT 许可证,详见 LICENSE

贡献

欢迎提交 Issue 和 Pull Request。

建议在提交前完成:

  1. 代码风格自检
  2. 必要测试补充
  3. 文档同步更新

作者


注意:该库当前仅支持 Linux(evdev)。未来可按需扩展到其他平台。

Release files for fly-stick 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fly-stick 0.1.0
File Size Uploaded
fly_stick-0.1.0.tar.gz 22.5 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for fly-stick 0.1.0
File Interpreter ABI Platform
fly_stick-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details
fly_stick-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details

Total release size: 24.1 MB

Release files / fly_stick-0.1.0.tar.gz

Download URL fly_stick-0.1.0.tar.gz
Size 22.5 MB
Tags Source
SHA-256 checksum
How to use checksums
d55bbac86b39221f49e85339fbe10db19324710880faf8f6dc53358c821afaf9
BLAKE2b-256 checksum
How to use checksums
562ee628e7264a27e18d420f7a418db4a9be8ded72661e28a6547885be9877b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via maturin/1.14.1

Release files / fly_stick-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL fly_stick-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 833.8 kB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
a8ab11242f8ca5102f7072458bd55191d5ab26ea4a666e1a16a2f82f0efa56f5
BLAKE2b-256 checksum
How to use checksums
ef31a474b8aae252d329e588914a39c05d778a987a91051681554132550e4527
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via maturin/1.14.1

Release files / fly_stick-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL fly_stick-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 836.3 kB
Tags CPython 3.9 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
5d28ba8d797b970f944d03153715f4812f1f4c71dbc284eaf6c5a0c8622bde20
BLAKE2b-256 checksum
How to use checksums
bcec52691c7c7ca3ab332b9bc6b118d1959f8ba5f7baff9493a0c3f09f171c08
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via maturin/1.14.1

Release history Release notifications | RSS feed

This release

0.1.0 This release

3 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page