跳到主要内容
版本:1.21 - 1.21.1

按键映射

键映射或键绑定定义了应与输入绑定的特定操作:鼠标单击、按键等。只要客户端可以接受输入,就可以检查键映射定义的每个操作。此外,每个键映射可以通过控制选项菜单分配给任何输入。

注册 KeyMapping

可以通过仅在物理客户端上监听mod 事件总线上的 RegisterKeyMappingsEvent 并调用 #register 来注册 KeyMapping

// In some physical client only class

// Key mapping is lazily initialized so it doesn't exist until it is registered
public static final Lazy<KeyMapping> EXAMPLE_MAPPING = Lazy.of(() -> /*...*/);

@SubscribeEvent // on the mod event bus only on the physical client
public static void registerBindings(RegisterKeyMappingsEvent event) {
event.register(EXAMPLE_MAPPING.get());
}

创建 KeyMapping

可以使用它的构造函数创建 KeyMappingKeyMapping 接受定义映射名称、映射默认输入的 翻译键,以及定义映射将放入 控件选项菜单 中的类别的 翻译键

提示

通过提供原版未提供的类别翻译关键字,可以将 KeyMapping 添加到自定义类别中。自定义类别翻译键应包含 mod id(例如 key.categories.examplemod.examplecategory)。

默认输入

每个键映射都有一个与其关联的默认输入。这是通过 InputConstants.Key 提供的。每个输入都包含一个 InputConstants.Type(定义提供输入的设备)和一个整数(定义设备上输入的关联标识符)。

原版 提供三种类型的输入:KEYSYM(通过提供的 GLFW 密钥标记定义键盘)、 SCANCODE(通过特定于平台的扫描码定义键盘)和 MOUSE(定义鼠标)。

备注

强烈建议对键盘使用 KEYSYM 而不是 SCANCODE,因为 GLFW 密钥令牌不绑定到任何特定系统。你可以在 GLFW 文档 上阅读更多内容。

整数取决于提供的类型。所有输入代码均在 GLFW 中定义:KEYSYM 令牌以 GLFW_KEY_* 为前缀,而 MOUSE 代码以 GLFW_MOUSE_* 为前缀。

new KeyMapping(
"key.examplemod.example1", // Will be localized using this translation key
InputConstants.Type.KEYSYM, // Default mapping is on the keyboard
GLFW.GLFW_KEY_P, // Default key is P
"key.categories.misc" // Mapping will be in the misc category
)
备注

如果键映射不应映射到默认值,则输入应设置为 InputConstants#UNKNOWN。普通构造函数将要求你通过 InputConstants$Key#getValue 提取输入代码,而 NeoForge 构造函数可以提供原始输入字段。

IKeyConflictContext

并非所有映射都在每个上下文中使用。有些映射仅在 GUI 中使用,而其他映射仅在游戏中使用。为了避免在不同上下文中使用的相同密钥的映射相互冲突,可以分配 IKeyConflictContext

每个冲突上下文包含两个方法:#isActive,它定义映射是否可以在当前游戏状态中使用;#conflicts,它定义映射是否与相同或不同冲突上下文中的键冲突。

目前,NeoForge 通过 KeyConflictContext 定义了三个基本上下文:UNIVERSAL,这是默认的,意味着密钥可以在每个上下文中使用;GUI,这意味着映射只能在 Screen 打开时使用;IN_GAME,这意味着映射只能在 Screen 打开时使用。 Screen 未开放。可以通过实施 IKeyConflictContext 创建新的冲突上下文。

new KeyMapping(
"key.examplemod.example2",
KeyConflictContext.GUI, // Mapping can only be used when a screen is open
InputConstants.Type.MOUSE, // Default mapping is on the mouse
GLFW.GLFW_MOUSE_BUTTON_LEFT, // Default mouse input is the left mouse button
"key.categories.examplemod.examplecategory" // Mapping will be in the new example category
)

KeyModifier

如果修饰键保持相同(例如 GCTRL + G),Mod 开发者可能不希望映射具有相同的行为。为了解决这个问题,NeoForge 在构造函数中添加了一个额外的参数来接收 KeyModifier,它可以将控制 (KeyModifier#CONTROL)、移位 (KeyModifier#SHIFT) 或 alt (KeyModifier#ALT) 应用于任何输入。 KeyModifier#NONE 是默认值,不会应用任何修饰符。

通过按住修改键和关联的输入,可以在控件选项菜单中添加修改器。

new KeyMapping(
"key.examplemod.example3",
KeyConflictContext.UNIVERSAL,
KeyModifier.SHIFT, // Default mapping requires shift to be held down
InputConstants.Type.KEYSYM, // Default mapping is on the keyboard
GLFW.GLFW_KEY_G, // Default key is G
"key.categories.misc"
)

检查 KeyMapping

可以检查 KeyMapping 是否被点击。根据何时,可以在条件中使用映射来应用关联的逻辑。

游戏内

在游戏中,应通过在 事件总线 上监听 ClientTickEvent.Post 并在 while 循环内检查 KeyMapping#consumeClick 来检查映射。 #consumeClick 将仅返回 true 执行输入且之前尚未处理的次数,因此它不会无限地停止游戏。

@SubscribeEvent // on the game event bus only on the physical client
public static void onClientTick(ClientTickEvent.Post event) {
while (EXAMPLE_MAPPING.get().consumeClick()) {
// Execute logic to perform on click here
}
}
警告

请勿使用 InputEvent 作为 ClientTickEvent.Post 的替代品。仅针对键盘和鼠标输入有单独的事件,因此它们不会处理任何其他输入。

GUI 内部

在 GUI 中,可以使用 IKeyMappingExtension#isActiveAndMatchesGuiEventListener 方法之一中检查映射。最常见的检查方法是 #keyPressed#mouseClicked

#keyPressed 接收 GLFW 密钥令牌、特定于平台的扫描代码以及按下的修饰符的位字段。可以通过使用 InputConstants#getKey 创建输入来检查映射的键。修饰符已经在映射方法本身中进行了检查。

// In some Screen subclass
@Override
public boolean keyPressed(int key, int scancode, int mods) {
if (EXAMPLE_MAPPING.get().isActiveAndMatches(InputConstants.getKey(key, scancode))) {
// Execute logic to perform on key press here
return true;
}
return super.keyPressed(x, y, button);
}
备注

如果你不拥有要检查的屏幕,则可以改为在事件总线上监听 ScreenEvent.KeyPressedPrePost 事件。

#mouseClicked 获取鼠标的 x 位置、 y 位置和单击的按钮。通过使用 InputConstants.Type#getOrCreateMOUSE 输入创建输入,可以根据映射检查鼠标按钮。

// In some Screen subclass
@Override
public boolean mouseClicked(double x, double y, int button) {
if (EXAMPLE_MAPPING.get().isActiveAndMatches(InputConstants.TYPE.MOUSE.getOrCreate(button))) {
// Execute logic to perform on mouse click here
return true;
}
return super.mouseClicked(x, y, button);
}
备注

如果你不拥有要检查鼠标的屏幕,则可以改为监听事件总线ScreenEvent.MouseButtonPressedPrePost 事件。