如何读取 Swift 中的 ANSI Escape 代码响应值?
How to read ANSI Escape code response value in Swift?
我正在使用 Swift 作为控制台应用程序来处理 ANSI 代码(ESC 序列)。发送 ESC 命令很简单,例如设置文本颜色。但是,从 ESC 命令读取响应值具有挑战性。这是一个简单的测试程序:
print("Get cursor position:", "\u{1b}[6n", terminator: "")
let s = readLine()!
print(s)
程序发送<ESC>[6n
获取当前光标位置,控制台将return<ESC>[<line>;<column>R
字符串。以下是问题:
readLine()
一直等待输入,直到用户按下 Return 或回车键。我以为输入缓冲区变空后它会自动停止读取。
readLine()
奇怪的是似乎没有从控制台读取响应值,尽管它清楚地打印在屏幕上。发生什么事了?
- 响应值打印在控制台上。我想静静地拥有它,就像
print()
打印 ESC 命令的方式一样。有没有办法暂时将标准输入重定向到变量?
系统:
• MacOS Mojave
• XCode 10
• Swift 4.2
• 运行 在终端应用程序上
我一直在查看 GitHub 和 Google 以找到一些答案,但我没有找到答案。那么,这里有人会提示我从哪里开始解决这个问题吗?谢谢。
此致,
~蜜蜂
终端默认处于“规范输入处理”模式,这意味着读取请求不会return直到整行被键入和处理。 tcsetattr()
函数用于禁用输入处理和回显,例如参见 [=17=]
- Reading the Device Status Report ANSI escape sequence reply
以及 tcsetattr(3)
和 termios(4)
手册页。
这里是 Swift 中的一个简单示例,灵感来自上述问答中的 C 代码,以及 Xcode Swift Command Line Tool reads 1 char from keyboard without echo or need to press return:
#if os(Linux)
import Glibc
#else
import Darwin
#endif
// 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
请注意,这仅在 运行 在终端 window 中有效,而不是在 Xcode.
中
我正在使用 Swift 作为控制台应用程序来处理 ANSI 代码(ESC 序列)。发送 ESC 命令很简单,例如设置文本颜色。但是,从 ESC 命令读取响应值具有挑战性。这是一个简单的测试程序:
print("Get cursor position:", "\u{1b}[6n", terminator: "")
let s = readLine()!
print(s)
程序发送<ESC>[6n
获取当前光标位置,控制台将return<ESC>[<line>;<column>R
字符串。以下是问题:
readLine()
一直等待输入,直到用户按下 Return 或回车键。我以为输入缓冲区变空后它会自动停止读取。readLine()
奇怪的是似乎没有从控制台读取响应值,尽管它清楚地打印在屏幕上。发生什么事了?- 响应值打印在控制台上。我想静静地拥有它,就像
print()
打印 ESC 命令的方式一样。有没有办法暂时将标准输入重定向到变量?
系统:
• MacOS Mojave
• XCode 10
• Swift 4.2
• 运行 在终端应用程序上
我一直在查看 GitHub 和 Google 以找到一些答案,但我没有找到答案。那么,这里有人会提示我从哪里开始解决这个问题吗?谢谢。
此致,
~蜜蜂
终端默认处于“规范输入处理”模式,这意味着读取请求不会return直到整行被键入和处理。 tcsetattr()
函数用于禁用输入处理和回显,例如参见 [=17=]
- Reading the Device Status Report ANSI escape sequence reply
以及 tcsetattr(3)
和 termios(4)
手册页。
这里是 Swift 中的一个简单示例,灵感来自上述问答中的 C 代码,以及 Xcode Swift Command Line Tool reads 1 char from keyboard without echo or need to press return:
#if os(Linux)
import Glibc
#else
import Darwin
#endif
// 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
请注意,这仅在 运行 在终端 window 中有效,而不是在 Xcode.
中