Как использовать escape-последовательности ANSI с CSCRIPT в Windows 10?

Я пытаюсь использовать новые возможности управляющей последовательности VT100 ANSI, доступные в консоли Windows 10, с помощью CSCRIPT (JScript). Но я не могу заставить его работать.

Вот действительно простой сценарий JScript:

test.js

WScript.Echo('\x1B[7mReverse\x1B[0m Normal');
WScript.stdout.WriteLine('\x1B[7mReverse\x1B[0m Normal');

Я провел ряд тестов, и escape-последовательности, выводимые CSCRIPT, бессильны при записи непосредственно на экран и работают только в том случае, если сначала записаны в файл, а затем введены в TYPE, или же захвачены FOR /F и ECHOed.

введите описание изображения здесь

У меня есть два вопроса:

1) Почему не работает прямая запись в консоль из CSCRIPT?
2) Как заставить работать прямую запись?

Я хочу добавить выделение текста в регулярное выражение JREPL.BAT для поиска/замены утилита (отсюда и batch-file), но я не буду реализовывать эту функцию, если для этого требуется временный файл и/или FOR /F.


person dbenham    schedule 05.08.2016    source источник
comment
Вы пытались передать его через «больше» или перенаправить в CON?   -  person jeb    schedule 07.08.2016
comment
@jeb - тест MORE уже находится в вопросе (без помощи), и я также попытался перенаправить на CON (не показано и все еще не помогает). Я обнаружил, что он отлично работает, если я запускаю тест через ANSICON либо через канал в ANSICON, либо как Аргумент командной строки ANSICON или как команда командной строки для процесса ANSICON.   -  person dbenham    schedule 07.08.2016


Ответы (2)


В документации MS указано

Следующие терминальные последовательности перехватываются хостом консоли при записи в выходной поток, если флаг ENABLE_VIRTUAL_TERMINAL_PROCESSING установлен в дескрипторе экранного буфера с помощью флага SetConsoleMode. Вы можете использовать флаги GetConsoleMode и SetConsoleMode для настройки этого поведения.

Итак, просто для проверки я написал простую программу на C, чтобы изменить режим консоли, а затем действовать как канал или запустить другой процесс и ждать (извините, просто тестовый код).

#define _WIN32_WINNT   0x0500
#include <windows.h>
#include <stdio.h>
#include <tchar.h>

#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004

int _tmain(int argc, TCHAR *argv[]){

    // Console handlers
    DWORD dwOldMode, dwMode ;
    HANDLE hStdout;

    // Pipe read buffer
    int c;

    // Spawn process variables
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    // Retrieve standard output handle
    hStdout = GetStdHandle( STD_OUTPUT_HANDLE );
    if (! GetConsoleMode( hStdout, &dwOldMode ) ) {
        return 1;
    }

    // Change standard output handle
    dwMode = dwOldMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    if (! SetConsoleMode( hStdout, dwMode ) ){
        CloseHandle( hStdout );
        return 2;
    }

    if( argc < 2 ) {
        // If there is not an argument, read stdin / write stdout 
        while ( EOF != (c = getchar()) ) putchar( c );    
    } else {
        // Argument is present, create a process and wait for it to end
        ZeroMemory( &si, sizeof(si) );
        si.cb = sizeof(si);
        ZeroMemory( &pi, sizeof(pi) );
        if( !CreateProcess(NULL, argv[1], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi )){
            printf( "CreateProcess failed (%d).\n", GetLastError() );
            return 3;
        }
        WaitForSingleObject( pi.hProcess, INFINITE );
        CloseHandle( pi.hProcess );
        CloseHandle( pi.hThread );    
    }

    // Restore old console mode
    SetConsoleMode( hStdout, dwOldMode );
    CloseHandle( hStdout );

    return 0;
};

Скомпилировано в run.exe с mingw/gcc. Результаты

Выходной захват тестовой сессии

Теперь выходные данные cscript и findstr обрабатываются, и управляющие последовательности интерпретируются.

