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

Batch file 通过Windows 10控制台VT-100转义序列获取光标位置,batch-file,windows-console,ansi-escape,Batch File,Windows Console,Ansi Escape,我正在玩Windows10控制台中对VT-100转义序列的新(有限)支持。支持的序列记录在 我特别感兴趣的是以下报告当前光标位置的序列 ESC[6n - responds with ESC[<n>;<m>R, where <n> is the row number, and <m> the column number --输出-- 一旦在变量中得到响应,我就可以使用FOR/F轻松解析出值。我遇到的问题是,在屏幕上出现响应后,我

我正在玩Windows10控制台中对VT-100转义序列的新(有限)支持。支持的序列记录在

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

ESC[6n - responds with ESC[<n>;<m>R, 
         where <n> is the row number, and <m> the column number
--输出--

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


编辑-最后一个要求:我不希望查询响应出现在屏幕上,因为这会中断屏幕,并更改光标位置。我怀疑这可能是最难解决的问题,也许纯批处理是不可能的。

我没有Windows 10,所以我无法完成任何测试。但是,如果Ansi
ESC[6n
序列的响应是用
ESC[;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}");

请发布结果…

三年后的重大变化

它通过使用
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
@echo关闭
对于/F“delims=#”%%a in(“'prompt#$E#&对于%%a in(1)do rem””),请设置“ESC=%%a”
呼叫:获取光标位置
退出/b
:获取光标位置
设置“响应=”
设置位置=2
:_get_loop
REM***请求光标位置
努尔
对于/F“令牌=1跳过=1下线=“%%C in”(““替换/W?”
主要问题是,
XCOPY
REPLACE
允许我从输入流中读取一个字符,但随后清除剩余的缓冲区

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

为了解决这个问题,我多次发出查询,每次读取响应的不同字符。对于每次迭代,我使用两个或多个
PAUSE
语句的组合,后跟
REPLACE
来读取响应的特定字符。每次迭代都比上一次迭代多使用一个
PAUSE
,直到我能读懂这封信


我开发了这项技术,最初发布在

上。你测试了读取输出的
xcopy
方法吗?当
SET/p
工作时,我怀疑
xcopy
也应该工作,你可以停在他
R
上。这应该工作,但当另一个应用程序有焦点时,它会变得烦人。+1,工作得很好。我想到了这一点s在我上床睡觉后。但解决方案仍未完成。我忘了提及我不希望查询响应出现在屏幕上-我希望在不中断屏幕或更改光标位置的情况下获取信息。我已编辑了我的问题。@dbenham如果其他窗口具有焦点,它将从SendKeys接收ENTER命令窗口(刚刚测试)@jeb-Ooh,很有趣。我现在正在工作,没有W10,所以我无法测试。但我怀疑当另一个窗口有焦点时,查询响应将遭受同样的命运!@dbenham sendkey问题在每个Windows版本中都存在(我猜,但至少在Win7中)。查询本身应该是安全的,因为它是以这种方式设计的(至少在正常的linux世界中)耶!我已经放弃了获得纯批处理解决方案的希望。做得很好。@dbenham感谢您的编辑。现在连我自己的文本都能理解:-)
@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}");
@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