输入管线补丁
基本信息
| 属性 | 值 |
|---|---|
| 补丁目标 | 原版 net.minecraft.client.settings.KeyBinding |
| 补丁类 | com.blamejared.controlling.mixins.early.MixinKeyBinding |
| 加载阶段 | Phase.EARLY(客户端) |
| Mixin 配置 | mixins.controlling.early.json,包 com.blamejared.controlling.mixins.early |
| 枚举项 | Mixins.KEYBINDING |
功能
组合键要生效,就必须在原版"这个键码按下了吗"的判定里插入修饰键检查。
MixinKeyBinding 对 KeyBinding 的 4 个方法做了注入,其中前两个完全取消原版实现
(ci.cancel()),后两个只是提前返回 false。
| 被补丁的原版方法 | 注入位置 | 是否取消原版 | 行为 |
|---|---|---|---|
setKeyBindState(int, boolean) |
HEAD |
是 | 逐个匹配 keyCode 的按键,只有修饰键满足时才置位 pressed |
onTick(int) |
HEAD |
是 | 只有修饰键满足时才累加 pressTime |
getIsKeyPressed() |
HEAD |
否(提前返回) | 修饰键不满足时直接返回 false |
isPressed() |
HEAD |
否(提前返回) | 修饰键不满足时把 pressTime 清零并返回 false |
被 shadow 的原版字段包括静态的 keybindArray、keyCode、keyCodeDefault、pressed、
pressTime,以及非静态的 keyCode。
按键激活判定
所有静态判定最终都汇到 controlling$isBindingActiveWithModifier(KeyBinding, int inputKeyCode),
按顺序执行 4 步:
| 步骤 | 条件 | 返回 |
|---|---|---|
| 1 | 该按键不是 ComboKeyBinding |
true(直接放行,不参与组合键系统) |
| 2 | 修饰键为 NONE 且 keyCode == inputKeyCode 且该输入键码本身是修饰键 |
true |
| 3 | 修饰键为 NONE 且 controlling$hasActiveModifiedSiblingBinding(...) 为真 |
false(压制) |
| 4 | 其余情况 | combo.controlling$isModifierActive() |
第 2 步的含义:当玩家直接按下 Ctrl/Shift/Alt 键本身时放行,这样裸修饰键(如直接绑定
Shift)仍然能被按到,而不会被"必须同时存在另一个修饰键"的条件卡死。
第 3 步是本 mod 最重要的行为修正,见下节。
兄弟按键压制
controlling$hasActiveModifiedSiblingBinding(KeyBinding keyBinding, int inputKeyCode) 遍历
keybindArray,寻找同一键码上另一个正在生效的组合键:
- 跳过自身;
- 跳过键码不等于
inputKeyCode的绑定; - 若该绑定是
ComboKeyBinding、其修饰键不为NONE、且该修饰键此刻isActive()→ 返回true。
结果就是:当玩家按住 G 时,如果 G 上还绑了一个 Ctrl + G,那么裸的 G 会被临时压制,
只有 Ctrl + G 生效。反过来在没有修饰键按下时,裸 G 照常工作。
源码在 GuiNewKeyBindingList 里的注释把这称为"less severe form of conflict"(较轻度的冲突),
对应 GUI 上用金色而非红色 [ ] 标记的情形。
裸修饰键绑定的额外条件
controlling$isModifierActive() 有一个针对 NONE 的分支:
- 若
keyModifier != NONE→ 直接返回keyModifier.isActive(); - 若
keyModifier == NONE且 键码本身是一个修饰键(KeyModifier.isKeyCodeModifier(keyCode)) → 返回KeyModifier.fromKeyCode(keyCode).isActive(); - 否则 → 返回
true(普通按键无修饰键要求)。
即:把裸 Ctrl / Shift / Alt 绑成热键时,只有按住该修饰键时该热键才触发。
而普通按键不绑修饰键时不受任何限制。
其他 Mixin 与加载器
除按键本身外,还有两个 Mixin 加载基础设施:
| 类 | 作用 |
|---|---|
EarlyMixinsLoader |
实现 IFMLLoadingPlugin + IEarlyMixinLoader,标注 @IFMLLoadingPlugin.MCVersion("1.7.10"),Mixin 配置 mixins.controlling.early.json。所有 IFMLLoadingPlugin 方法均返回 null 或空实现 |
LateMixinsLoader |
标注 @LateMixin,实现 ILateMixinLoader,Mixin 配置 mixins.controlling.late.json |
Mixins |
枚举,KEYBINDING → 早期 MixinKeyBinding,GAME_SETTINGS → 早期 MixinGameSettings |
Mixins 枚举中没有任何 Phase.LATE 条目,所以 mixins.controlling.late.json
当前不注册任何 mixin(仓库中另有未被引用的 mixins.controlling.json)。
配套资源 META-INF/controlling_at.cfg 开通了两个原版私有字段以支持界面实现:
GuiScreen.buttonList(field_146292_n)与 GuiScreen.selectedButton(field_146290_a)。