
我们在开发游戏时,经常会使用 WASD 控制角色移动。这种操作方式十分常见,代码实现也很简单。
但是,这里隐藏着一个容易被忽略的问题:
如果玩家的键盘不是 QWERTY 布局,WASD 还能保持原来的操作位置吗?
这个问题引出了游戏输入系统中的一个重要概念:物理按键映射(Physical Key Mapping)。
它不仅存在于 Unity 中,也是所有跨地区、跨平台游戏输入系统需要考虑的问题。
一、物理按键映射要解决什么问题?
1. 不同国家的键盘布局并不相同
我们熟悉的英文键盘通常采用 QWERTY 布局,但法国等地区常见的键盘采用 AZERTY 布局。

假设游戏使用以下代码检测玩家是否按下 W:
if (Input.GetKey(KeyCode.W))
{
MoveForward();
}
这里的 KeyCode.W 究竟代表什么?
有两种解释:
- 逻辑键值:寻找当前键盘布局中代表 W 的按键。
- 物理位置:寻找标准 QWERTY 键盘中 W 所在的位置。
在 QWERTY 键盘上,两种解释通常没有区别。但在 AZERTY 键盘上,它们就会产生不同的结果。
如果按照逻辑键值解释,玩家必须按下实际标记为 W 的键,原本紧凑的 WASD 操作布局就会被破坏。
如果按照物理位置解释,玩家按下相同位置的 Z 键,游戏仍然会执行前进操作。
2. 游戏关心的往往不是字符,而是位置
对于文字编辑器来说,按下 W 键通常意味着用户希望输入字母 W。
但对于游戏来说,W 往往只是一个操作约定,它真正表达的是:
玩家按下了左手容易触及、位于 S 上方的那个键,游戏应当执行前进动作。
也就是说,游戏控制关注的是按键的位置,而不是按键对应的字符。
物理按键映射正是为了解决这两种需求之间的冲突。
二、Unity Input Manager 如何解决这个问题?
1. Physical Keys 开关
Unity 旧版 Input Manager 提供了 Use Physical Keys 设置。
在 Unity 6.x 中,可以通过以下路径查看:
Edit → Project Settings → Input Manager
该选项决定 KeyCode 的映射依据:
| 设置 | 按键解释方式 | 结果 |
|---|---|---|
| 启用 Physical Keys | 按标准 QWERTY 物理位置映射 | 同一物理位置触发同一按键代码 |
| 禁用 Physical Keys | 按当前键盘布局及平台规则映射 | 相同按键代码可能对应不同物理位置 |
Unity 官方文档说明,启用后引擎使用通用 ANSI/ISO QWERTY 布局表示按键位置。
例如,KeyCode.Q 会对应标准 QWERTY 布局中第一排最左边的字母键位置,不管用户使用的是哪种语言布局。
值得注意的是,从 Unity 2022.1 开始,Use Physical Keys 默认启用。因此,在 Unity 6.3 LTS 中使用默认配置时,通常已经采用物理按键映射。
2. Physical Keys 不只影响 GetKey
以下代码使用 KeyCode 检测键盘状态:
Input.GetKey(KeyCode.W);
Input.GetKeyDown(KeyCode.W);
Input.GetKeyUp(KeyCode.W);
Physical Keys 会影响这些按键代码与实际键盘按键之间的对应关系。
与此同时,Input Manager 还允许开发者在虚拟轴中配置按键,例如:
Axis Name: Vertical
Positive Button: w
Negative Button: s
游戏代码再通过虚拟轴读取移动方向:
float vertical = Input.GetAxis("Vertical");
这里存在两个不同的映射层次:

