一个基于 Rust 和 PyO3 构建的高性能 Python 库,专门用于处理游戏控制器(操纵杆/手柄)输入设备。该库使用 Linux evdev 接口提供低延迟的设备监控和状态读取能力,特别适用于飞行模拟器等实时输入场景。
- 🎮 多设备支持 - 同时监控多个游戏控制器设备
- ⚡ 高性能核心 - Rust 底层实现,提供毫秒级响应
- 🔄 异步/非阻塞双模式 - 支持
await fetch()与fetch_nowait() - 📊 设备池管理 - 统一管理多设备,读取逻辑设备状态
- 🛠️ TOML 配置 - 基于 TOML 的设备描述文件
- 🐍 完整 Python API - 直接从
fly_stick包导入核心类型 - 🎯 按钮模式控制 - 支持
trigger与hold两种按钮处理模式 - 📈 实时状态监控 - 轴、按钮、帽子开关状态实时更新
- Linux 系统(依赖 evdev)
- Python 3.10+
- Rust(仅开发或源码构建时需要)
# 克隆仓库
git clone https://github.com/WindLX/fly_stick.git
cd fly_stick
# 安装构建依赖
pip install maturin
# 构建并安装到当前 Python 环境
maturin developuv sync
uv run maturin developimport 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: 轴配置列表,包含code与aliasbuttons: 按钮配置列表,包含code与aliashats: 帽子开关配置列表,包含code与alias
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(属性,可读写)
JoystickInfo(path,name)JoystickState(axes,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)DeviceDescriptionDeviceDescription.from_toml(toml_file)DeviceDescription.build_state()DeviceItemDeviceButtonMode.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.tomldevices/Thrustmaster/twcs.tomldevices/Thrustmaster/t16000m.tomldevices/Thrustmaster/tca_qeng.tomldevices/Thrustmaster/twcs_with_tfrp.tomldevices/Microsoft X-Box 360/pad.tomldevices/Microsoft X-Box 360/series_sx.toml
项目提供了设备按键映射图:
figures/Thrustmaster_TA320_Copilot.drawio.pngfigures/Thrustmaster_TWCS_Throttle.drawio.pngfigures/Thrustmaster T.16000M.drawio.pngfigures/Thrustmaster T.Flight Rudder Pedals.drawio.pngfigures/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 提供内存安全保障
-
alias支持 - 按钮触发逻辑优化
本项目采用 MIT 许可证,详见 LICENSE。
欢迎提交 Issue 和 Pull Request。
建议在提交前完成:
- 代码风格自检
- 必要测试补充
- 文档同步更新
- windlx - 初始开发 - https://github.com/WindLX
注意:该库当前仅支持 Linux(evdev)。未来可按需扩展到其他平台。