如何在 Swift 中读取 ANSI 转义码响应值? [英] How to read ANSI Escape code response value in Swift?

查看:18
本文介绍了如何在 Swift 中读取 ANSI 转义码响应值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm playing around with ANSI code (ESC sequence) using Swift as a console app. Sending an ESC command is trivial, such as setting text color. However, reading a response value from an ESC command is challenging. Here's a simple test program:

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

程序发送[6n获取当前光标位置,控制台返回[;R代码>字符串.以下是问题:

The program sends <ESC>[6n to get the current cursor position and the console would return <ESC>[<line>;<column>R string. Here are the problems:

  1. readLine() 一直等待输入,直到用户按下 Return 或 Enter 键.我认为一旦输入缓冲区变空它会自动停止读取.
  2. readLine() 奇怪的是似乎没有从控制台读取响应值,尽管它清楚地打印在屏幕上.发生了什么事?
  3. 响应值打印在控制台上.我想静静地使用它,就像 print() 打印 ESC 命令的方式一样.有没有办法将标准输入临时重定向到变量中?
  1. readLine() keeps waiting for input until user press Return or Enter key. I thought it will automatically stop reading once the input buffer gets empty.
  2. readLine() strangely doesn't seem to read the response value from the console although it's clearly printed on the screen. What's is happening?
  3. The response value is printed on the console. I'd like to have it silently, like the way print() prints the ESC command. Is there a way to temporarily redirect standard input into a variable?

系统:
• MacOS Mojave
• XCode 10
• 斯威夫特 4.2
• 在终端应用上运行

System:
• MacOS Mojave
• XCode 10
• Swift 4.2
• run on Terminal app

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

I've been looking at GitHub and Google to find some answers, but I got no luck. So, would anyone here give me a hint where to start solving this problem? Thank you.

问候,

~蜜蜂

推荐答案

默认情况下终端处于规范输入处理"中模式,这意味着在输入和处理完整行之前,读取请求不会返回.tcsetattr() 函数用于禁用输入处理和回显,参见示例

A terminal is by default in "canonical input processing" mode, which means that a read request will not return until an entire line has been typed and processed. The tcsetattr() function is used to disable both the input processing and echo, see for example

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

and the tcsetattr(3) and termios(4) manual pages.

这是一个简单的 Swift 示例,灵感来自上述问答中的 C 代码,以及 Xcode Swift 命令行工具从键盘读取 1 个字符而无需回声或需要按回车:

Here is a simple example in Swift, inspired by the C code in the above Q&As, and also by 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

请注意,这仅在终端窗口中运行时才有效,在 Xcode 中无效.

Note that this works only when run in a Terminal window, not within Xcode.

这篇关于如何在 Swift 中读取 ANSI 转义码响应值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