Windows控制台:虚拟终端序列仅限于视口

nue99wik  于 2023-03-13  发布在  Windows
关注(0)|答案(1)|浏览(219)

我正在尝试实现一个clear_terminal()函数,它只清除给定数量的行,而不是整个屏幕。
在unix终端中,这可以通过以下ansi转义序列解决:

\033[{rows}A \033[0J

使用Windows API函数可以重现完全相同的结果:

hConsoleOutput = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
lpConsoleScreenBufferInfo = CONSOLE_SCREEN_BUFFER_INFO()

ctypes.windll.kernel32.GetConsoleScreenBufferInfo(
    hConsoleOutput,
    ctypes.byref(lpConsoleScreenBufferInfo)
)

lpConsoleScreenBufferInfo.dwCursorPosition.Y -= rows
ctypes.windll.kernel32.SetConsoleCursorPosition(
    hConsoleOutput,
    lpConsoleScreenBufferInfo.dwCursorPosition
)

ctypes.windll.kernel32.FillConsoleOutputCharacterA(
    hConsoleOutput,
    ctypes.c_char(b' '),
    lpConsoleScreenBufferInfo.dwSize.X * rows,
    lpConsoleScreenBufferInfo.dwCursorPosition,
    ctypes.byref(wintypes.DWORD(0))
)

ctypes.windll.kernel32.FillConsoleOutputAttribute(
    hConsoleOutput,
    lpConsoleScreenBufferInfo.wAttributes,
    lpConsoleScreenBufferInfo.dwSize.X * rows,
    lpConsoleScreenBufferInfo.dwCursorPosition,
    ctypes.byref(wintypes.DWORD(0))
)

但这正如微软所说的遗留问题。因为从Windows 10 TH2(v1511)开始,cmd.exe支持ANSI转义序列。它们必须使用SetConsoleMode ENABLE_VIRTUAL_TERMINAL_PROCESSING标志启用。
启用此选项会显示转义码无法正常工作:仅清除固定数量的行。文档中说明了此原因:
光标的移动将被当前 windows 限制在缓冲区内。滚动(如果可用)将不会发生。
所以使用虚拟序列时,不可能将光标位置设置得高于可视区域的上限。有没有解决办法来消除这种不必要的视口限制?
我使用了与上面相同的转义序列。Windows API解决方案总是清理正确的行数,并且不会遇到这些限制。

qco9c6ql

qco9c6ql1#

没有真实的的区别:您使用的转义序列仅限于可见屏幕。根据引用的文档,Windows控制台不实现擦除滚动区:
对于以下命令,参数有3个有效值:

  • 0擦除从当前光标位置(含)到行/显示的末尾
  • 1擦除从行/显示的开头到当前光标位置(包括当前光标位置)的内容
  • 2擦除整行/显示

与xterm相比:

CSI Ps J  Erase in Display (ED), VT100.
            Ps = 0  ⇒  Erase Below (default).
            Ps = 1  ⇒  Erase Above.
            Ps = 2  ⇒  Erase All.
            Ps = 3  ⇒  Erase Saved Lines, xterm.

(Windows终端不同,但完全没有文档记录)。

相关问题