如何使 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."
我正在尝试调用 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."