Files
XCEngine/docs/api/XCEngine/Input/InputManager/InputManager.md

7.4 KiB

InputManager

命名空间: XCEngine::Input

类型: class (singleton)

头文件: XCEngine/Input/InputManager.h

描述: 保存当前输入状态、提供轮询查询接口,并同步广播输入事件。

概述

InputManager 是 XCEngine 当前输入系统的核心入口。平台层通过 ProcessKeyDownProcessMouseMove 等方法把原始输入送进来;游戏代码、编辑器和测试代码则通过 IsKeyDownGetAxisGetButtonDownOnKeyEvent 等 API 查询或订阅这些状态。

它同时承担两种角色:

  • 轮询中心
    • 保存“当前是否按住”“本帧是否刚按下”“本帧是否刚释放”“本帧鼠标位移 / 滚轮”等状态
  • 事件中心
    • 把输入变化同步广播给订阅者

当前帧状态模型

当前实现内部至少维护四组和键鼠查询直接相关的状态:

状态层 键盘 鼠标 作用
按住态 m_keyDown m_mouseButtonDown 回答 IsKeyDown() / IsMouseButtonDown() / GetAxis() / GetButton() / IsAnyKeyDown()
按下边沿 m_keyDownThisFrame m_mouseButtonDownThisFrame 回答 IsKeyPressed() / IsMouseButtonClicked() / GetButtonDown() / IsAnyKeyPressed()
上一帧按下边沿 m_keyDownLastFrame m_mouseButtonDownLastFrame 帮助判断“这一帧是否第一次按下”
释放边沿 m_keyUpThisFrame m_mouseButtonUpThisFrame 回答 IsKeyReleased() / IsMouseButtonReleased() / GetButtonUp()

这里要特别区分两组很容易混淆的接口:

  • IsKeyUp() / IsMouseButtonUp()
    • 只是“当前没有按住”
    • 等价于 !IsKeyDown() / !IsMouseButtonDown()
  • IsKeyReleased() / IsMouseButtonReleased()
    • 是“本帧刚释放”
    • 依赖 ProcessKeyUp() / ProcessMouseButton(..., false, ...) 写入的释放边沿缓存

生命周期

  • Get 返回进程级单例。
  • Initialize 分配内部状态数组、保存窗口句柄并注册默认轴/按钮。
  • Shutdown 会清空状态和映射,但当前不会清空事件监听器。
  • Update 用于推进帧边界并清理瞬时状态。

默认映射

当前 Initialize() 会注册以下默认逻辑项:

  • 轴:Horizontal (D / A)、Vertical (W / S)
  • 轴:Mouse XMouse Y
    • 但两者当前都绑定为 KeyCode::None
    • 因此 GetAxis() / GetAxisRaw() 结果始终为 0.0f
  • 按钮:Jump (Space)、Fire1 (LeftCtrl)、Fire2 (LeftAlt)、Fire3 (LeftShift)

当前实现行为

  • GetAxisGetAxisRaw 当前使用同一套实现,都会根据持续按住状态返回 -1.0f / 0.0f / 1.0f
  • 逻辑按钮当前只是“名字到 KeyCode”的映射;GetButtonDown() / GetButtonUp() 仍然分别转发到键盘的按下边沿 / 释放边沿查询。
  • IsAnyKeyDownIsAnyKeyPressed 会同时统计键盘和鼠标按键,不只是键盘。
  • ProcessKeyDown 不会因为 repeat == true 而跳过按下缓存写入,所以 IsKeyPressed() / GetButtonDown() / IsAnyKeyPressed() 反映的是“这一帧是否收到按下消息”,不保证只对应首次物理按下。
  • m_buttonDownThisFrame / m_buttonDownLastFrame 当前只在 Update 中维护,还没有成为逻辑按钮查询的主来源。

线程语义

  • 当前实现没有锁,也不是为多线程输入注入设计的。
  • Process*Update()、注册映射和查询最好都在主线程或同一逻辑线程完成。
  • 事件回调同步执行在调用 Process* 的线程上。

当前实现限制

  • platformWindowHandle 会被保存,但 InputManager 当前并不直接使用它。
  • KeyCode 数值存在重复项,而 InputManager 用原始枚举值索引固定数组,因此部分按键状态会别名冲突。
  • GetAxisRaw() 当前和 GetAxis() 没有行为差异。
  • 键盘按下边沿接口不屏蔽平台重复按键消息。
  • ClearAxes() 会同时清空 m_axesm_buttons
  • 触摸接口已暴露,但当前实现没有任何公开路径去填充 m_touches
  • Shutdown() 不会清空事件监听器;如果单例跨生命周期反复初始化,需要调用方自己解除订阅。

公开方法

方法 说明
Get 获取全局 InputManager 实例。
Initialize 初始化输入状态和默认映射。
Shutdown 清空输入状态与映射。
Update 推进帧边界并清理瞬时状态。
IsKeyDown 查询键是否处于按下状态。
IsKeyUp 查询键是否处于抬起状态。
IsKeyPressed 查询键是否在本帧刚被按下。
IsKeyReleased 查询键是否在本帧刚被释放。
GetMousePosition 读取当前鼠标位置。
GetMouseDelta 读取本帧鼠标位移。
GetMouseScrollDelta 读取本帧滚轮增量。
IsMouseButtonDown 查询鼠标按键是否按下。
IsMouseButtonUp 查询鼠标按键是否抬起。
IsMouseButtonClicked 查询鼠标按键是否在本帧刚被按下。
IsMouseButtonReleased 查询鼠标按键是否在本帧刚被释放。
GetTouchCount 读取触点数量。
GetTouch 读取指定触点状态。
GetAxis 读取具名逻辑轴。
GetAxisRaw 读取具名逻辑轴的当前原始值。
GetButton 查询具名按钮当前是否按下。
GetButtonDown 查询具名按钮是否在本帧刚按下。
GetButtonUp 查询具名按钮是否在本帧刚释放。
IsAnyKeyDown 查询是否存在任意键盘键或鼠标键处于按住状态。
IsAnyKeyPressed 查询是否存在任意键盘键或鼠标键在本帧刚被按下。
RegisterAxis 注册或覆盖一个具名轴。
RegisterButton 注册或覆盖一个具名按钮。
ClearAxes 清空轴和按钮映射。
OnKeyEvent 获取键盘事件通道。
OnMouseButton 获取鼠标按键事件通道。
OnMouseMove 获取鼠标移动事件通道。
OnMouseWheel 获取鼠标滚轮事件通道。
OnTextInput 获取文本输入事件通道。
ProcessKeyDown 注入按键按下事件。
ProcessKeyUp 注入按键抬起事件。
ProcessMouseMove 注入鼠标移动事件。
ProcessMouseButton 注入鼠标按键事件。
ProcessMouseWheel 注入鼠标滚轮事件。
ProcessTextInput 注入文本输入事件。

真实行为依据

  • engine/src/Input/InputManager.cpp
  • tests/Input/test_input_manager.cpp

相关文档