如何在Windows 10上与CSCRIPT一起使用ANSI转义序列?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (62)

我正在尝试使用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输出的转义序列直接写入屏幕时无效,只有先写入文件然后再打字才能工作,或者由FOR / F和ECHOed捕获。

我有两个问题:

1)为什么直接写入控制台不能从CSCRIPT工作? 2)如何直接写作?

我想在我的JREPL.BAT正则表达式查找/替换实用程序(因此批处理文件标记)中添加文本突出显示,但如果它需要临时文件和/或FOR / F,我将不会实现该功能。

提问于
用户回答回答于

MS文档说明

如果使用SetConsoleMode标志在屏幕缓冲区句柄上设置了ENABLE_VIRTUAL_TERMINAL_PROCESSING标志,则在写入输出流时,控制台主机会截获以下终端序列 。您可以使用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。结果是

现在,处理和处理输出cscriptfindstr解释转义序列。

此外,如果不是运行单独的程序,我cmd.exe自己运行

由于我没有更改代码findstr.execscript.exe或者cmd.exe只是它们正在工作的环境,似乎是这样

  • 既不cscript也不findstr配置/改变控制台缓冲器配置
  • 一些内部cmd命令改变它的缓冲器配置(I忘记将其包括在所述捕获,但copy test.txt conprompt也可以),或者如你点,它们使用不同的输出方法
  • 写入标准输出流的应用程序的唯一要求是正确配置控制台输出缓冲区模式。

不,我不知道如何从纯批次启用它。

用户回答回答于

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

我终于在这个SuperUser答案中找到了一种在CSCRIPT中启用VT-100序列的机制。我从答案中复制了相关文本并将其发布在下面。

幸运的是,全局默认值可以从选择加入更改为选择退出。注册表项HKEY_CURRENT_USER\Console\VirtualTerminalLevel设置处理ANSI转义序列的全局默认行为。创建DWORD密钥(如有必要)并将其值设置为默认情况下1全局启用(或0禁用)ANSI处理。 [HKEY_CURRENT_USER \控制台] “VirtualTerminalLevel”= DWORD:00000001 请注意,此注册表设置控制默认值,这意味着它仅影响未通过调用显式操作控制台模式的控制台应用程序SetConsoleMode(...)。由此可见,虽然注册表值可能有助于为控制台模式不经意的应用程序启用 ANSI ,但它对任何控制台模式 - 精明的应用程序(由于某种原因)可能明确禁用 ANSI 没有任何影响。

请注意,更改仅影响新启动的控制台窗口 - 它不会为现有的控制台窗口启用VT-100。

此线程中,DosTips用户aGerman发现您可以通过在脚本中异步启动PowerShell来启用转义序列。PowerShell配置输出以支持转义序列,并且只要您的CSCRIPT进程保持活动状态,即使在PowerShell退出后该支持仍然存在。

例如,下面是一些将启用序列的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文档描述将转义序列发送到控制台所需的机制。

扫码关注云+社区

领取腾讯云代金券