broroeror/gamesir-PenGUIcken

GitHub: broroeror/gamesir-PenGUIcken

逆向工程的 GameSir Cyclone 2 手柄 Linux GUI 控制工具,提供完整的输入诊断、配置编辑、灯光控制和备份恢复功能。

Stars: 0 | Forks: 0

# GameSir Cyclone 2 — Linux 控制应用 这是一款适用于 GameSir Cyclone 2 手柄的 Linux GUI,通过手柄的 vendor (hidraw) 接口进行通信,协议完全从零开始逆向工程得出。涵盖功能: - **实时输入视图** — 摇杆、扳机、所有按键(包括 L4/R4/M/Home/ Share 额外按键)、方向键、电池电量及充电状态、固件版本,以及模式警告。 - **配置文件** — 读取活动配置文件并进行切换 (1–4);震动测试。 - **灯光** — 独立 RGB 控制、捕捉到的预设效果、亮度/速度, 音频响应 / 拿起唤醒 / 休眠超时,以及**自定义关键帧 动画编辑器**(添加/删除关键帧、随机化、播放/暂停)。 - **配置编辑器** — 死区、抗死区、摇杆轨迹、灵敏度 曲线(预设**及**可拖动的自定义曲线编辑器)、扳机调节 (微动扳机 + 响应曲线)、震动、回报率以及按键重映射。 - **备份 / 恢复** — 将所有 4 个配置文件及灯光设置快照为 JSON 文件, 并可在日后写回。 - **鼠标模式切换** — 直接在应用中关闭(普通手柄)或开启 KDE/KWin 的“手柄控制光标”行为 (摇杆作为光标的“客厅模式”),此外还提供适用于非 KDE 环境的 EVIOCGRAB 备选方案(Wayland;见状态)。 ![status: input, battery, profiles, RGB + keyframes, full config editor, remap, and JSON backup/restore working] **版本:** `0.1.0-alpha.1` — 一个已知稳定的基线版本(git tag `v0.1.0-alpha.1`)。 剩余的 bug、提议的更改以及待解决的逆向工程问题位于 **[TODO.md](TODO.md)** — 一个持续更新的清单。这是一个业余的逆向工程 项目;你可以随意 fork 并进行自定义。 ## 环境要求 - Python 3 - [`hidapi`](https://pypi.org/project/hidapi/) (`import hid`) - [`dearpygui`](https://pypi.org/project/dearpygui/) - `xrandr` (可选;仅用于将窗口放置在主显示器上) ``` pip install hidapi dearpygui ``` ## 运行说明 手柄必须处于 **Xbox / XInput 模式(按住绿色按键约 2 秒)** — 该 vendor 协议在 PS4/DS4 和 Switch 模式下是无效的。当手柄未处于 Xbox 模式时, 应用会在顶部标题栏发出警告。 **推荐方式 — 无需 `sudo`。** 安装随附的 udev 规则(仅需一次),以便您的 用户可以直接打开手柄的 `hidraw` 节点(及其 `input` 事件 节点,用于下文的鼠标模式修复)— 该规则专门限定于 GameSir 的 USB vendor id,不涉及 其他设备。请**在仓库目录下**(即 `70-gamesir.rules` 所在位置)运行此命令: ``` sudo cp 70-gamesir.rules /etc/udev/rules.d/ sudo udevadm control --reload-rules && sudo udevadm trigger ``` 然后运行(无需重新插拔 — 触发器会重新应用访问 ACL): ``` python3 gamesir_gui.py ``` 该规则使用 `TAG+="uaccess"`,这将授予权限给 本地桌面登录的用户。**前缀 `70-` 非常重要**:udev 会按文件名顺序执行规则, 而实际应用 `uaccess` ACL 的是 `73-seat-late.rules` — 编号为 `73`+ 的规则设置 tag 太晚,导致 ACL 永远无法静默授予。在 没有本地 seat 的无头/远程机器上,`uaccess` 不起作用;请改用 group (`MODE="0660", GROUP="input"`)并将自己添加到该组中。 要确认是否生效,手柄的节点应显示您的 ACL: `getfacl /dev/hidraw0` → 应包含一行 `user::rw-`。 **备选方式 — 使用 `sudo`。** 如果您不想安装规则,由于 `hidraw` 节点默认属于 root 用户,请执行: ``` sudo python3 gamesir_gui.py ``` 请注意,在 `sudo` 下,`~` 会解析为 `/root`,因此默认的备份路径会 落入 `/root/` 中 — 这也是推荐使用 udev 规则方式的另一个原因。 ## 工作原理(协议说明) 该手柄暴露了一个 **vendor HID 接口**(USB VID `0x3537`),承载着 64 字节的命令/报告通道。以下所有操作均需在 **Xbox 模式**并保持 **持续的心跳信号**(每约 0.5 秒发送一次 `0x0F 0xF2`)。 - **输入**:增强型报告 `0x12` 流式传输摇杆、扳机、IMU、电池状态 (第 36 字节为百分比,第 35 字节 bit0 = 充电状态),以及标准 PS4 报告 无法读取的额外按键(第 60 字节中的 L4/R4/M/Home/Share)。 - **命令**(输出报告 `0x0F`,填充至 64 字节): - 心跳 `0F F2` - 获取/设置配置文件 `0F 0B` → `10 0C