这说明:
Physical Keys 解决的是"哪个实际按键对应哪个按键代码"的问题;虚拟轴和虚拟按钮解决的是"按键如何转换成游戏输入"的问题。
二者不是同一个概念。
3. Physical Keys 的局限性
虽然 Physical Keys 能够解决不同键盘布局带来的操作位置问题,但它并不是完整的键盘输入解决方案。
首先,它不能替代玩家自定义按键。例如,玩家希望使用方向键而不是 WASD,仍然需要游戏提供相应的输入映射。
其次,它也不能用于可靠的文字输入。
例如:
if (Input.GetKeyDown(KeyCode.A))
{
// 不应该简单认为用户输入了字符 'a'
}
按下一个键并不意味着一定产生一个字符。实际字符可能受到键盘布局、Shift 等修饰键以及输入法影响。
Unity 官方文档也明确指出,不应通过读取游戏按键来实现文字输入,特别是需要支持非拉丁字符时,应使用相应的文本输入与输入法机制,例如 Input.compositionString,或使用成熟的 UI 输入组件。
三、Unity Input System 如何处理物理按键映射?
Unity 新版 Input System 延续了物理位置优先的设计,但实现方式更加灵活。
与旧版 Input Manager 不同,新版系统不再需要通过 Physical Keys 开关切换整个系统的按键解释方式,而是将物理按键识别作为键盘输入的基础,同时允许开发者根据当前键盘布局查找按键。
1. 默认使用物理位置识别按键
在 Input System 中,读取 W 键可以这样写:
using UnityEngine.InputSystem;
bool pressed = Keyboard.current.wKey.isPressed;
这里的 wKey 并不意味着必须按下键帽印着 W 的按键,而是指标准美式 QWERTY 键盘中 W 所在的位置。
因此:
- 在 QWERTY 键盘上,按下 W 触发。
- 在 AZERTY 键盘上,按下相同位置的 Z 触发。
这种设计使游戏操作不再依赖当前键盘的语言布局。
2. 同时支持按字符查找按键
Input System 还提供了另一种能力:根据当前键盘布局中产生的字符查找对应按键。
例如,在 Input Action 中,可以使用两种绑定路径:
<Keyboard>/w
<Keyboard>/#(w)
它们的含义不同。
| 绑定路径 | 映射依据 | 在 AZERTY 布局中的含义 |
|---|---|---|
<Keyboard>/w |
物理位置 | 标准 QWERTY 的 W 位置,即 Z 键位置 |
<Keyboard>/#(w) |
当前布局产生的字符 | 当前布局中对应 w 字符的按键 |
这实际上是将物理按键映射与布局相关的按键映射从概念上区分开来,允许开发者根据具体需求选择。
需要注意,#(w) 是键盘布局相关的按键匹配机制,不等同于完整的文本输入,不能替代输入法。
3. 能够获取按键在当前布局中的显示名称
假设一个游戏使用 W 的物理位置表示前进。
在 QWERTY 键盘上,按键提示应该显示 W;但在 AZERTY 键盘上,更合理的提示应该是 Z。
Input System 提供了 displayName 属性:
using UnityEngine;
using UnityEngine.InputSystem;
public class KeyboardExample : MonoBehaviour
{
void Start()
{
var keyboard = Keyboard.current;
if (keyboard == null)
return;
Debug.Log(keyboard.keyboardLayout);
Debug.Log(keyboard.wKey.displayName);
}
}
keyboard.wKey.displayName 根据当前键盘布局返回按键的显示名称;键盘布局发生变化时,该名称也会更新。
这样就可以实现:
操作绑定保持不变,但显示给玩家的按键名称随键盘布局变化。
这种能力尤其适合游戏中的操作教程、按键提示和按键设置界面。
4. Input Manager 与 Input System 的比较
| 对比维度 | Input Manager | Input System |
|---|---|---|
| 物理位置映射 | 通过 Use Physical Keys 开关控制 | 默认采用物理位置 |
| 逻辑布局映射 | 关闭 Physical Keys 后采用布局及平台相关映射 | 可通过 #(字符) 匹配 |
| 物理按键检测 | Input.GetKey(KeyCode.W) |
Keyboard.current.wKey.isPressed |
| 获取布局相关显示名称 | 缺少同等级的直接按键控件接口 | KeyControl.displayName |
| 游戏动作映射 | Virtual Axis / Virtual Button | Input Actions / Bindings |
| 文本输入 | inputString、IME 相关 API、UI 输入组件 |
onTextInput、IME 支持及 UI 输入组件 |
二者最大的区别不在于能否支持物理按键映射,而在于设计方式。
Input Manager 主要通过一个全局配置决定键位解释方式;Input System 则提供更明确的物理按键、布局相关按键及文本输入接口。
不过,新版 Input System 并没有彻底消除键盘兼容性问题。特殊键盘、操作系统提供的键位信息以及硬件报告方式仍可能影响识别结果。
四、其他游戏引擎如何处理?
物理按键映射并不是 Unity 独有的功能。
不同引擎采用了不同的 API 设计,但底层面对的是同一个问题:如何区分玩家按下的键盘位置和这个位置所代表的字符。
1. Godot:明确区分物理键码与逻辑键码

