键盘子系统(CategoryKeyboard)
SDL 提供的键盘管理功能集,用于处理键盘设备检测、按键状态查询、文本输入等核心键盘交互逻辑。
关于不同类型程序中键盘输入的最佳实践,可参考官方文档:
https://wiki.libsdl.org/SDL3/BestKeyboardPractices
函数
- SDL_ClearComposition:清空当前的输入法候选文本(适用于中文/日文等输入法的组合输入状态)
- SDL_GetKeyboardFocus:获取当前拥有键盘焦点的 SDL 窗口(返回 SDL_Window 指针)
- SDL_GetKeyboardNameForID:根据键盘设备 ID 获取对应的设备名称(如 "USB Keyboard")
- SDL_GetKeyboards:枚举系统中所有已连接的键盘设备(返回设备 ID 列表及数量)
- SDL_GetKeyboardState:获取当前所有按键的状态(返回一个字节数组,索引为扫描码,值为 1 表示按下,0 表示释放)
- SDL_GetKeyFromName:根据按键名称(如 "A"、"Escape")获取对应的 SDL_Keycode(按键码,与键盘布局相关)
- SDL_GetKeyFromScancode:将 SDL_Scancode(扫描码,与硬件位置相关)转换为 SDL_Keycode(按键码)
- SDL_GetKeyName:根据 SDL_Keycode 获取对应的按键名称(如 SDLK_a 返回 "A")
- SDL_GetModState:获取当前的键盘修饰键状态(如 Shift/Ctrl/Alt 是否按下,返回 SDL_Keymod 组合值)
- SDL_GetScancodeFromKey:将 SDL_Keycode(按键码)转换为 SDL_Scancode(扫描码)
- SDL_GetScancodeFromName:根据扫描码名称(如 "ScanCode_A")获取对应的 SDL_Scancode
- SDL_GetScancodeName:根据 SDL_Scancode 获取对应的扫描码名称(如 SDL_SCANCODE_A 返回 "A")
- SDL_GetTextInputArea:获取当前设置的文本输入区域(用于移动平台虚拟键盘的位置适配)
- SDL_HasKeyboard:检查系统是否连接了至少一个键盘设备(返回布尔值)
- SDL_HasScreenKeyboardSupport:检查当前平台是否支持屏幕虚拟键盘(如手机/平板,返回布尔值)
- SDL_ResetKeyboard:重置键盘状态(清除所有按键按下状态,恢复修饰键为默认)
- SDL_ScreenKeyboardShown:检查屏幕虚拟键盘是否处于显示状态(返回布尔值)
- SDL_SetModState:手动设置键盘修饰键状态(仅用于模拟,不会实际改变物理按键状态)
- SDL_SetScancodeName:自定义扫描码的名称(覆盖系统默认名称)
- SDL_SetTextInputArea:设置文本输入区域(移动平台虚拟键盘会避开该区域显示)
- SDL_StartTextInput:启用文本输入功能(激活输入法,触发 SDL_TextInputEvent 事件)
- SDL_StartTextInputWithProperties:带属性的文本输入启用(指定输入类型,如数字/密码)
- SDL_StopTextInput:停止文本输入功能(禁用输入法,不再接收文本输入事件)
- SDL_TextInputActive:检查文本输入功能是否处于激活状态(返回布尔值)
数据类型
- SDL_KeyboardID:键盘设备唯一标识类型(用于区分多个连接的键盘设备)
结构体
- (无)
枚举
- SDL_Capitalization:文本大小写规则枚举(如 SDL_CAPITALIZATION_NONE/SDL_CAPITALIZATION_SENTENCES,用于控制输入文本的大小写)
- SDL_TextInputType:文本输入类型枚举(如 SDL_TEXT_INPUT_TYPE_TEXT/SDL_TEXT_INPUT_TYPE_NUMBER/SDL_TEXT_INPUT_TYPE_PASSWORD,限定输入内容类型)
宏
- (无)
FreeBASIC 示例代码
' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库)
#Include "SDL.bi"
' 辅助函数:打印修饰键状态
Sub PrintModState()
Dim As SDL_Keymod modState = SDL_GetModState()
Dim As String modStr = ""
If (modState And SDL_MOD_SHIFT) Then modStr &= "Shift "
If (modState And SDL_MOD_CTRL) Then modStr &= "Ctrl "
If (modState And SDL_MOD_ALT) Then modStr &= "Alt "
If (modState And SDL_MOD_GUI) Then modStr &= "GUI " ' Windows/Command 键
If (modStr = "") Then modStr = "无"
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "当前修饰键状态:%s", modStr)
End Sub
' 主程序
Dim As SDL_Window Ptr window = NULL
Dim As SDL_Event evt
Dim As UByte Ptr keyState = NULL
Dim As SDL_KeyboardID Ptr keyboardIDs = NULL
Dim As Integer keyboardCount = 0
Dim As Integer quit = 0
Dim As String inputText = ""
' 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. 检查键盘设备
If (Not SDL_HasKeyboard()) Then
SDL_LogError(SDL_LOG_CATEGORY_INPUT, "系统未检测到键盘设备")
SDL_Quit()
End 1
End If
' 枚举键盘设备
keyboardCount = SDL_GetKeyboards(0, NULL)
If (keyboardCount > 0) Then
keyboardIDs = Callocate(keyboardCount * SizeOf(SDL_KeyboardID))
keyboardCount = SDL_GetKeyboards(keyboardCount, keyboardIDs)
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "检测到 %d 个键盘设备", keyboardCount)
For i As Integer = 0 To keyboardCount - 1
Dim As ZString Ptr kbName = SDL_GetKeyboardNameForID(keyboardIDs[i])
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "键盘 %d:%s", i, kbName)
SDL_free(kbName)
Next
End If
' 3. 创建窗口
window = SDL_CreateWindow("SDL 键盘输入示例", _
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _
600, 400, SDL_WINDOW_SHOWN)
If (window = NULL) Then
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建窗口失败:%s", SDL_GetError())
SDL_Quit()
End 1
End If
' 4. 启用文本输入功能
SDL_StartTextInput()
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "文本输入功能已启用")
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== 键盘操作示例 ===")
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按 ESC 退出 | 按任意键测试按键检测 | 输入文本将显示在日志中 | 按 F1 打印修饰键状态")
' 5. 主事件循环
While (quit = 0)
' 获取当前按键状态(实时查询,非事件驱动)
keyState = SDL_GetKeyboardState(NULL)
' 处理事件队列
While (SDL_PollEvent(@evt))
Select Case evt.type
' 窗口关闭事件
Case SDL_QUITEVENT
quit = 1
' 键盘按键事件(按下/释放)
Case SDL_KEYDOWN
Select Case evt.key.keysym.sym
Case SDLK_ESCAPE
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "ESC 键按下,退出程序")
quit = 1
Case SDLK_F1
PrintModState()
Case Else
' 打印按键信息(扫描码 + 按键码 + 名称)
Dim As SDL_Scancode scancode = evt.key.keysym.scancode
Dim As SDL_Keycode keycode = evt.key.keysym.sym
Dim As ZString Ptr scName = SDL_GetScancodeName(scancode)
Dim As ZString Ptr kName = SDL_GetKeyName(keycode)
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, _
"按键按下 - 扫描码:%s (0x%X) | 按键码:%s (0x%X)", _
scName, scancode, kName, keycode)
SDL_free(scName)
SDL_free(kName)
End Select
' 文本输入事件(输入法处理后的完整文本)
Case SDL_TEXTINPUT
inputText &= *evt.text.text
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "文本输入:%s | 累计输入:%s", evt.text.text, inputText)
' 文本编辑事件(输入法组合状态,如中文拼音)
Case SDL_TEXTEDITING
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "文本编辑:%s (光标位置:%d,选择长度:%d)", _
evt.edit.text, evt.edit.start, evt.edit.length)
End Select
Wend
' 实时检测特定按键(非事件驱动)
If (keyState[SDL_SCANCODE_SPACE] = 1) Then
Static As Integer spacePressed = 0
If (Not spacePressed) Then
SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "空格键被按住(实时检测)")
spacePressed = 1
End If
Else
spacePressed = 0
End If
SDL_Delay(10)
Wend
' 6. 清理资源
SDL_StopTextInput()
If (keyboardIDs <> NULL) Then
Deallocate(keyboardIDs)
End If
SDL_DestroyWindow(window)
SDL_Quit()
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "程序正常退出,累计输入文本:%s", inputText)
End 0
总结
- SDL 键盘子系统分两类核心能力:
- 按键状态查询:
SDL_GetKeyboardState实时获取按键状态(非事件驱动),SDL_KEYDOWN/UP事件驱动检测; - 文本输入处理:
SDL_StartTextInput启用输入法,通过SDL_TEXTINPUT事件接收完整文本(适配多语言输入法);
- 按键状态查询:
- FreeBASIC 中使用时需区分「扫描码(Scancode)」和「按键码(Keycode)」:
- 扫描码:与硬件位置绑定(如 SDL_SCANCODE_A 始终对应键盘 A 键位置);
- 按键码:与键盘布局绑定(如不同语言键盘的 A 键可能对应不同 Keycode);
- 关键接口:
- 设备管理:
SDL_GetKeyboards/SDL_GetKeyboardNameForID; - 状态查询:
SDL_GetKeyboardState/SDL_GetModState; - 文本输入:
SDL_StartTextInput/SDL_TEXTINPUT事件。
- 设备管理:
评论一下?