• Forge论坛

导航页

  • 主页
  • 向文档做出贡献
  • 入门
    • 概述
    • 模组文件
    • 规划你的模组结构
    • 版本号
  • 核心概念
    • 注册表
    • 端位(Sides)
    • 事件
    • 模组生命周期
    • 资源
    • 国际化与本地化
  • 方块
    • 概述
    • 方块状态
  • 物品
    • 概述
    • BlockEntityWithoutLevelRenderer
  • 网络
    • 概述
    • SimpleImpl
    • 实体的同步
  • 方块实体
    • 概述
    • BlockEntityRenderer
  • 游戏特效
    • 粒子效果
    • 音效
  • 数据储存
    • Capabilities
    • Saved Data
    • 编解码器(Codecs)
  • 图形用户界面
    • 菜单(Menus)
    • 屏幕(Screens)
  • 渲染
    • 模型扩展
      • 概述
      • 根变换
      • 渲染类型
      • 部分可见度
      • 面数据
    • 模型加载器
      • 概述
      • 烘焙模型
      • 变换
      • 物品重载
  • 资源
    • 客户端资源(Assets)
      • 概述
      • 模型
        • 概述
        • 纹理色调
        • 物品属性
    • 服务端数据(Data)
      • 概述
      • 配方
        • 概述
        • 自定义配方
        • 原料
        • 非数据包配方
      • 战利品表
      • 全局战利品修改器
      • 标签
      • 进度
      • 条件性加载数据
  • 数据生成
    • 概述
    • 客户端资源(Assets)
      • 模型提供者
      • 语言提供者
      • 音效提供者
    • 服务端数据(Data)
      • 配方提供者
      • 战利品表提供者
      • 标签提供者
      • 进度提供者
      • 全局战利品修改器提供者
      • 数据包注册表对象提供者
  • 杂项功能
    • 配置
    • 键盘布局
      • 注册一个KeyMapping
      • 创建一个KeyMapping
      • 检查一个KeyMapping
    • 游戏测试
    • Forge更新检查器
    • 调试分析器
  • 进阶主题
    • 访问转换器
  • 向Forge做出贡献
    • 概述
    • Pull Request准则
  • 旧版本
    • 概述
    • 移植到当前版本

键盘布局

键盘布局(键映射)或键盘绑定定义了应与输入绑定的特定操作:鼠标单击、按键等。每当客户端可以进行输入时,都可以检查键盘布局定义的每个操作。此外,每个键盘布局都可以通过控制选项菜单分配给任何输入。

注册一个KeyMapping

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

// 在某个仅物理客户端的类中

// 键盘布局是延迟初始化的,因此在注册之前它不存在
public static final Lazy<KeyMapping> EXAMPLE_MAPPING = Lazy.of(() -> /*...*/);

// 事件仅在物理客户端上的模组事件总线上
@SubscribeEvent
public void registerBindings(RegisterKeyMappingsEvent event) {
  event.register(EXAMPLE_MAPPING.get());
}

创建一个KeyMapping

KeyMapping可以使用其构造函数创建。KeyMapping接受一个定义映射名称的翻译键,映射的默认输入,以及定义映射将放在控制选项菜单中的类别的翻译键。

提示

通过提供原版未提供的类别翻译键,可以将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", // 将使用该翻译键进行本地化
  InputConstants.Type.KEYSYM, // 在键盘上的默认映射
  GLFW.GLFW_KEY_P, // 默认键为P
  "key.categories.misc" // 映射将在杂项(misc)类别中
)

注意

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

IKeyConflictContext

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

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

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

new KeyMapping(
  "key.examplemod.example2",
  KeyConflictContext.GUI, // 映射只能在当一个屏幕打开时使用
  InputConstants.Type.MOUSE, // 在鼠标上的默认映射
  GLFW.GLFW_MOUSE_BUTTON_LEFT, // 在鼠标左键上的默认鼠标输入
  "key.categories.examplemod.examplecategory" // 映射将在新的示例类别中
)

KeyModifier

如果修改键保持不变(例如G与CTRL + G),则修改器可能不希望映射具有相同的行为。为了解决这个问题,Forge在构造函数中添加了一个额外的参数来接受一个KeyModifier,它可以将control(KeyModifier#CONTROL)、shift(KeyModifier#SHIFT)或alt(KeyModifier#ALT)映射到任何输入。KeyModifier#NONE是默认值,不会应用任何修改器。

通过接纳修饰符键和相关输入,可以在控制选项菜单中添加修改器。

new KeyMapping(
  "key.examplemod.example3",
  KeyConflictContext.UNIVERSAL,
  KeyModifier.SHIFT, // 默认映射要求shift被按下
  InputConstants.Type.KEYSYM, // 默认映射在键盘上
  GLFW.GLFW_KEY_G, // 默认键为G
  "key.categories.misc"
)

检查一个KeyMapping

可以检查KeyMapping以查看它是否已被单击。根据时间的不同,可以在条件中使用映射来应用关联的逻辑。

在游戏内

在游戏内,应通过在Forge事件总线上监听ClientTickEvent并在while循环中检查KeyMapping#consumeClick来检查映射。#consumeClick仅当输入已执行但之前尚未处理的次数时才会返回true,因此不会无限拖延游戏。

// 事件仅在物理客户端上的Forge事件总线上
public void onClientTick(ClientTickEvent event) {
  if (event.phase == TickEvent.Phase.END) { // 仅调用代码一次,因为tick事件在每个tick调用两次
    while (EXAMPLE_MAPPING.get().consumeClick()) {
      // 在此处执行单击时的逻辑
    }
  }
}

警告

不要将InputEvent用作ClientTickEvent的替代项。只有键盘和鼠标输入有单独的事件,所以它们不会处理任何额外的输入。

Inside a GUI

在GUI内,可以使用IForgeKeyMapping#isActiveAndMatches在其中一个GuiEventListener方法中检查映射。可以检查的最常见方法是#keyPressed和#mouseClicked。

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

// 在某个Screen子类中
@Override
public boolean keyPressed(int key, int scancode, int mods) {
  if (EXAMPLE_MAPPING.get().isActiveAndMatches(InputConstants.getKey(key, scancode))) {
    // 在此处执行按键时的逻辑
    return true;
  }
  return super.keyPressed(x, y, button);
} 

注意

如果你不拥有要检查键的屏幕,你可以在Forge事件总线上监听ScreenEvent$KeyPressed的Pre或Post事件。

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

// 在某个Screen子类中
@Override
public boolean mouseClicked(double x, double y, int button) {
  if (EXAMPLE_MAPPING.get().isActiveAndMatches(InputConstants.TYPE.MOUSE.getOrCreate(button))) {
    // 在此处执行鼠标单击时的逻辑
    return true;
  }
  return super.mouseClicked(x, y, button);
} 

注意

如果你不拥有要检查鼠标的屏幕,你可以在Forge事件总线上监听ScreenEvent$MouseButtonPressed的Pre或Post事件。

Built with MkDocs using a custom theme. Hosted by Read the Docs.
Enable Dark Theme