【问题标题】:How to use the new support for ANSI escape sequences in the Windows 10 console?如何在 Windows 10 控制台中使用对 ANSI 转义序列的新支持?
【发布时间】:2016-08-14 02:17:36
【问题描述】:

最新的 Windows 10 更新包括 conhost.exe 中的support for ANSI escape sequences

我已经能够确认转义序列在 cmd.exe 中被正确提取,所以我有必要的更新。特别是,我尝试输入prompt $e[?25l,隐藏光标,然后输入prompt $e[?25h,再次显示光标。

但是,如果我启动一个 Python 解释器,然后执行以下操作:

>>> import sys
>>> sys.stdout.write("\033[?25l")

嗯,光标没有隐藏。如何以正确的方式进行设置,以便控制台能够从 Python 获取转义序列?

【问题讨论】:

    标签: python cmd windows-10 windows-console


    【解决方案1】:

    问题在于 Python 解释器无法处理 ANSI 转义序列。 ANSI 序列在 Windows 命令提示符下工作,因为cmd 确实启用了它们。如果您从命令提示符启动 Python,您会发现 ANSI 序列确实有效,包括用于启用和禁用光标的序列。那是因为cmd 已经为该控制台窗口启用了它们。

    如果您想要一些东西,您可以单击以启动启用了 ANSI 转义的 Python 解释器,您可以创建一个快捷方式来运行类似 cmd /c C:\PythonXY\python 的命令。

    另一个更难的解决方案是使用 ctypes 来启用控制台窗口的 ANSI 转义序列处理,方法是调用带有 ENABLE_VIRTUAL_TERMINAL_PROCESSING 标志集的 SetConsoleMode Windows API。例如:

    import ctypes
    
    kernel32 = ctypes.windll.kernel32
    kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
    

    【讨论】:

    • 嗨罗斯——感谢这个非常好的答案:) 看来你做了很多与控制台相关的事情,我想知道——你是否也知道如何在Windows 控制台,类似于在 Linux 中的操作,通过使用 O_NONBLOCK 标志? Python Prompt Toolkit 通过使用 Windows API 公开的特殊读取函数实现非阻塞输入:github.com/jonathanslenders/python-prompt-toolkit/blob/master/…——似乎没有我可以设置的标志,然后允许sys.stdin.read() 不阻塞?
    • @user89 不,不幸的是,没有等效于 O_NONBLOCK 标志。 Windows 使用不同的模型,涉及等待句柄和重叠 I/O 上的事件(控制台句柄不支持后者)。您要么需要通过 ctypes 深入研究 Windows API,要么让诸如 curses 之类的东西为您处理它。用于 Windows 的 Python 不附带诅咒支持,但您可以单独下载端口,请参阅:docs.python.org/3.3/howto/curses.html
    • 有道理——我想我会等着看 Windows 控制台如何改进(尤其是随着即将在 Windows 上发布的 bash),现在坚持在 Linux 上使用 VM,以便运行+开发控制台应用程序。
    • @user89 Bash for Windows 是他们用于 Windows 的新 Linux 子系统的一部分。不幸的是,它的集成度比在 Linux 上使用 VM 好一点,文件系统是共享的,仅此而已。您可能会改用 Cygwin,它除了让您从 bash 运行 Windows 程序和从 Windows 命令行运行“Linux”程序外,它还可以在当前版本的 Windows 10 以及旧版本的 Windows 上运行。
    • @HenriqueDias 相当于ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_VIRTUAL_TERMINAL_PROCESSING 相当于0x0001|0x0002|0x0004 等于7。Python不能包含定义这些标志的C头文件,所以我只是替换了他们最终评估为第 7 位。前两个标志默认打开并启用您所期望的正常控制台输出处理,第三个是启用处理 ANSI 转义序列的标志,默认情况下未启用。
    【解决方案2】:

    我提出的一些代码的改编 here 应该可以帮助您入门。在 Windows 10 上启用 ANSI VT 模式(虚拟终端处理)。为 stdout2 stderr 传入参数值 1

    def _windows_enable_ANSI(std_id):
        """Enable Windows 10 cmd.exe ANSI VT Virtual Terminal Processing."""
        from ctypes import byref, POINTER, windll, WINFUNCTYPE
        from ctypes.wintypes import BOOL, DWORD, HANDLE
    
        GetStdHandle = WINFUNCTYPE(
            HANDLE,
            DWORD)(('GetStdHandle', windll.kernel32))
    
        GetFileType = WINFUNCTYPE(
            DWORD,
            HANDLE)(('GetFileType', windll.kernel32))
    
        GetConsoleMode = WINFUNCTYPE(
            BOOL,
            HANDLE,
            POINTER(DWORD))(('GetConsoleMode', windll.kernel32))
    
        SetConsoleMode = WINFUNCTYPE(
            BOOL,
            HANDLE,
            DWORD)(('SetConsoleMode', windll.kernel32))
    
        if std_id == 1:       # stdout
            h = GetStdHandle(-11)
        elif std_id == 2:     # stderr
            h = GetStdHandle(-12)
        else:
            return False
    
        if h is None or h == HANDLE(-1):
            return False
    
        FILE_TYPE_CHAR = 0x0002
        if (GetFileType(h) & 3) != FILE_TYPE_CHAR:
            return False
    
        mode = DWORD()
        if not GetConsoleMode(h, byref(mode)):
            return False
    
        ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
        if (mode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0:
            SetConsoleMode(h, mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
        return True
    

    【讨论】:

    • 它不起作用,给出“NameError: name 'compat_ctypes_WINFUNCTYPE' is not defined”
    • 正如作者所说,这段代码来自关于 youtube-dl 的 GitHub 问题评论。缺少的功能在 youtube-dl 中定义(您可以使用 GitHub 搜索功能在那里找到它)。如果你没有使用 PyPy,那么 compat_ctypes_WINFUNCTYPE = WINFUNCTYPE 这样你就可以相应地替换这些调用。
    【解决方案3】:

    colorama 包在 Windows 中启用 ANSI 代码。

    用法:

    from colorama import init
    init()
    

    在那之后 ANSI 代码应该可以工作了。

    【讨论】:

    • 很好的答案!我用过 colorama,但不知道 init() 会在 Windows 上启用支持。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-11
    • 2011-11-18
    • 1970-01-01
    • 1970-01-01
    • 2015-10-08
    • 2021-01-15
    相关资源
    最近更新 更多