` / `0F 07

` - 震动 `0F 20 66 55 ` - 读取寄存器 `0F 04 ` → `10 05 ` - 写入寄存器 `0F 03 ` - **灯光**位于寄存器 **bank `0x20`**: - `0x0000` = 活动槽位选择器 (0–3;同时也是 M+摇杆手势的可靠实时回读) - 槽位记录位于 `0x0001 + slot*0x7c` (124 字节):`[type, 05, param, brightness]` 随后是一系列 RGB 三元组调色板,渲染为重复的 **5-元组帧** - 帧位置 → 灯光:**0=左侧握把, 1=右侧握把, 2=(无 LED), 3=Profile, 4=Home**。纯色/单灯光颜色 = 类型 `0x01`,在整个记录中平铺一个相同的帧 (将尾部清零会使 Profile LED 熄灭)。 - 动态**效果预设**是从应用中捕获的特殊 `type` 字节 (`rgb_profiles_test.pcapng`):`0x05` Flow, `0x08` Rainbow, `0x02` Pulse, `0x06` Alarm, `0x01`+调色板 Standoff。原样存储在 `gamesir_led.py` (`PATTERNS`)中;`set_pattern` 会将其写入活动槽位, 并使用滑块覆盖亮度字节。 - **自定义关键帧动画**重用了 `0x05` 调色板引擎:记录 头部为 `[count, 0x05, speed, brightness]` — **字节 0 为关键帧 数量** (1–8),因此编辑器会在回读时恢复它。每个关键帧对应一帧 5-元组;`decode_record` 是 `set_keyframes` 的逆操作。 `gamesir_kf_cache.py` 会保存一份关于确切颜色/数量的本地副本,使得我们写入的槽位 能够完美往返,即使设备实际上只能存储 8 个平铺帧。 - **播放 / 暂停**当前运行动画的 vendor 命令为 `0F 0D `(从应用中捕获):字节 2 = `1` 播放 / `0` 暂停,字节 3 = **用于冻结的基于 1 的关键帧索引** — 因此暂停会停留在您当前查看的帧, 而不是跳转到第 1 帧。 - **固件版本**直接来自于 USB 设备描述符的 `bcdDevice`(hidapi 的 `release_number`),采用 BCD 编码的 `JJ.MN` 格式 — 无需 USB 命令或 网络调用。官方应用的 Info 按钮读取的也是相同的字段。 - **模式切换** (Xbox ↔ Switch ↔ PlayStation) 属于硬件按键组合, 会触发完整的 USB **重新枚举**,而不是可通过发送命令实现的操作。只有 Xbox 模式暴露了 vendor 通道;在其他模式下 `0x12` 流会全部变为零, 应用会将其检测为“未处于 Xbox 模式”。 注意事项:手柄**会丢弃紧随其他命令之后发送的命令** — 请拉开周期性查询的时间间隔(GUI 会交替执行它们)。 完整的硬件笔记保存在助手记忆库文件 `gamesir-vendor-interface-findings.md` 中。 ## 文件布局 **应用(运行时)** — GUI 被拆分为专注的模块: - `gamesir_gui.py` — 视图层:面板构建、逐帧更新、回调 - `gs_state.py` — 共享的实时 `state` 字典(零依赖) - `gamesir_reader.py` — 填充 `state` 的后台连接/读取循环 - `gamesir_control.py` — 命令通道:`send_cmd`、profile、rumble、寄存器读/写 - `gamesir_led.py` — 灯光域(bank `0x20`):`set_lights`、槽位选择、关键帧、恢复出厂设置 - `gamesir_config.py` — 每个配置文件的配置寄存器映射(死区 / 曲线 / 震动 / 回报率 …) - `gamesir_backup.py` — 全设置导出/恢复:读取所有 profile + 灯光信息,(反)序列化 JSON - `gamesir_kf_cache.py` — 每个槽位确切关键帧颜色/数量的本地缓存(在配置文件切换期间作为权威来源) - `gamesir_mousegrab.py` — 抑制模拟的鼠标/键盘 (EVIOCGRAB),用于鼠标模式修复 - `gamesir_window.py` — 视口放置(xrandr 主显示器几何形状;X11/XWayland) - `gs_common.py` — vendor 接口发现 + 助手功能(包括固件/`bcdDevice` 读取) - `gamesir_enhanced.py` — `0x12` 增强型报告解析器 - `gamesir_led_factory.py` — 捕获的“恢复预设”灯光基线 **工具:** - `gamesir_regdump.py` — 转储/对比寄存器范围 (`sudo python3 gamesir_regdump.py `; bank 0x20 = `32`) - `gamesir_regread.py` — 读取单个寄存器 - `gamesir_regwrite_test.py` — 安全的写入寄存器验证器(对单个字节执行读-改-读回-恢复) - `gamesir_profile_axis.py` — 关于配置文件如何映射到 bank 的只读探测 - `gamesir_parse_capture.py` — 将 USBPcap `.pcapng` 解码为 vendor 命令(无依赖)。`--writes` 仅过滤 WRITE-REG 并打印每个地址的摘要 — 非常适合嘈杂的设置更改捕获 - `gamesir_input_diag.py` — 鼠标模式隔离器:逐一抓取手柄的 evdev 节点,以便您查看合成器正在读取哪一个(摇杆节点)来控制光标 (`sudo python3 gamesir_input_diag.py`) **`USBPcap Controller Tests/`** — 配置映射所基于的官方应用捕获 逆向工程自(连接-同步、持久化、重映射、死区、曲线、 回报率、震动)。可使用 `gamesir_parse_capture.py` 解析其中任何一个。 **`archive/`** — 一次性探测、按键/LED 发现脚本、原始的 PS4 模式读取器、重构前的单体 GUI (`gamesir_gui_monolithic.py`)、 过时的交接文档以及 LED USB 捕获 (`gamesir_led.pcapng`)。保留以供 参考;这些脚本要求仓库根目录在导入路径上 (`from gs_common import …`)。 ## 状态与后续步骤 已实现:实时输入、电池、固件读数、Xbox 模式警告、配置文件 读取/切换、震动、完整的独立 RGB、**效果预设**、灯光电源 设置(音频响应 / 拿起唤醒 / 休眠)、**自定义关键帧 动画编辑器**(基于槽位,添加/删除 1–8 帧、随机化、播放/暂停)、 **配置编辑器**(死区、抗死区、摇杆轨迹 + 灵敏度 曲线,包括**可拖动的自定义曲线编辑器**、机死区 + 微动扳机 + 响应曲线、震动 L/R、回报率)以及**按键重映射** — 所有操作均会读取活动配置文件的当前值并实时写入编辑内容。 **备份 / 恢复:** 导出会将所有 4 个配置文件及灯光设置快照到一个带标签的 JSON 文件中;恢复会将其写回。两者均已**在硬件上进行了端到端验证。** 恢复采用**写入-验证-重试**机制:每个区块在写入后都会被读回, 如果未生效则会重新发送(手柄会静默丢弃连续的命令, 因此盲目写入会丢失区块——例如第一个灯光记录),最多会重试几次, 并报告明确的通过/失败状态。选择恢复文件时会显示一个内联的 **“将加载的备份写入手柄”** 按钮(没有模态弹窗——这 在窗口管理器中被证明是不可靠的)。注意:bank `0x02`-`0x04`(已存储的、 非活动的配置文件)在此手柄上显示为只读,因此仅能保证对 **活动配置文件 + 灯光** 进行恢复;如果无法确认存储的配置文件, 状态行会予以提示。 **鼠标模式修复 (KDE/KWin Game Controller 插件):** 在 2.4GHz 接收器 重新配对/重新插拔后,移动摇杆会开始控制桌面光标(并且 按键会触发点击)。这**不是**手柄模拟鼠标 — 而是 **KWin 的 “Game Controller” 插件** (Plasma 6.7,一项 2025 年 GSoC 功能) 将摇杆映射为 → 指针,扳机映射为 → 点击,**直接**读取摇杆 evdev 节点。 (通过逐一抓取手柄的 evdev 节点进行了诊断 — 只有 *摇杆*节点会停止光标移动;模拟的鼠标/键盘节点读取值为零。 `fuser` 确认 `kwin_wayland` 占用了摇杆节点,并且测试了 `LIBINPUT_IGNORE_DEVICE` 规则,发现它**没有**帮助 — KWin 读取该节点是 带外传输的,而不是通过 libinput。) **推荐修复 — 禁用插件**(永久有效,并且不影响游戏, 因为游戏会直接读取 evdev;当其他应用 使用手柄时,该插件甚至会自动禁用): ``` kwriteconfig6 --file kwinrc --group Plugins --key gamecontrollerEnabled false qdbus6 org.kde.KWin /KWin reconfigure # or just log out/in ``` `gamecontrollerEnabled true/false` 实际上就是鼠标模式的开启/关闭开关 (还有一个 **系统设置 → Game Controller** 的开关)。 **应用内备选方案(非 KDE / 按需):** **停止鼠标模式** 开关会对摇杆节点采取独占式的 `EVIOCGRAB`,使得合成器无法读取它,并且会在重新插拔后 重新应用抓取。它是桌面环境无关的,但在开启时, evdev 游戏(Steam/SDL)也无法看到手柄(旧版的 `/dev/input/jsN` 节点和 hidraw 应用仍然可以工作) — 因此在 KDE 上建议优先使用插件开关。(运行 `gamesir_input_diag.py` 以自行复现这种逐一节点的隔离测试。) **配置架构(由 USB 捕获确定):** 读/写命令的字节 2 是一个 **bank** 选择器。编辑目标指向 **bank `0x01`,即*活动*配置文件的实时工作副本** — 官方应用会将每个配置/重映射更改写入那里, 而不管配置文件编号是多少。bank `0x02`–`0x05` 是仅供应用读取的存储/辅助区 (`0x02`–`0x04` 是默认配置文件存储;`0x05` 是另一个不同的辅助 bank),而 `0x20` 是灯光。寄存器偏移量(震动 `0x20`/`0x21`,回报率 `0x2e`, 扳机区块 `~0x1f1`,摇杆区块 `~0x227`,下方的重映射记录)位于 `gamesir_config.py` 和助手记忆库文件中。**写入会自动持久化到闪存 — 无需提交命令。** **重映射:** 每个输入都有一个 7 字节的记录;只有 `[enabled, target_code]` 是重要的(清除 = `[00 00]`)。源地址和目标代码映射在 `gamesir_config.py` (`REMAP_SLOTS` / `REMAP_TARGETS`) 中。 **右摇杆区块** 已被**捕获** (`15_rs_testing.pcapng`):它是 镜像于 `+0x20` 处的左摇杆区块(轨迹 `0x0247`,死区最小值/最大值 `0x0249`/`0x024a`,抗死区最小值/最大值 `0x024b`/`0x024c`,曲线 `0x024e`)。该 捕获还揭示了**左摇杆具有一个我们一直遗漏的死区*最大值***,位于 `0x022a` 处 — 编辑器现在会显示两个摇杆的死区最小值+最大值。 **RT 扳机区块**暴露为镜像于 `+0x1c` 处的 LT(RT 重映射 地址证实了该步长) — 属于**推断得出,尚待验证**,需等待对 RT 设置更改的捕获。 待办项目:验证推断的 RT 区块;View/Menu/L4/R4 的*目标*代码(尚未 作为目标被捕获);配置文件切换如何将 bank `0x01` 同步到一个存储中(一个 `SET-PROFILE` + 重读测试);以及 PS4/Switch 模式的输入解析。 ## 许可与免责声明 基于 [MIT License](LICENSE) 发布 — 可自由使用、修改和重新分发。 这是一个独立的业余逆向工程项目。它**与 GameSir 没有任何关联、认可或 支持**,“GameSir” 和 “Cyclone 2” 是其各自所有者的商标。该协议是为了 互操作性而进行逆向工程的;本仓库仅包含原创 代码(无 vendor 固件、USB 捕获或第三方资产)。按“原样”提供, **不提供任何保证** — 您使用它并测试手柄寄存器的 风险由您自行承担。

标签:GUI, Python, 云资产清单, 无后门, 游戏外设, 逆向工具, 逆向工程, 配置工具