如何在Swift Command Line Tool应用中获取非字符串类键盘输入
Swift 命令行程序实时读取特殊按键(方向键/修饰键)可行方案
核心原理
默认终端采用行缓冲模式,输入内容需要按下回车才会提交给程序,所以无法实现实时按键响应。我们可以通过POSIX标准终端控制接口修改终端属性,关闭行缓冲和输入回显,直接读取按键的原始转义序列,就能识别方向键、Shift组合键等特殊输入。
完整实现代码
import Foundation // 存储程序启动前的原始终端配置 private var originalTerm = termios() /// 开启终端原始模式,禁用行缓冲与输入回显 func enableRawMode() { tcgetattr(STDIN_FILENO, &originalTerm) var rawConfig = originalTerm rawConfig.c_lflag &= ~(UInt(ICANON | ECHO)) tcsetattr(STDIN_FILENO, TCSANOW, &rawConfig) } /// 恢复终端默认配置 func restoreOriginalMode() { tcsetattr(STDIN_FILENO, TCSANOW, &originalTerm) } // 注册程序退出回调,自动恢复终端配置,避免终端异常 atexit { restoreOriginalMode() } /// 读取按键输入,返回按键标识 func readKey() -> String? { var buffer = [CChar](repeating: 0, count: 4) let readByteCount = read(STDIN_FILENO, &buffer, 4) guard readByteCount > 0 else { return nil } // 匹配常见特殊按键转义序列,不同终端序列可自行打印buffer调整 switch (buffer[0], buffer[1], buffer[2]) { // 方向键 case (27, 91, 65): return "arrow_up" case (27, 91, 66): return "arrow_down" case (27, 91, 67): return "arrow_right" case (27, 91, 68): return "arrow_left" // 普通控制键 case (127, _, _): return "backspace" case (10, _, _): return "enter" // Shift+方向键 case (27, 91, 49): switch buffer[3] { case 65: return "shift_arrow_up" case 66: return "shift_arrow_down" case 67: return "shift_arrow_right" case 68: return "shift_arrow_left" default: break } // 普通字符按键 default: guard let scalar = UnicodeScalar(UInt8(buffer[0])) else { return nil } return String(scalar) } return nil } // 调用示例,可直接嵌入俄罗斯方块的主循环 enableRawMode() print("按键测试,按q退出") while true { if let key = readKey() { if key == "q" { break } print("触发按键:\(key)") // 这里添加俄罗斯方块的按键逻辑:移动、旋转、加速下落等 } // 控制游戏帧率,16ms对应约60帧 usleep(16000) }
Xcode运行配置说明
- Xcode内置控制台对特殊转义序列支持不完整,建议编译完成后直接在系统「终端」app中运行生成的可执行文件,按键识别兼容性最好
- 如果需要在Xcode调试时直接测试,可修改运行Scheme:打开
Product > Scheme > Edit Scheme > Run > Options,将「Launch」项的终端设置改为Use external terminal,运行时会自动唤起系统终端执行程序
Command键适配说明
Command键为系统级修饰键,默认会被终端.app拦截作为全局快捷键使用。如果必须使用Command键作为游戏操作,需要先在终端的「设置 > 描述文件 > 键盘」中手动修改快捷键映射,否则无法被程序捕获。更推荐使用Option/Shift键作为游戏功能键,不需要额外配置即可兼容绝大多数终端环境。
内容的提问来源于stack exchange,提问作者Kamran Maximoff
相关产品推荐
相关产品推荐

