通过 Windows 10 控制台 VT-100 转义序列获取光标位置
Get cursor position via Windows 10 console VT-100 escape sequence
我正在尝试 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
响应作为键盘输入传递出去,并出现在屏幕上,但我不知道如何以编程方式利用这些信息。理想情况下,我想将 <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!
--输出--
C:\test>ansi
Inquiry:
^[[3;9R
response=ESC[3;9R
C:\test>
一旦我在变量中有了响应,我就可以使用 FOR /F 轻松地解析出这些值。我遇到的问题是我必须在响应出现在屏幕上后手动按下 <Enter>
键以终止我的 SET /P 语句的输入。我对从这里去哪里感到难过...
编辑 - 最后一个要求:我不希望查询响应出现在屏幕上,因为这会扰乱屏幕并改变光标位置。我怀疑这可能是最难破解的坚果,也许纯批处理是不可能的。
我没有 Windows 10,所以我无法完成任何测试。但是,如果 Ansi ESC[6n
序列的响应是 用 ESC[<n>;<m>R
个字符填充键盘输入缓冲区 ,那么只需要添加一个 Enter 键即可输入以便通过 SET /P
命令读取它,这可以通过 SendKeys JScript 方法完成。
我还使用了一种更简单的方法来获取变量中的 ESC 字符。
编辑:我根据评论修改了代码...
@if (@CodeSegment == @Batch) @then
@echo off
title Ansi Test
setlocal EnableDelayedExpansion
for /F %%a in ('echo prompt $E ^| cmd') do set "esc=%%a"
set "csi=%esc%["
echo Inquiry:%csi%6n
cscript //nologo //E:JScript "%~F0"
set /p "pos=" > NUL
echo response=!pos:%esc%=ESC!
@end
var sh = WScript.CreateObject("WScript.Shell");
sh.AppActivate("Ansi Test");
sh.SendKeys("{ENTER}");
拜托,post 结果...
三年后的重大变化
它与使用 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
主要问题是,XCOPY
或 REPLACE
允许我从输入流中读取一个字符,但随后会清除剩余的缓冲区。
相反,PAUSE
读取一个字符,保留剩余的缓冲区,但不显示读取的字符。
为了解决这个问题,我多次发出查询,每次读取响应的不同字符。对于每次迭代,我使用 2 个或更多 PAUSE
语句的组合,后跟 REPLACE
来读取响应的特定字符。每次迭代比前一次迭代多使用 PAUSE
,直到我能够读取终止 R.
我开发了这项技术并最初将其发布在 DosTips - Query States using Console Virtual Terminal Sequences.
我正在尝试 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
响应作为键盘输入传递出去,并出现在屏幕上,但我不知道如何以编程方式利用这些信息。理想情况下,我想将 <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!
--输出--
C:\test>ansi
Inquiry:
^[[3;9R
response=ESC[3;9R
C:\test>
一旦我在变量中有了响应,我就可以使用 FOR /F 轻松地解析出这些值。我遇到的问题是我必须在响应出现在屏幕上后手动按下 <Enter>
键以终止我的 SET /P 语句的输入。我对从这里去哪里感到难过...
编辑 - 最后一个要求:我不希望查询响应出现在屏幕上,因为这会扰乱屏幕并改变光标位置。我怀疑这可能是最难破解的坚果,也许纯批处理是不可能的。
我没有 Windows 10,所以我无法完成任何测试。但是,如果 Ansi ESC[6n
序列的响应是 用 ESC[<n>;<m>R
个字符填充键盘输入缓冲区 ,那么只需要添加一个 Enter 键即可输入以便通过 SET /P
命令读取它,这可以通过 SendKeys JScript 方法完成。
我还使用了一种更简单的方法来获取变量中的 ESC 字符。
编辑:我根据评论修改了代码...
@if (@CodeSegment == @Batch) @then
@echo off
title Ansi Test
setlocal EnableDelayedExpansion
for /F %%a in ('echo prompt $E ^| cmd') do set "esc=%%a"
set "csi=%esc%["
echo Inquiry:%csi%6n
cscript //nologo //E:JScript "%~F0"
set /p "pos=" > NUL
echo response=!pos:%esc%=ESC!
@end
var sh = WScript.CreateObject("WScript.Shell");
sh.AppActivate("Ansi Test");
sh.SendKeys("{ENTER}");
拜托,post 结果...
三年后的重大变化
它与使用 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
主要问题是,XCOPY
或 REPLACE
允许我从输入流中读取一个字符,但随后会清除剩余的缓冲区。
相反,PAUSE
读取一个字符,保留剩余的缓冲区,但不显示读取的字符。
为了解决这个问题,我多次发出查询,每次读取响应的不同字符。对于每次迭代,我使用 2 个或更多 PAUSE
语句的组合,后跟 REPLACE
来读取响应的特定字符。每次迭代比前一次迭代多使用 PAUSE
,直到我能够读取终止 R.
我开发了这项技术并最初将其发布在 DosTips - Query States using Console Virtual Terminal Sequences.