gpt4 book ai didi

python - 如何获取 ANSI 终端中光标的位置?

转载 作者:行者123 更新时间:2023-11-30 22:59:56 25 4
gpt4 key购买 nike

我想获取终端窗口中光标的位置。我知道我可以echo -e "\033[6n"读取输出-s,如 this answer 所示,但是我怎样才能在Python中做到这一点呢?

我已经尝试过this contextmanager像这样:

with Capturing() as output:
sys.stdout.write("\e[6n")
print(output)

但它只捕获我编写的 \e[6n ('\x1b[6n') 转义序列,而不是 ^[[x;yR1 我需要的序列。

我还尝试生成一个子进程并获取其输出,但同样,只捕获我编写的转义序列:

output = subprocess.check_output(["echo", "\033[6n"], shell=False)
print(output)

shell=True 使输出成为空字符串列表。

避免 curses (因为这应该是一个简单,穷人的光标 pos getter),我如何获得通过打印 \返回的转义序列e[6n?

最佳答案

虽然 Stack Overflow 上的问题很老了,但它肯定没有过时,因此我写了一个完整的示例来说明如何做到这一点。

基本方法是:

  1. stdout 上启用 ANSI 转义序列处理。
  2. stdin 上禁用 ECHO 和线路模式。
  3. 发送 ANSI 序列以查询 stdout 上的光标位置。
  4. 阅读 stdin 上的回复。
  5. 恢复stdinstdout的设置。

对于第 1 步,在 Linux 下,默认情况下应启用 stdout 上的 ANSI 转义序列处理,但在 Windows 下,至少目前并未启用,这就是下面的示例使用的原因SetConsoleMode 来启用这些。对于 kernel32.GetStdHandle() 调用,stdin 的 Windows 标准句柄为 -10,stdout 的 Windows 标准句柄为 -11,并且我们只是获取这些文件的文件描述符。这些是仅限 Windows 的功能。

对于Linux,我们可以使用termios来禁用/启用ECHO和线路模式。值得注意的是 termios 在 Windows 下不可用。

对于第 2 步,stdin 上的任何输入都会被缓冲,并且仅逐行向前发送,但我们希望尽快读取 stdin 上的所有输入。我们还想禁用 ECHO,这样第 3 步的回复就不会打印到控制台。

为了更好地衡量,如果出现问题,下面的示例将给出 (-1, -1) 的结果,因此您的代码可以例如再试一次。

import sys, re
if(sys.platform == "win32"):
import ctypes
from ctypes import wintypes
else:
import termios

def cursorPos():
if(sys.platform == "win32"):
OldStdinMode = ctypes.wintypes.DWORD()
OldStdoutMode = ctypes.wintypes.DWORD()
kernel32 = ctypes.windll.kernel32
kernel32.GetConsoleMode(kernel32.GetStdHandle(-10), ctypes.byref(OldStdinMode))
kernel32.SetConsoleMode(kernel32.GetStdHandle(-10), 0)
kernel32.GetConsoleMode(kernel32.GetStdHandle(-11), ctypes.byref(OldStdoutMode))
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
else:
OldStdinMode = termios.tcgetattr(sys.stdin)
_ = termios.tcgetattr(sys.stdin)
_[3] = _[3] & ~(termios.ECHO | termios.ICANON)
termios.tcsetattr(sys.stdin, termios.TCSAFLUSH, _)
try:
_ = ""
sys.stdout.write("\x1b[6n")
sys.stdout.flush()
while not (_ := _ + sys.stdin.read(1)).endswith('R'):
True
res = re.match(r".*\[(?P<y>\d*);(?P<x>\d*)R", _)
finally:
if(sys.platform == "win32"):
kernel32.SetConsoleMode(kernel32.GetStdHandle(-10), OldStdinMode)
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), OldStdoutMode)
else:
termios.tcsetattr(sys.stdin, termios.TCSAFLUSH, OldStdinMode)
if(res):
return (res.group("x"), res.group("y"))
return (-1, -1)

x, y = cursorPos()
print(f"Cursor x: {x}, y: {y}")

结果输出应该类似于:

Cursor x: 1, y: 30

如果有人希望深入研究所有这些内容,例如,可能有用的其他链接在此扩展功能:Man-page for Linux's termios , Windows SetConsoleMode , Windows GetConsoleMode , Wikipedia-entry for ANSI escape sequences

关于python - 如何获取 ANSI 终端中光标的位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35526014/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com