可视化键盘
基本信息
| 属性 | 值 |
|---|---|
| 实现类 | com.blamejared.controlling.client.gui.GuiVisualKeyboard |
| 打开方式 | 控制界面上的 “Key Map” 按钮(ID 1007),或列表行内的键盘图标按钮(ID 2002) |
| 面板分页 | Page 私有枚举:3 页 |
| 修饰键按钮 | 来自 KeyModifier.VALUES,4 个 |
| 来源 | 代码改编自 Keyboard Wizard / KeyboardWizard-Legacy-Forge-1.7.10,作者 MrNerdy42 与 Tapio,MIT 许可 |
功能
可视化键盘是一个覆盖在控制设置界面上的浮层,用鼠标点选代替"按下按键"来完成绑定,
因此不需要真的去按键盘。文件头注明改编自 Keyboard Wizard 项目(见仓库 THIRD_PARTY_NOTICES.md)。
面板内的键位不是贴图,而是按标准键盘布局用 Gui.drawRect 逐个矩形绘制出来的。
Page —— 分页(3 值)
Page 是 GuiVisualKeyboard 内的私有枚举,初始为 Page.MAIN。
面板右上角有 3 个分页按钮,对应 i18n options.visualKeyboardMain /
options.visualKeyboardNumpad / options.visualKeyboardAux。
| 取值 | 标签 | 行数 | 内容 |
|---|---|---|---|
MAIN |
主板 | 6 | Esc + F1–F12、数字/符号行、Tab 字母行、Caps 字母行、Shift 字母行、Ctrl/Win/Alt/空格行 |
NUMPAD |
小键盘 | 4 | Num / * -;7 8 9 +;4 5 6 Enter;1 2 3 . |
AUX |
辅助键 | 4 | PrtSc ScrLk Pause Ins Home;PgUp Del End PgDn Up;Left Down Right F13 F14;F15 F16 F17 F18 F19 |
MAIN 页各行的完整键位(含 Keyboard.KEY_* 常量与宽度单位):
| 行 | 键位(宽度单位) |
|---|---|
| 1 | Esc、F1–F12(各 1.0) |
| 2 | `、1–0、-、=(各 1.0)、Back(2.0) |
| 3 | Tab(1.5)、Q W E R T Y U I O P、[、](各 1.0)、\(1.5) |
| 4 | Caps(1.75)、A S D F G H J K L、;、'(各 1.0)、Enter(2.25) |
| 5 | LShift(2.25)、Z X C V B N M、,、.、/(各 1.0)、RShift(2.75) |
| 6 | LCtrl、LWin、LAlt(各 1.25)、Space(7.5)、RAlt、RWin、RCtrl(各 1.25) |
MAIN 与 AUX 页包含左右成对的 Ctrl/Shift/Alt/Win 键,与
修饰键枚举 的"左右键合并为同一逻辑修饰键"设计对应。
布局计算
layout(screen) 每次绘制前重算,面板按屏幕尺寸自适应:
| 量 | 计算方式 |
|---|---|
maxWidth |
max(220, screen.width - 24) |
keyboardWidth |
先 min(560, maxWidth - 16),再 max(180, panelWidth - 16) |
panelWidth |
min(screen.width - 8, keyboardWidth + 16) |
keyGap |
keyboardWidth < 360 ? 2 : 4 |
keyHeight |
max(14, min(24, (screen.height - 116) / 7)) |
headerHeight |
57(标题 + 提示 + 修饰键按钮行) |
footerHeight |
24 |
| 键盘区行数 | MAIN 为 6,其余为 4 |
修饰键按钮
面板标题下方有"Modifier"标签(options.visualKeyboardModifier),其后横排 4 个按钮,
直接由 KeyModifier.VALUES 生成,标签取 getDisplayName(),即 None / Ctrl / Shift / Alt。
点击按钮即 screen.setVisualKeyboardModifier(modifier)。当前生效的修饰键按钮高亮为选中色。
None 按钮的作用就是退回裸键绑定。
修饰键的可推断性:如果玩家此刻真的按着某个修饰键,
GuiNewControls.getVisualKeyboardModifier() 会返回 KeyModifier.getActiveModifier() 而非面板记录的值。
所以玩家可以直接按住 Ctrl 再点主键,无需先点 Ctrl 按钮。
键位颜色状态
每个 KeyButton 的底色按固定优先级选取:
| 优先级 | 状态 | 颜色 | 触发条件 |
|---|---|---|---|
| 1 | 禁用 | 0xFF303030 |
modifier.matches(keyCode) —— 当前修饰键对应的物理键,不能绑成自己 |
| 2 | 选中 | 0xFFD4A928 |
该键是当前正在编辑的绑定(键码相同且修饰键相同) |
| 3 | 冲突 | 0xFF8A2525 |
该键码 + 当前修饰键下有 >1 个绑定 |
| 4 | 已绑定 | 0xFF236B23 |
该键码 + 当前修饰键下有 1 个绑定 |
| 5 | 悬停 | 0xFF888888 |
鼠标位于该键上 |
| 6 | 普通 | 0xFF555555 |
其余 |
其他面板色:面板底 0xEE101010,边框 0xFF777777,文字 0xFFFFFF,
禁用态文字 0xA0A0A0。
绑定归属的统计口径见 getMatchingKeyBindings:遍历 mc.gameSettings.keyBindings,
要求键码相同、分类不以 .hidden 结尾、且该绑定的修饰键等于当前修饰键
(非 ComboKeyBinding 的绑定一律按 NONE 计)。
因此在 Ctrl 面板下
G显示为"未绑定"是正常的——Ctrl + G归在 Ctrl 页, 裸G才在 None 页显示为已绑定。
键名标签
getKeyLabel(keyCode, fallback) 的取值优先级:
- 若未加载
lwjgl3ify→ 用硬编码标签; - 若
shouldUseFixedLabel(keyCode)命中 → 用硬编码标签; - 否则取
Keyboard.getKeyName(keyCode),若为null或以"Key "开头 → 退回硬编码标签。
shouldUseFixedLabel 固定了 29 个键码(Esc、Back、Tab、Caps、Enter、LShift、RShift、
LCtrl、RCtrl、LMenu、RMenu、LMeta、RMeta、Space、NumLock、SysRq、Scroll、Insert、Delete、
Home、End、PgUp、PgDn、Up、Down、Left、Right、小键盘 Enter),
避免在 LWJGL2 与 LWJGL3 下显示不一致。
Loader.isModLoaded("lwjgl3ify") 是一个可选依赖检测:装了就用 LWJGL3 的原生键名,
没装就用自绘标签,保证两种环境都能正常显示。
点击行为
mouseClicked 的判定顺序:
- 点击不在面板内 → 返回
false,交还给底层列表; - 面板内且非左键(
mouseButton != 0)→ 返回true直接吞掉,避免误操作; - 命中分页按钮 → 切换
Page; - 命中修饰键按钮 → 设置当前修饰键;
- 命中某个可用键 → 分两种情况:
- 当前没有选中待编辑的绑定 → 用
getMatchingKeyBindings(...)反查, 若有结果则showKeyBinding(第一个匹配项),即跳转到列表中的那一条; - 已选中待编辑的绑定 →
selectVisualKeyboardKey(key.keyCode)完成绑定;
- 当前没有选中待编辑的绑定 → 用
- 其余情况(面板内空白处)→ 返回
true吞掉点击。
"点击面板外"这一约定来自界面提示 options.visualKeyboardHint:
“Click a key to bind. Click outside to bind a mouse button.”
(点键完成绑定,点面板外则改为绑定鼠标键)。