Кроме того, если вместо запуска отдельных программ я запускаю саму cmd.exe

Выходной захват перенаправленного cmd.exe

Поскольку я не менял код с findstr.exe, cscript.exe или cmd.exe, только среда, в которой они работают, кажется, что

  • ни cscript, ни findstr не настраивают/не изменяют конфигурацию буфера консоли

  • некоторые внутренние cmd команды изменяют конфигурацию буфера (забываю включить в захват, но copy test.txt con и prompt тоже работают) или, как вы указываете, используют другой метод вывода

  • единственное требование для приложения, которое записывает в стандартный поток вывода, состоит в том, что режим буфера вывода консоли правильно настроен.

И нет, я не знаю, как включить его из чистого пакета.

person MC ND    schedule 09.09.2016
comment
Да!! Наконец-то я нашел способ включить VT-100 для CSCRIPT (или любого консольного приложения, которое его не отключает) в сообщении SuperUser. Смотрите мой обновленный ответ. - person dbenham; 07.05.2019
comment
@dbenham, Да!!, я должен с вами согласиться. Кажется, может быть некоторые побочные эффекты оставляют его активным, но это действительно хорошая находка и новый способ изучения. Спасибо. - person MC ND; 07.05.2019

Обновленный ответ на часть 2: как заставить его работать в CSCRIPT

Наконец-то я нашел механизм включения последовательностей VT-100 в CSCRIPT в этом ответе суперпользователя. Я скопировал соответствующий текст из ответа и разместил его ниже.

К счастью, глобальное значение по умолчанию можно изменить с включить на отказаться. Раздел реестра HKEY_CURRENT_USER\Console\VirtualTerminalLevel устанавливает глобальное поведение по умолчанию для обработки управляющих последовательностей ANSI. Создайте ключ DWORD (при необходимости) и установите для него значение 1, чтобы глобально включить (или 0, чтобы отключить`) обработку ANSI по умолчанию.

[HKEY_CURRENT_USER\Console]
"VirtualTerminalLevel"=dword:00000001

Обратите внимание, что этот параметр реестра управляет значением по умолчанию, а это означает, что он влияет только на консольные приложения, которые явно не манипулируют режимом консоли, вызывая SetConsoleMode(...). Из этого следует, что, хотя значение реестра может помочь включить ANSI для приложений console-mode-oblivious, оно никак не повлияет на console-mode-savvy< /em>, которое (по какой-то причине) может явным образом отключить ANSI.

Обратите внимание, что изменение затрагивает только вновь запущенные окна консоли — оно не активирует VT-100 для уже существующих окон консоли.


В этой теме пользователь DosTips aGerman обнаружил, что вы можете включить escape-последовательности, асинхронно запуская PowerShell из вашего скрипта. PowerShell настраивает выходные данные для поддержки escape-последовательностей, и эта поддержка остается даже после выхода из PowerShell, пока ваш процесс CSCRIPT остается активным.

Например, вот некоторый код JScript, который активирует последовательности

var ps = WScript.CreateObject("WScript.Shell").Exec("powershell.exe -nop -ep Bypass -c \"exit\"");
while (ps.Status == 0) WScript.Sleep(50);


Мой оригинальный ответ на часть 1: почему это не работает в CSCRIPT

Ладно, думаю, у меня есть жизнеспособная теория, почему это не работает. Я считаю, что должен быть какой-то низкоуровневый способ/вызов/функция/метод (независимо) для передачи stdout на консоль, о котором знают только несколько внутренних команд. Я основываю это на том факте, что FINDSTR также не может отправлять на консоль функционирующие управляющие последовательности, как показано ниже:

введите здесь описание изображения

Я уже показал, что и TYPE, и ECHO работают. Я также проверил, что SET /P работает (не показано). Поэтому я подозреваю, что cmd.exe был изменен для поддержки новых функций консоли Windows 10.

Я хотел бы увидеть некоторую документацию MS, описывающую необходимый механизм для отправки управляющих последовательностей на консоль.

person dbenham    schedule 07.08.2016