# handlepro **Repository Path**: hseisirs/handlepro ## Basic Information - **Project Name**: handlepro - **Description**: HandlePro - SDL style controller layer for Minecraft 26.1 (Fabric, client side) - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-11-07 - **Last Updated**: 2026-11-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # HandlePro **Minecraft 的手柄语义层。纯客户端,不改服务器,不发伪造数据包。** **A controller layer for Minecraft — client side only, no forged packets.** [![star](https://gitee.com/hseisirs/handlepro/badge/star.svg?theme=dark)](https://gitee.com/hseisirs/handlepro/stargazers) [![fork](https://gitee.com/hseisirs/handlepro/badge/fork.svg?theme=dark)](https://gitee.com/hseisirs/handlepro/members) ![license](https://img.shields.io/badge/license-MIT-3fae6a.svg) ![side](https://img.shields.io/badge/environment-client-3fae6a.svg) ![HandlePro](HandlePro-icon.png) Minecraft 会从 GLFW 读到摇杆的原始轴,却从来没把手柄当手柄用:没有设备身份、没有品牌刻字、 界面点不动、没有宏,也没有马达。系统级映射工具(Steam Input / DS4Windows / reWASD)能用, 但它们把一切都压成“鼠标 + 键盘”,于是手柄之所以是手柄的那部分全丢了。 HandlePro 在客户端内部重建了 SDL 的 GameController 层:认设备、认品牌、按品牌画键、 让右摇杆驱动真实光标、保持扳机模拟量、接上原生马达、记录和回放宏。 --- ## 中文 ### 支持的版本 | 版本线 | Minecraft | Fabric Loader | Fabric API | Java | 模组版本 | 下载 | | --- | --- | --- | --- | --- | --- | --- | | `fabric/1.20.1` | 1.20.1 | 0.20.1+ | 0.92.12+1.20.1 | 17 | **1.1.0** | [handlepro-1.1.0.jar](https://gitee.com/hseisirs/handlepro/releases/download/v1.1.0/handlepro-1.1.0.jar) | | `fabric/26.1` | 26.1 | 0.19.3+ | 0.145.1+26.1 | 25 | **1.0.0** | [handlepro-1.0.0.jar](https://gitee.com/hseisirs/handlepro/releases/download/v1.0.0/handlepro-1.0.0.jar) | 两条线行为一致、各自独立构建。26.3 起 Mojang 自己做了手柄支持,那条线是给 26.3 之前的版本补课; 1.20.1 线则是长期维护、最新特性的落脚点(原生马达就是先从这条线落地的)。 ### 它能做什么 - **设备识别** —— 从 SDL GUID 解出厂商 / 产品号,结合驱动名判断品牌: `Xbox / PlayStation / Nintendo / GameSir / ShanWan / 8BitDo / Logitech / Valve / Razer / 通用`。 认不出的老老实实报“通用”,不瞎猜。热插拔不用重启游戏。 - **品牌刻字** —— 同一颗物理键,Xbox 印 `A`,PlayStation 印 `✕`,Nintendo 印 `B`(布局是反的)。 提示药丸的配色跟着品牌走。所有图标都是代码画的,不借贴图。 - **映射库** —— 内置 `gamecontrollerdb.txt` 片段;把完整库放到 `config/handlepro/gamecontrollerdb.txt` 就会优先用它。没有映射串的山寨手柄回落到 XInput / Switch / Legacy 三套原始布局,可逐设备强制。 - **界面适配** —— 右摇杆直接驱动系统光标,原版所有界面(背包、设置、服务器列表、聊天)立刻可点, 悬浮高亮、工具提示、滚轮滚动都正常。自绘界面另加方向键选行、滑杆、开关、文本编辑。 - **游戏操作** —— 左摇杆走位、右摇杆视角(每帧泵,不是 20Hz)、扳机按模拟阈值触发攻击 / 使用, 其余按键落回原版键位。不伪造数据包,服务器看不出区别。 - **原生马达** —— 走系统 XInput 直驱左右马达(GLFW 根本没有震动 API)。受伤、落地、攻击、 低血量心跳、界面操作、宏开始 / 结束都能触发,强度和槽位可调,页内自带轻 / 重 / 双马达测试。 - **宏** —— 按真实时间采样录制,回放走同一条输入管线;支持循环、重命名、删除,一个宏一个 JSON。 **多人游戏默认锁定**,必须在界面里显式打开才可用。 - **浅色 / 深色双主题**,中英双语界面,`F9` 开面板、`F10` 录宏、panic 键一键放权并停马达。 ### 原生马达(1.1.0) | 层 | 做什么 | | --- | --- | | `rumble/XInputBackend` | JNA 调 `XInput1_4`(缺失时退 `xinput1_3` / `XInput9_1_0`),独占马达通道 | | `rumble/RumbleEngine` | 脉冲混合器:多脉冲按马达取最大值、乘全局强度、每帧线性衰减 | | `rumble/RumbleFeedback` | 把本地可观测事件(`hurtTime`、`fallDistance`、血量)翻成脉冲 | | 界面马达页 | 后端状态、槽位、强度、6 个事件开关、3 个测试按钮 | JNA 已经打进 jar(`META-INF/jars/jna-5.14.0.jar`),不用另装,也不会污染别的模组。 只支持 **XInput 设备**:Xbox 系列,以及跑在 XInput 模式下的 GameSir / 8BitDo / ShanWan。 DualShock / DualSense 若在原生(非 XInput)模式下会显示“不可用”,而不是假装支持。 ### 安装 1. 装好对应版本的 Fabric Loader(见上表)。 2. 把 jar 丢进 `mods/`,**同时装对应版本的 Fabric API**。 3. 只装客户端。服务器不需要,也装不上——`fabric.mod.json` 里 `environment: client`。 进游戏按 `F9` 打开 HandlePro,手柄页能看到设备、品牌、布局来源,就是认到了。 ### 默认手柄按键 | 手柄 | 作用 | | --- | --- | | A | 跳跃 / 界面确定 | | B | 潜行 / 界面右键 | | X | 攻击(按住连续) | | Y | 使用 / 放置 | | LT / RT | 攻击 / 使用(模拟量超阈值即按住) | | LB / RB | 疾跑(按住)/ 副手交换 | | 左摇杆按下 | 疾跑 | | 右摇杆 | 视角 / 界面光标;按下切换视角 | | 方向键 | 界面滚动 / 自绘界面选行;上开背包、下丢物品 | | BACK(视图键) | 关闭当前界面 | | START(菜单键) | 打开背包 | ### 配置 `config/handlepro/config.json`,宏在 `config/handlepro/macros/*.json`: ```json { "theme": "auto", "enabled": true, "guiCursor": true, "gameplay": true, "deadzone": 0.18, "responseCurve": 1.0, "lookSensitivity": 1.0, "triggerThreshold": 0.35, "rawLayout": "auto", "brandOverride": "auto", "macros": { "enabled": true, "allowInMultiplayer": false, "maxSeconds": 120 }, "rumble": { "enabled": true, "strength": 0.7, "slot": "auto", "guiFeedback": true, "onHurt": true, "onLanding": true, "onAttack": true, "lowHealth": true, "onMacro": true } } ``` ### 从源码构建 ```bash cd fabric/1.20.1/1.1.0 && ./gradlew build # → build/libs/handlepro-1.1.0.jar cd fabric/26.1/1.0.0 && ./gradlew build # → build/libs/handlepro-1.0.0.jar ``` 仓库里的 `gradle.properties` 不带任何代理配置。需要走代理才能连 `maven.fabricmc.net` 的机器, 用环境变量自己传,别写进文件: ```bash GRADLE_OPTS="-Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=7890 \ -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=7890" ./gradlew build ``` 1.20.1 的 jar 是混淆的,`build.gradle` 必须写 `loom.officialMojangMappings()` 并用 `modImplementation`; 26.x 的 jar 不混淆,不写 mappings、用 `implementation`。这两条线的差别基本就集中在这里。 ### 仓库结构 ``` handlepro/ ├── fabric/1.20.1/1.1.0/ # 1.20.1 线,原生马达 ├── fabric/26.1/1.0.0/ # 26.1 线,给 26.3 之前补课 │ └── src/main/java/top/hseisirs/handlepro/ │ ├── api/ 只放契约,不含 Minecraft 类型 │ ├── device/ GLFW 后端、GUID、品牌识别、热插拔 │ ├── mapping/ SDL 映射串、映射库、死区、原始布局 │ ├── input/ 光标、界面驱动、游戏驱动、路由 │ ├── macro/ 录制、回放、存储、多人策略 │ ├── gui/ 主题令牌、绘制工具、面板、提示浮层 │ ├── config/ JSON 配置 │ ├── rumble/ 原生马达(仅 1.20.1) │ └── mixin/ 两个注入,都有注释说明理由 ├── Planning/Planning.md # 为什么这么建 ├── PARTITION.md # 分区图与同步契约 ├── MODRINTH.md # 发布页文案(加载器 / 版本中立) └── handlepro.html # 落地页 ``` ### 边界 - 纯客户端。服务器上不装东西、不改协议、不发额外包。 - 宏在多人游戏默认锁定,这个开关是显式的,模组不会替你隐藏“你在用宏”这件事。 - 马达仅 XInput。原生模式下运行的 PlayStation 手柄拿不到震动,会如实报不可用。 - 单个 jar 不跨版本通用:1.20.1 的 jar 装不进 26.1,反之亦然。 --- ## English ### Supported versions | Line | Minecraft | Fabric Loader | Fabric API | Java | Mod | Download | | --- | --- | --- | --- | --- | --- | --- | | `fabric/1.20.1` | 1.20.1 | 0.20.1+ | 0.92.12+1.20.1 | 17 | **1.1.0** | [handlepro-1.1.0.jar](https://gitee.com/hseisirs/handlepro/releases/download/v1.1.0/handlepro-1.1.0.jar) | | `fabric/26.1` | 26.1 | 0.19.3+ | 0.145.1+26.1 | 25 | **1.0.0** | [handlepro-1.0.0.jar](https://gitee.com/hseisirs/handlepro/releases/download/v1.0.0/handlepro-1.0.0.jar) | Both lines behave the same and build independently. Minecraft 26.3 ships native controller support; the 26.1 line backports that experience to earlier versions, while 1.20.1 is the long-lived line where new features land first (native rumble started there). ### What it does - **Device identity** — decodes vendor/product from the SDL GUID, cross-checks the driver name, and reports the brand: Xbox, PlayStation, Nintendo, GameSir, ShanWan, 8BitDo, Logitech, Valve, Razer or generic. Unknown pads are reported as generic rather than guessed. Hot-plug works without a restart. - **Brand-correct glyphs** — the same physical south button is `A` on Xbox, `✕` on PlayStation and `B` on Nintendo. Hint pills follow the brand palette. Every glyph is drawn in code, no textures. - **Mapping database** — ships a `gamecontrollerdb.txt` subset, prefers your own copy at `config/handlepro/gamecontrollerdb.txt`, and falls back to XInput / Switch / Legacy raw layouts (forceable per device) for pads without a mapping line. - **GUI adaptation** — the right stick drives the real system cursor, so every vanilla screen becomes clickable at once with working hover, tooltips and scrolling. Custom screens add dpad row navigation, sliders, toggles and inline text editing. - **Gameplay** — left stick moves, right stick looks (per frame, not 20 Hz), analog triggers attack and use, the rest map onto vanilla key bindings. No packets are forged. - **Native rumble** — drives both motors through the platform's XInput API, because GLFW has none. Hurt, landing, attack, low health, UI actions and macro cues fire pulses; strength and slot are configurable; test buttons ship in the tab. - **Macros** — time-based sampling, playback through the same input pipeline, one JSON per macro, loop / rename / delete. **Locked by default in multiplayer**, with an explicit opt-in. - **Light and dark themes**, bilingual UI, `F9` panel, `F10` record, unbound-by-default panic key that releases the pad and silences the motors. ### Install 1. Install the matching Fabric Loader (table above). 2. Drop the jar into `mods/` together with the matching **Fabric API**. 3. Client only — `environment: client`, so servers neither need nor accept it. Press `F9`; the controller tab shows the device, brand and where its layout came from. ### Build ```bash cd fabric/1.20.1/1.1.0 && ./gradlew build # → build/libs/handlepro-1.1.0.jar cd fabric/26.1/1.0.0 && ./gradlew build # → build/libs/handlepro-1.0.0.jar ``` The committed `gradle.properties` carries no proxy settings. If your machine only reaches `maven.fabricmc.net` through a proxy, pass it via the environment instead of editing the file: ```bash GRADLE_OPTS="-Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=7890 \ -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=7890" ./gradlew build ``` 1.20.1 ships obfuscated jars, so its `build.gradle` declares `loom.officialMojangMappings()` and uses `modImplementation`; 26.x jars are deobfuscated and use `implementation`. That is most of the diff between the two lines. ### Scope - Client side only: nothing is installed on the server, no protocol changes, no extra packets. - Macros are locked in multiplayer by default; the opt-in is visible on purpose. - Rumble is XInput only. A PlayStation pad in native mode reports "unavailable" instead of pretending. - One jar per version: the 1.20.1 jar will not load on 26.1, and vice versa. --- ## 链接 / Links - 落地页 / Landing page — - 发布页文案 / Store description — [MODRINTH.md](MODRINTH.md) - 分区与同步契约 / Partition contract — [PARTITION.md](PARTITION.md) - 设计记录 / Design notes — [Planning/Planning.md](Planning/Planning.md) - 问题反馈 / Issues — ## 许可证 / License [MIT](LICENSE) © 2026 Hseisirs 随便用、改、再发、商用,保留版权声明即可。没有附加条款,也没有“禁止用于某某”这种尾巴。