【问题标题】:Get cursor position via Windows 10 console VT-100 escape sequence通过 Windows 10 控制台 VT-100 转义序列获取光标位置
【发布时间】:2016-11-09 06:57:38
【问题描述】:

我正在尝试 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

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

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

我可以使用以下名为 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 轻松解析出这些值。我遇到的问题是我必须在屏幕上出现响应后手动按下&lt;Enter&gt; 键才能终止我的 SET /P 语句的输入。我很困惑从这里去哪里......

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

【问题讨论】:

  • 您是否测试了xcopy 方法来读取输出?当SET/p 工作时,我怀疑xcopy 也应该工作,你可以停在他R

标签: batch-file windows-console ansi-escape


【解决方案1】:

三年后的重大变化

它适用于使用XCOPYREPLACE 读取响应。

我在这里使用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

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

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

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

我开发了这项技术,最初发布在DosTips - Query States using Console Virtual Terminal Sequences.

【讨论】:

  • 耶!我已经放弃了获得纯批处理解决方案的希望。做得很好。
  • @dbenham 感谢您的编辑。现在,即使我能够理解我自己的文字 :-)
【解决方案2】:

我没有 Windows 10,所以我无法完成任何测试。但是,如果 Ansi ESC[6n 序列的响应是ESC[&lt;n&gt;;&lt;m&gt;R 字符填充键盘输入缓冲区,那么只需向此类输入添加一个 Enter 键,以便通过以下方式读取它SET /P 命令,这可以通过 SendKeys JScript 方法完成。

我还使用了一种更简单的方法来获取变量中的 ESC 字符。

编辑:我根据cmets修改了代码...

@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}");

请发布结果...

【讨论】:

  • 这应该可以,但是当另一个应用程序获得焦点时会很烦人。
  • +1,效果很好。我睡觉后想到了这个。但解决方案仍然不完整。我忘了提到我不希望查询响应出现在屏幕上 - 我想在不破坏屏幕或更改光标位置的情况下获取信息。我已经编辑了我的问题。
  • @dbenham 如果另一个窗口有焦点,它将从 SendKeys 接收 ENTER 而不是命令窗口(刚刚测试)
  • @jeb - 哦,有趣。我现在在工作,没有W10,所以我无法测试。但是我怀疑当另一个窗口有焦点时,查询响应会遭受同样的命运!
  • @dbenham 每个 Windows 版本都存在 sendkey 问题(我猜,但至少在 Win7 中)。查询本身应该是安全的,因为它是这样设计的(至少在 普通 linux 世界中)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-02
  • 2023-02-12
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 2013-07-02
相关资源
最近更新 更多