Как прочитать значение ответа кода ANSI Escape в Swift? - PullRequest
0 голосов
/ 03 декабря 2018

Я играю с кодом ANSI (последовательность ESC), используя Swift в качестве консольного приложения.Отправка команды 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 голосов
/ 04 декабря 2018

Терминал по умолчанию находится в режиме «канонической обработки ввода», что означает, что запрос на чтение не вернется, пока не будет напечатана и обработана вся строка.Функция tcsetattr() используется для отключения как обработки ввода, так и эха, см., Например,

и справочные страницы tcsetattr(3) и termios(4).

Вот простой пример в Swift,Вдохновленный кодом C в приведенных выше вопросах и ответах, а также Инструмент командной строки Xcode Swift считывает 1 символ с клавиатуры без эха или необходимости нажимать 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
...