扫描码子系统(CategoryScancode)
该模块定义了键盘扫描码(Scancode)的核心枚举类型,扫描码用于标识键盘上物理按键的位置,而非按键上的符号。
关于扫描码的具体含义和最佳使用方式,请参考官方键盘使用最佳实践文档:
https://wiki.libsdl.org/SDL3/BestKeyboardPractices
函数
- (无)
数据类型
- (无)
结构体
- (无)
枚举
- SDL_Scancode:键盘扫描码枚举(每个值对应键盘上一个固定的物理位置,参考美式 QWERTY 键盘布局,与按键符号/键盘布局无关)
宏
- (无)
FreeBASIC 示例代码
' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库)
#Include "SDL.bi"
' 辅助函数:打印扫描码详细信息
Sub PrintScancodeInfo(ByVal scancode As SDL_Scancode)
' 获取扫描码名称
Dim As ZString Ptr scName = SDL_GetScancodeName(scancode)
' 扫描码转按键码(体现布局差异)
Dim As SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode)
Dim As ZString Ptr keyName = SDL_GetKeyName(keycode)
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, _
"扫描码:%d (0x%X) | 扫描码名称:%s | 对应按键码:0x%X | 按键名称:%s", _
scancode, scancode, scName, keycode, keyName)
' 释放字符串资源
SDL_free(scName)
SDL_free(keyName)
End Sub
' 模拟 WASD 移动(核心场景:基于物理位置的输入)
Sub HandleWASDMovement()
Static As Integer lastDirX = 0, lastDirY = 0
Dim As UByte Ptr keyStates = SDL_GetKeyboardState(NULL)
' 基于扫描码的物理位置检测(与布局无关)
Dim As Integer dirX = 0, dirY = 0
If (keyStates[SDL_SCANCODE_A]) Then dirX -= 1 ' A 键位置:左
If (keyStates[SDL_SCANCODE_D]) Then dirX += 1 ' D 键位置:右
If (keyStates[SDL_SCANCODE_W]) Then dirY -= 1 ' W 键位置:上
If (keyStates[SDL_SCANCODE_S]) Then dirY += 1 ' S 键位置:下
' 仅在方向变化时打印日志
If (dirX <> lastDirX Or dirY <> lastDirY) Then
If (dirX = 0 And dirY = 0) Then
SDL_LogInfo(SDL_LOG_CATEGORY_GAME, "停止移动")
Else
Dim As String dirStr = ""
If (dirY < 0) Then dirStr &= "上 "
If (dirY > 0) Then dirStr &= "下 "
If (dirX < 0) Then dirStr &= "左 "
If (dirX > 0) Then dirStr &= "右 "
SDL_LogInfo(SDL_LOG_CATEGORY_GAME, "移动方向:%s", dirStr)
End If
lastDirX = dirX
lastDirY = dirY
End If
End Sub
' 主程序
Dim As SDL_Window Ptr window = NULL
Dim As SDL_Event evt
Dim As Boolean quit = False
' 1. 初始化 SDL
If (SDL_Init(SDL_INIT_VIDEO) < 0) Then
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败:%s", SDL_GetError())
End 1
End If
' 2. 创建窗口
window = SDL_CreateWindow("SDL Scancode 示例", _
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _
800, 600, SDL_WINDOW_SHOWN)
If (window = NULL) Then
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建窗口失败:%s", SDL_GetError())
SDL_Quit()
End 1
End If
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== SDL_Scancode 核心示例 ===")
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "WASD:移动(基于物理位置)| 按任意键查看扫描码信息 | ESC:退出")
' 3. 主循环
While (Not quit)
' 每帧处理 WASD 移动(状态查询)
HandleWASDMovement()
' 处理事件队列
While (SDL_PollEvent(@evt))
Select Case evt.type
Case SDL_QUITEVENT
quit = True
Case SDL_EVENT_KEY_DOWN
' ESC 退出
If (evt.key.scancode = SDL_SCANCODE_ESCAPE) Then
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按下 ESC 键(扫描码),退出程序")
quit = True
Else
' 打印当前按键的扫描码信息
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "==== 按键物理位置信息 ====")
PrintScancodeInfo(evt.key.scancode)
End If
' 演示:扫描码转名称(自定义绑定场景)
If (evt.key.scancode = SDL_SCANCODE_SPACE) Then
Dim As ZString Ptr spaceName = SDL_GetScancodeName(SDL_SCANCODE_SPACE)
SDL_LogInfo(SDL_LOG_CATEGORY_GAME, "按下 %s 键(物理位置),触发跳跃", spaceName)
SDL_free(spaceName)
End If
End Select
Wend
SDL_Delay(10) ' 降低 CPU 占用
Wend
' 4. 清理资源
SDL_DestroyWindow(window)
SDL_Quit()
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "程序正常退出")
End 0
核心扫描码枚举说明
SDL_Scancode 枚举值完全对应美式 QWERTY 键盘的物理位置,以下是游戏开发中最常用的核心值:
| 扫描码常量 | 物理位置(美式键盘) | 典型用途 |
|---|---|---|
| SDL_SCANCODE_W | W 键 | 上/前进 |
| SDL_SCANCODE_A | A 键 | 左 |
| SDL_SCANCODE_S | S 键 | 下/后退 |
| SDL_SCANCODE_D | D 键 | 右 |
| SDL_SCANCODE_SPACE | 空格键 | 跳跃/确认 |
| SDL_SCANCODE_ESCAPE | ESC 键 | 取消/退出 |
| SDL_SCANCODE_SHIFT | Shift 键(左右均可) | 加速/大写 |
| SDL_SCANCODE_CTRL | Ctrl 键(左右均可) | 特殊操作 |
| SDL_SCANCODE_R | R 键 | 换弹/刷新 |
| SDL_SCANCODE_F1-F12 | F1-F12 功能键 | 功能快捷键 |
| SDL_SCANCODE_UP/DOWN/LEFT/RIGHT | 方向键 | 菜单导航/移动 |
扫描码 vs 按键码 核心区别
| 特性 | SDL_Scancode(扫描码) | SDL_Keycode(按键码) |
|---|---|---|
| 绑定对象 | 物理按键位置(与布局无关) | 按键符号(与布局相关) |
| 核心场景 | 游戏移动(WASD)、快捷键(物理位置) | 文本输入、通用按键(ESC/Enter) |
| 示例 | 法语键盘按 Z 键 → SDL_SCANCODE_W | 法语键盘按 Z 键 → SDLK_z |
| 稳定性 | 跨布局稳定(位置不变) | 跨布局变化(符号不变) |
总结
- SDL_Scancode 核心价值:绑定键盘物理位置,是游戏中「设备无关输入」的基础(如 WASD 移动在任何布局的键盘上都对应相同的手指位置);
- 使用场景:所有基于「物理按键位置」的输入(移动、射击、快捷键)都应优先使用扫描码;
- 关键配合函数:
SDL_GetKeyboardState:通过扫描码查询实时按键状态;SDL_GetScancodeName:获取扫描码的可读名称(用于配置界面);SDL_GetKeyFromScancode:扫描码转按键码(适配布局的符号显示)。
评论一下?