【问题标题】:How to use ANSI escape sequences with CSCRIPT on Windows 10?如何在 Windows 10 上使用 ANSI 转义序列和 CSCRIPT?
【发布时间】:2016-12-11 06:54:11
【问题描述】:

我正在尝试使用带有 CSCRIPT (JScript) 的 Windows 10 控制台中提供的新 VT100 ANSI 转义序列功能。但我无法让它工作。

这是一个非常简单的 JScript 脚本:

test.js

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

我做了很多测试,CSCRIPT 输出的转义序列在直接写入屏幕时是无效的,只有先写入文件然后 TYPE 才有效,否则由 FOR /F 和 ECHO 捕获.

我有两个问题:

1) 为什么不能从 CSCRIPT 直接写入控制台?
2) 我怎样才能让直接写入工作?

我想在我的 JREPL.BAT regular expression find/replace utility 中添加文本突出显示(因此是 标记),但如果它需要临时文件和/或 FOR /F,我将不会实现该功能。

【问题讨论】:

  • 您是否尝试将其通过“更多”管道传输或将其重定向到 CON?
  • @jeb - MORE 测试已经在问题中(没有帮助),我还尝试重定向到 CON(未显示,仍然没有帮助)。我发现如果我通过ANSICON, 运行测试,或者通过管道到ANSICON,或者作为ANSICON 命令行参数,或者作为ANSICON 进程的命令行命令,它工作正常。

标签: batch-file batch-file windows-10 ansi-escape wsh


【解决方案1】:

MS documentation 状态

以下终端序列被控制台主机截获 当写入输出流时,如果 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.exemingw/gcc。结果是

现在,处理来自cscriptfindstr 的输出并解释转义序列。

另外,如果我不运行单独的程序,而是运行cmd.exe 本身

由于我没有从findstr.execscript.execmd.exe 更改代码,因此只有他们工作的环境似乎

  • cscriptfindstr 都不配置/更改控制台缓冲区配置

  • 一些内部cmd 命令会更改缓冲区配置(我忘记将其包含在捕获中,但copy test.txt conprompt 也可以)或者,正如您所指出的,它们使用不同的输出方法

  • 写入标准输出流的应用程序的唯一要求是正确配置控制台输出缓冲区模式。

不,我不知道如何从纯批处理中启用它。

【讨论】:

  • 是的!我终于在 SuperUser 帖子中找到了一种为 CSCRIPT(或任何不禁用它的控制台应用程序)启用 VT-100 的方法。请参阅我的更新答案。
  • @dbenham,“是的!!”,我必须同意你的看法。似乎有some 的副作用使其处于活动状态,但这是一个非常好的发现和一种新的探索方式。谢谢。
【解决方案2】:

更新了第 2 部分的答案:如何使其在 CSCRIPT 中工作

我终于在this SuperUser answer 找到了在 CSCRIPT 中启用 VT-100 序列的机制。我从答案中复制了相关文字并发布在下面。

幸运的是,全局默认值可以从 opt-in 更改为 opt-outHKEY_CURRENT_USER\Console\VirtualTerminalLevel 处的注册表项设置处理 ANSI 转义序列的全局默认行为。创建一个DWORD 键(如有必要)并将其值设置为1 以默认全局启用(或0 以禁用`)ANSI 处理。

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

请注意,此注册表设置控制 默认值,这意味着它仅影响未通过调用 SetConsoleMode(...) 显式操作控制台模式的控制台应用程序。因此,虽然注册表值可能有助于 console-mode-oblivious 应用程序启用 ANSI,但它不会影响任何 console-mode-savvy 应用程序(出于某种原因)可能会显式禁用 ANSI。

请注意,此更改仅影响新启动的控制台窗口 - 它不会为已经存在的控制台窗口启用 VT-100。


this thread 内,DosTips 用户 aGerman 发现您可以通过在脚本中异步启动 PowerShell 来启用转义序列。 PowerShell 将输出配置为支持转义序列,并且即使在 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 中不起作用

好的,我想我有一个可行的理论来解释为什么它不起作用。我相信必须有一些低级的方式/调用/功能/方法(无论如何)将标准输出传递到只有少数内部命令知道的控制台。我基于 FINDSTR 也无法将正常的转义序列发送到控制台这一事实,如下所示:

我已经证明 TYPE 和 ECHO 都可以工作。我还验证了 SET /P 是否有效(未显示)。所以我怀疑 cmd.exe 被修改为支持新的 Windows 10 控制台功能。

我希望看到一些 MS 文档描述了向控制台发送转义序列所需的机制。

【讨论】:

    猜你喜欢
    • 2016-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-14
    • 2015-08-14
    相关资源
    最近更新 更多