通过 Windows 10 控制台 VT-100 转义序列获取光标位置

dbe*_*ham 5 batch-file ansi-escape windows-console

我正在尝试 Windows 10 控制台中对 VT-100 转义序列的新(有限)支持。支持的序列记录在https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx

我特别感兴趣的是以下报告当前光标位置的序列。

ESC[6n - responds with ESC[<n>;<m>R, 
         where <n> is the row number, and <m> the column number
Run Code Online (Sandbox Code Playgroud)

响应作为键盘输入传递,并显示在屏幕上,但我不知道如何以编程方式利用这些信息。理想情况下,我想从批处理文件中将<n>和值放入环境变量中。<m>

但是,如果任何人都可以演示如何使用任何语言捕获变量,那么我也许可以利用这些知识来开发有效的批处理文件策略。

我可以使用以下名为 ANSI.BAT 的简单脚本来接近

@echo off
setlocal enableDelayedExpansion

for /f "delims=" %%C in (
  'forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x1B"'
) do set "esc=%%C"
set "csi=%esc%["

echo(Inquiry:%csi%6n
set /p "pos="
echo response=!pos:%esc%=ESC!
Run Code Online (Sandbox Code Playgroud)

- 输出 -

C:\test>ansi
Inquiry:
^[[3;9R
response=ESC[3;9R

C:\test>
Run Code Online (Sandbox Code Playgroud)

一旦我在变量中得到响应,我就可以使用 FOR /F 轻松解析出值。我遇到的问题是,<Enter>在屏幕上出现响应后,我必须手动按下该键才能终止 SET /P 语句的输入。我很困惑从这里该去哪里......

编辑- 最后一个要求:我不希望查询响应出现在屏幕上,因为这会破坏屏幕并更改光标位置。我怀疑这可能是最难破解的难题,也许对于纯批次来说是不可能的。

jeb*_*jeb 6

三年后的重大变化

XCOPY它可以通过使用或来读取响应REPLACE

replace在这里使用是为了避免语言相关的问题。

@echo off
for /F "delims=#" %%a in ('"prompt #$E# & for %%a in (1) do rem"') do set "ESC=%%a"

call :get_cursor_pos
exit /b

:get_cursor_pos
set "response="
set pos=2

:_get_loop
REM *** Request Cursor position
<nul set /p "=%ESC%[6n" 
FOR /L %%# in (1 1 %pos%) DO pause < CON > NUL

for /F "tokens=1 skip=1 eol=" %%C in ('"REPLACE /W ? . < con"') DO (
    set "char=%%C"
)
set "response=%response%%char%"
set /a pos+=1
if "%char%" NEQ "R" goto :_get_loop

set response
exit /b
Run Code Online (Sandbox Code Playgroud)

主要问题是,XCOPYREPLACE允许我从输入流中读取一个字符,但随后清除剩余的缓冲区。

相反,PAUSE读取一个字符,保留剩余的缓冲区,但不会显示读取的字符。

为了解决这个问题,我多次发出查询,每次读取响应的不同字符。对于每次迭代,我使用 2 个或更多语句的组合PAUSE,然后REPLACE读取响应的特定字符。每次迭代都比前一次迭代多使用一个PAUSE,直到我能够读取终止 R。

我开发了这项技术,并最初将其发布在DosTips - 使用控制台虚拟终端序列的查询状态。