Godot 将物理键码和逻辑键码设计为不同的输入信息,并提供相应的方法读取。
例如:
Input.is_physical_key_pressed(KEY_W)
表示检测标准 QWERTY 布局中 W 所在的物理位置。
而:
Input.is_key_pressed(KEY_W)
使用逻辑按键解释。
在键盘事件 InputEventKey 中,Godot 同时提供:
physical_keycode:代表按键的物理位置。keycode:代表布局相关的逻辑键码。unicode:用于表示相应字符信息。
Godot 官方明确推荐,对于 WASD 等游戏操作,优先使用物理按键检测,以避免不同地区键盘布局造成的问题。
Godot 的设计表明:物理按键和逻辑按键可以作为两种并存的数据,而不是必须在项目层面二选一。
2. SDL:从底层区分 Scancode 和 Keycode
Sdl 2.0.12 released! - SDL Announcements - Simple Directmedia Layer

SDL 是跨平台多媒体开发库,提供键盘、鼠标、窗口、音频等底层能力,也常用于游戏引擎和游戏程序。
在 SDL 中,两个概念被直接命名为:
| 类型 | 含义 |
|---|---|
SDL_Scancode |
按键的物理位置表示 |
SDL_Keycode |
经过当前键盘布局解释的键值 |
例如,SDL3 的键盘事件同时包含:
event.key.scancode;
event.key.key;
其中 scancode 用于识别物理位置,key 提供逻辑键值。SDL 的键值解释还允许某些兼容性选项,因此不能简单认为所有 Keycode 都严格对应某个字符。
SDL 的实现揭示了一个更基础的事实:
物理按键与逻辑键值的区分,并不是游戏引擎额外创造出来的概念,而是跨平台键盘输入抽象本身就需要处理的问题。
3. 不同引擎的共同点
综合 Unity、Godot 与 SDL,可以发现它们的设计虽然不同,但目标基本一致。
| 系统 | 物理位置 | 逻辑键值 |
|---|---|---|
| Unity Input Manager | Use Physical Keys 启用时 | 关闭后采用布局相关映射 |
| Unity Input System | Keyboard.current.wKey |
#(w) 布局相关匹配 |
| Godot | physical_keycode |
keycode |
| SDL | SDL_Scancode |
SDL_Keycode |
也就是说,物理按键映射不是 Unity 的特殊功能,而是跨平台输入系统的一种通用设计机制。
五、进一步理解:键盘输入实际上有三个层次
从前面的分析可以发现,仅仅将按键区分为物理按键和逻辑按键还不够。
因为实际开发中,我们还有第三种需求:文本输入。
这三个概念应该明确区分。

举一个例子。
假设玩家使用中文输入法,按下键盘上的 A 键。
从三个层次来看:
- 物理位置:按下标准 QWERTY 布局中 A 所在的位置。
- 逻辑键值:根据当前键盘布局解释为相应键值。
- 文本输入:输入法可能将它用于拼音组合,并不立即产生最终文本字符。
这也解释了为什么我们不应该使用 GetKey() 来实现聊天输入框。
GetKey() 的职责是检测按键状态,而不是处理完整的文字输入过程。
六、通用结论:游戏输入与文本输入需要不同的抽象
通过 Unity Input Manager、Input System、Godot 和 SDL 的对比,我们可以得到几个具有跨引擎适用性的结论。
第一,键盘输入必须区分物理位置、逻辑键值和文本字符。
它们分别回答不同的问题,不能简单地将按下某个键等同于输入某个字符。
第二,游戏控制通常优先考虑物理位置。
对于 WASD 移动等操作,保持按键的空间排列一致,通常比保持键帽字符一致更加重要。
第三,文本输入必须考虑键盘布局和输入法。
文本输入不是单纯的按键检测,它还涉及修饰键、字符组合、输入法候选和 Unicode 字符等处理。
第四,物理按键映射不等于游戏动作映射。
前者解决按键身份问题,后者解决按键与游戏行为的关系。例如,W 的物理位置可以映射为前进,也可以映射为跳跃,这属于游戏动作映射的职责。
第五,支持物理按键映射不代表不需要按键重绑定。
物理位置映射解决默认操作在不同键盘布局下的一致性问题;自定义绑定则解决玩家的个人偏好、设备差异和无障碍需求。二者应当配合使用。
最后,可以用一句话概括物理按键映射的设计思想:
游戏操作关心玩家按下了哪里,文本输入关心玩家最终输入了什么。物理按键映射让游戏控制摆脱对键盘语言布局的依赖。
这才是 Physical Keys 背后真正值得理解和掌握的通用设计原则。
参考文档