如何在Swift中读取ANSI Escape代码响应值?

时间:2018-12-03 04:52:13

标签: swift macos ansi

我正在使用Swift作为控制台应用程序来处理ANSI代码(ESC序列)。发送ESC命令很简单,例如设置文本颜色。但是,从ESC命令读取响应值具有挑战性。这是一个简单的测试程序:

print("Get cursor position:", "\u{1b}[6n", terminator: "")
let s = readLine()!
print(s)

程序将发送<ESC>[6n以获取当前光标位置,并且控制台将返回<ESC>[<line>;<column>R字符串。这里有问题:

  1. readLine()一直在等待输入,直到用户按Return或Enter键。我认为一旦输入缓冲区为空,它将自动停止读取。
  2. readLine()似乎没有从控制台读取响应值,尽管它清楚地打印在屏幕上。发生了什么事?
  3. 响应值打印在控制台上。我想安静地使用它,就像print()打印ESC命令的方式一样。有没有办法将标准输入临时重定向到变量?

系统:
•MacOS Mojave
•XCode 10
•Swift 4.2
•在终端应用上运行

我一直在GitHub和Google上寻找答案,但是我没有运气。那么,这里有人可以给我一个提示,从哪里开始解决这个问题?谢谢。

此致

〜蜜蜂

1 个答案:

答案 0 :(得分:0)

默认情况下,终端处于“规范输入处理”模式,这意味着在键入和处理了整行之前,读请求将不会返回。 tcsetattr()函数用于禁用输入处理和回显,例如参见

以及tcsetattr(3)termios(4)手册页。

这是Swift中的一个简单示例,受上述问答中的C代码以及Xcode Swift Command Line Tool reads 1 char from keyboard without echo or need to press return的启发:

// Write escape sequence:
write(STDOUT_FILENO, "\u{1b}[6n", 4)

// Save terminal attributes:
var oldt = termios()
tcgetattr(STDIN_FILENO, &oldt)

// Disable canonical input processing and echo:
var newt = oldt
newt.c_lflag &= ~tcflag_t(ICANON)
newt.c_lflag &= ~tcflag_t(ECHO)
tcsetattr(STDIN_FILENO, TCSANOW, &newt)

// Read response:
var response: [UInt8] = []
var c: UInt8 = 0
repeat {
    read(STDIN_FILENO, &c, 1)
    response.append(c)
} while c != UInt8(ascii: "R")

// Restore original terminal attributes:
tcsetattr(STDIN_FILENO, TCSANOW, &oldt)

print(response) // [27, 91, 52, 59, 49, 82] == ESC[4;1R