2016-04-21 26 views
7

Gli ultimi aggiornamenti di Windows 10 includono support for ANSI escape sequences in conhost.exe.Come utilizzare il nuovo supporto per le sequenze di escape ANSI nella console di Windows 10?

enter image description here

sono stato in grado di confermare che le sequenze di escape vengono raccolti correttamente in cmd.exe, quindi non ho gli aggiornamenti necessari. In particolare, ho provato a digitare prompt $e[?25l, che nasconde il cursore, e quindi prompt $e[?25h, che mostra nuovamente il cursore.

Tuttavia, se mi metto un interprete Python, e quindi effettuare le seguenti operazioni:

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

Ebbene, il cursore non è nascosto. Come posso impostare le cose nel modo giusto in modo che la console sia in grado di ottenere sequenze di escape da Python?

risposta

12

Il problema è che l'interprete Python non abilita l'elaborazione delle sequenze di escape ANSI. Le sequenze ANSI funzionano dal prompt dei comandi di Windows perché cmd le abilita. Se avvii Python dal prompt dei comandi troverai che le sequenze ANSI funzionano, comprese quelle per abilitare e disabilitare il cursore. Questo perché cmd li ha già abilitati per quella finestra della console.

Se si desidera avere qualcosa su cui è possibile fare clic per avviare l'interprete Python con gli escape ANSI abilitati, è possibile creare un collegamento che esegua un comando come cmd /c C:\PythonXY\python.

Un altro, più duro, la soluzione sarebbe quella di utilizzare ctypes per consentire l'elaborazione ANSI sequenza di escape per la finestra della console chiamando l'API di Windows SetConsoleMode con il set ENABLE_VIRTUAL_TERMINAL_PROCESSING bandiera. Per esempio:

import ctypes 

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

Hi Ross - grazie per questo davvero bella risposta :) Sembra si fa un sacco di cose relative console, e mi chiedo - si fa a sapere anche come raggiungere ingresso non-blocking in una console di Windows , simile a come si potrebbe fare in Linux, usando il flag O_NONBLOCK? Python Prompt Toolkit ottiene input non bloccanti utilizzando una funzione di lettura speciale esposta dall'API di Windows: https://github.com/jonathanslenders/python-prompt-toolkit/blob/master/prompt_toolkit/terminal/win32_input.py#L99 - - Non sembra che ci sia una bandiera che posso impostare, il che consentirebbe a 'sys.stdin.read()' di non bloccare? – user89

+0

@ user89 No, sfortunatamente non c'è alcun equivalente al flag O_NONBLOCK. Windows utilizza un modello diverso che prevede l'attesa di eventi su handle e I/O sovrapposti (il successivo non è supportato per gli handle della console). Dovrai o approfondire l'API di Windows tramite i ctype o lasciare che qualcosa come i curses gestisca per te. Il supporto delle maledizioni non è fornito con Python per Windows, ma puoi scaricare una porta separatamente, vedi: https://docs.python.org/3.3/howto/curses.html –

+0

Ha senso - Immagino che aspetterò per vedere come migliora la console di Windows (in particolare con l'imminente rilascio di bash su Windows), e per ora limitarsi a utilizzare le macchine virtuali con Linux per eseguire + sviluppare app per console. – user89

0

Questo adattamento di un codice ho proposto here dovrebbe aiutarti ad iniziare. Abilita la modalità ANSI VT (elaborazione terminale virtuale) su Windows 10. Passa in argomento valore 1 per stdout o 2stderr.

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 = compat_ctypes_WINFUNCTYPE(
     HANDLE, 
     DWORD)(('GetStdHandle', windll.kernel32)) 

    GetFileType = compat_ctypes_WINFUNCTYPE(
     DWORD, 
     HANDLE)(('GetFileType', windll.kernel32)) 

    GetConsoleMode = compat_ctypes_WINFUNCTYPE(
     BOOL, 
     HANDLE, 
     POINTER(DWORD))(('GetConsoleMode', windll.kernel32)) 

    SetConsoleMode = compat_ctypes_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 
Problemi correlati