我正在尝试使用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 regular expression find/replace utility(因此batch-file标记)中添加文字突出显示,但如果它需要临时文件和/或FOR /F,我将不会实现该功能。 p>
答案 0 :(得分:6)
控制台主机拦截以下终端序列 当写入输出流时如果 使用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
。结果是
现在,处理cscript
和findstr
的输出并解释转义序列。
另外,如果不是运行单独的程序,而是运行cmd.exe
本身
由于我没有更改findstr.exe
,cscript.exe
或cmd.exe
的代码,只有他们正在使用它的环境似乎
cscript
和findstr
都没有配置/更改控制台缓冲区配置
一些内部cmd
命令会更改缓冲区配置(我忘记将其包含在捕获中,但copy test.txt con
和prompt
也可以工作)或者,正如您所指出的那样,使用不同的输出方法
写入标准输出流的应用程序的唯一要求是正确配置了控制台输出缓冲区模式。
不,我不知道如何从纯批次启用它。
答案 1 :(得分:3)
我终于找到了一种在this SuperUser answer的CSCRIPT中启用VT-100序列的机制。我复制了答案中的相关文字并将其发布在下面。
幸运的是,全局默认值可以从 opt-in 更改为 opt-out 。
HKEY_CURRENT_USER\Console\VirtualTerminalLevel
处的注册表项设置处理ANSI转义序列的全局默认行为。创建一个DWORD
密钥(如果需要)并将其值设置为1
以全局启用(或0
禁用`)默认情况下ANSI处理。[HKEY_CURRENT_USER\Console] "VirtualTerminalLevel"=dword:00000001请注意,此注册表设置控制默认,这意味着它仅影响未通过调用
SetConsoleMode(...)
显式操作控制台模式的控制台应用程序。因此,虽然注册表值可以帮助为控制台模式 - 不经意应用程序启用 ANSI,但它对任何 console-mode-savvy <没有任何影响/ em> app(由于某种原因)可以明确禁用 ANSI。
请注意,此更改仅影响新启动的控制台窗口 - 它不会为现有控制台窗口启用VT-100。
在this thread内,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);
我已经证明TYPE和ECHO都有效。我还验证了SET / P的工作原理(未显示)。因此我怀疑cmd.exe已被修改为支持新的Windows 10控制台功能。
我希望看到一些MS文档描述将转义序列发送到控制台所需的机制。