如何使 msvcrt.getch() 在 mintty 中的行为方式与在 cmd 中的行为方式相同?

How can I make msvcrt.getch() behave the same way in mintty as in cmd?

我正在尝试调用 python 中的按键功能。当脚本在 Windows 命令行 (cmd.exe) 中为 运行 时,一切都按预期工作。但通常当我在 Windows 上时,我使用 mintty。

在 mintty 中,应用程序的行为有所不同。 getch() 阻止应用程序(永远)。

import msvcrt

print("press a key")
char = msvcrt.getch()
print(f"you pressed: {char}")

在Windows命令行中:

press a key

(I press the a key)

you pressed: b'a'

(application closed as it should)

在薄荷糖中:

press a key

(i press a multiple times)

aaaaaaaaaaaaaa

(nothing happens)

简短的回答是“确保 windows python 可执行调用包含在 winpty 调用中”。

我有一个类似的挑战,我希望支持一个完全交互式的控制台应用程序,它在 unixey 环境中使用 termios,在 Windows 中使用 msvcrt

  • 适用于 linux & mac,
  • 它在 windows cmd 控制台中工作,
  • 它可以在时髦的 windows bash 终端中运行,例如 VS Code,
  • 它在“纯”msys2 中工作(其中 python 通过 pacman 安装,在 mintty 中编译为 运行,因此支持 termios),但是
  • 在“Git for Windows”的 mintty bash window 中失败,除非调用者添加“ winpty" 在命令之前......当它失败时,它失败了! (无法轻易退出损坏的控制台应用程序,因为读取键不起作用)

我在这里看到的最大剩余挑战是检测失败。

到目前为止,我有以下条件:

  • 如果 msvcrt 已加载(我们 运行 在 windows python 中)
  • os.environ.get('TERM_PROGRAM') == "mintty"(mintty 是控制台)
  • os.environ.get('TERM') == "xterm"(winpty没有改变mintty的xterm默认的终端类型)
  • 然后引发异常要求用户使用 winpty
  • 调用

这依赖于我系统上一系列奇怪的巧合:

  • mintty 的默认“TERM”设置是“xterm”(但可配置!)
  • 与最近的 git 捆绑在一起的 winpty 将其重置为 None(在 python 术语中)
  • 与 msys2 捆绑在一起的 winpty 将其重置为“xterm-256color”

不幸的是,我认为这个逻辑不是很可靠 - 其他版本的 winpty 和 mintty 可能表现不同,并且用户可能将 mintty 中的终端类型设置更改为“xterm”以外的其他设置,在这种情况下我的脚本会错误地假设一切正常。

我非常希望有一种更可靠的方法来检测我的脚本何时处于“python for windows 运行ning in mintty without winpty”。

更新:使用 Bash 可以工作!

对于它的价值,if 你可以依靠路径中的 bash 可用(如果你试图从 python,我猜实际上很有可能吧?),那么你可以:

  • 调用 bash 脚本(不通过管道传输 stdin 和 stdout,并传递参数 -i,因此它连接到终端,并与)
  • 依靠 mintty 的辅助设备属性支持
  • 使用echo -n -e打印转义序列
  • 使用带有超时的 read 来捕获 tty 响应
  • 使用 stderr 或退出代码将结果输出到 python

示例 bash 脚本:

echo -n -e '\e[>c';
read -rs -t 0.2 -d "" <$(tty)
echo "Look ma! Secondary device attributes are ${REPLY#?} - now if they start with [>77; then I know I'm in mintty."