Неясное поведение ANSI CUB/CUF

#c #escaping #ansi

Вопрос:

Изучая контрольные последовательности ANSI, я столкнулся с неясным поведением.

Я попытался создать эффект «матрицы» в терминале, который изменяет одну случайную цифру за итерацию цикла в строке из n 0/1 цифр:

 #include <iostream>
#include <chrono>
#include <thread>

const int n = 5; // row length
const int pause = 50; // milliseconds

int main() {
    using namespace std;
    using this_thread::sleep_for;
    using chrono::milliseconds;

    for (int i = 0; i < n; i  ) {
      cout << rand() % 2;
    }

    int offset;
    while (true) {
      offset = rand() % n   1; // random digit in row 1..n

      cout << "x1b[" << offset << "D";
      cout.flush();
      sleep_for(milliseconds(pause));

      cout << rand() % 2;
      cout.flush();
      // cout << "x1b[" << 1 << "D";
      // cout.flush();
      sleep_for(milliseconds(pause));

      cout << "x1b[" << offset - 1 << "C";
      cout.flush();
      sleep_for(milliseconds(pause));
    }
}

 

Насколько я понимаю, криминалист офсетной Д перемещает курсор назад офсетной раз, если это возможно в текущей строке, а затем я cout случайная цифра, что перемещает курсор вперед 1 раз, затем я использую криминалист смещение — 1 С , чтобы переместить его вперед смещение — 1 раз, то следует вернуться курсор N 1 для строк позиций, поэтому Н цифр идти до курсора, но иногда идет дальше, чем Н 1, значит, после нескольких итераций он заканчивается в конце строки. Я хотел бы знать, почему это происходит.

Однако, когда я использую cout << "x1b[" << 1 << "D"; , а затем cout << "x1b[" << offset << "C"; вместо cout << "x1b[" << offset - 1 << "C"; этого это работает нормально.

Я также знаю об использовании CSI n G, который также отлично работает, но я хочу понять, что происходит с CSI n C/D. Может быть, это моя математическая ошибка, но не использовать cout << "x1b[" << 1 << "D"; , похоже, равносильно использованию cout << "x1b[" << offset - 1 << "C"; , так что это действительно сбивает меня с толку.

Комментарии:

1. Почему вы перемещаете курсор сначала назад, а затем вперед? И почему offset - 1 — как только вы напишете цифру, вам придется вернуться еще на одну, так что это так offset 1 . Оч — вы хотите, чтобы курсор «оставался» справа?

2. После того, как for петли уже по N цифр в строке (е.G, если н = 5, то позиция курсора находится в 6), так что придется возвращаться offset раз (скажем, 3, поэтому курсор находится в 6 — 3 = 3 позиции), а затем cout перемещает его 1 раз вперед (3 1 = 4), то у меня переместить его offset - 1 вперед (4 (3 — 1) = 6).

Ответ №1:

Кажется, что x1b[0C курсор перемещается вправо, по крайней мере, на моем терминале (не знаю, указано ли это/требуемое поведение).

 $ printf "ax1b[0Cbn"
a b
$ printf "ax1b[1Cbn"
a b
 

Проверьте offset - 1 , не равно ли нулю.

 if (offset - 1) {
  cout << "x1b[" << offset - 1 << "C";
}
 

Комментарии:

1. Большое спасибо, он действительно перемещает его 1 раз, если я делаю это, используя 0 в качестве offset значения (для CSI n D работает одинаково). Как я понимаю, это происходит, когда offset равно 1, значит offset - 1 , равно 0, поэтому CUF все равно перемещает его