Skip to main content

A Python library for game controller input handling

Project description

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)。未来可按需扩展到其他平台。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fly_stick-0.1.0.tar.gz (22.5 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

fly_stick-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (833.8 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

fly_stick-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (836.3 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

File details

Details for the file fly_stick-0.1.0.tar.gz.

File metadata

  • Download URL: fly_stick-0.1.0.tar.gz
  • Upload date:
  • Size: 22.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.14.1

File hashes

Hashes for fly_stick-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d55bbac86b39221f49e85339fbe10db19324710880faf8f6dc53358c821afaf9
MD5 f616429aedf09d758ce489ae7e585b64
BLAKE2b-256 562ee628e7264a27e18d420f7a418db4a9be8ded72661e28a6547885be9877b7

See more details on using hashes here.

File details

Details for the file fly_stick-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for fly_stick-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a8ab11242f8ca5102f7072458bd55191d5ab26ea4a666e1a16a2f82f0efa56f5
MD5 c6fede1c362c7583bdddec66894910f6
BLAKE2b-256 ef31a474b8aae252d329e588914a39c05d778a987a91051681554132550e4527

See more details on using hashes here.

File details

Details for the file fly_stick-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for fly_stick-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 5d28ba8d797b970f944d03153715f4812f1f4c71dbc284eaf6c5a0c8622bde20
MD5 4c06ae77d561efb95330e6d7041c03b4
BLAKE2b-256 bcec52691c7c7ca3ab332b9bc6b118d1959f8ba5f7baff9493a0c3f09f171c08

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page