2016-04-21 10 views
7

Najnowsze aktualizacje systemu Windows 10 obejmują support for ANSI escape sequences w pliku conhost.exe.Jak korzystać z nowej obsługi sekwencji kontrolnych ANSI w konsoli systemu Windows 10?

enter image description here

byłem w stanie potwierdzić, że sekwencje są poprawnie odebrać w cmd.exe, więc mam niezbędnych aktualizacji. W szczególności próbowałem pisać w prompt $e[?25l, który ukrywa kursor, a następnie prompt $e[?25h, który ponownie pokazuje kursor.

Jeśli jednak zacznę interpreter Pythona, a następnie wykonaj następujące czynności:

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

dobrze, kursor nie jest ukryte. Jak mogę ustawić wszystko we właściwy sposób, aby konsola mogła uzyskać sekwencje specjalne z Pythona?

Odpowiedz

12

Problem polega na tym, że interpreter języka Python nie umożliwia przetwarzania sekwencji escape ANSI. Sekwencje ANSI działają z wiersza polecenia systemu Windows, ponieważ umożliwia je cmd. Jeśli uruchomisz Python z wiersza poleceń, zobaczysz, że działają sekwencje ANSI, w tym te, które włączają i wyłączają kursor. To dlatego, że cmd już je włączył dla tego okna konsoli.

Jeśli chcesz mieć coś, co możesz kliknąć, aby uruchomić interpreter języka Python z włączonymi wersjami ANSI, możesz utworzyć skrót uruchamiający komendę podobną do cmd /c C:\PythonXY\python.

Innym, trudniejszym rozwiązaniem byłoby użycie ctypów do włączenia przetwarzania sekwencji kodu ANSI w oknie konsoli przez wywołanie interfejsu API Windows SetConsoleMode z zestawem flag ENABLE_VIRTUAL_TERMINAL_PROCESSING. Na przykład:

import ctypes 

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

Cześć Ross - dzięki za to naprawdę miły odpowiedź :) Wydaje się wiele rzeczy związanych z konsoli zrobić, i zastanawiam się - czy też, jak osiągnąć wejściowych bez blokowania w konsoli systemu Windows , podobnie jak można to zrobić w Linuksie, używając flagi O_NONBLOCK? Python Prompt Toolkit uzyskuje dane bez blokowania za pomocą specjalnej funkcji odczytu ujawnionej przez interfejs API systemu Windows: https://github.com/jonathanslenders/python-prompt-toolkit/blob/master/prompt_toolkit/terminal/win32_input.py#L99 - - nie wydaje mi się, że flaga może ustawić, co pozwoliłoby, aby 'sys.stdin.read()' nie blokowało? – user89

+0

@ user89 Nie, niestety nie ma odpowiednika flagi O_NONBLOCK. System Windows używa innego modelu, w tym oczekiwania na zdarzenia na uchwytach i nakładających się operacjach wejścia/wyjścia (ta ostatnia nie jest obsługiwana w przypadku uchwytów konsoli). Musisz albo zagłębić się w Windows API poprzez cpy, albo pozwolić, żeby coś takiego jak curses sobie z tym poradziło. Wsparcie dla Curses nie jest dostarczane z Pythonem dla Windows, ale możesz pobrać port osobno, zobacz: https://docs.python.org/3.3/howto/curses.html –

+0

To ma sens - myślę, że poczekam aby zobaczyć, jak poprawia się konsola Windows (szczególnie w nadchodzącym wydaniu bash w systemie Windows), i na razie trzymaj się maszyn wirtualnych z Linuksem, aby uruchamiać + tworzyć aplikacje konsolowe. – user89

0

Ta adaptacja kodu zaproponowanego przeze mnie here powinna pomóc Ci zacząć. Włącza tryb ANSI VT (wirtualne przetwarzanie terminali) na Windows 10. Przekaż wartość argumentu 1 dla stdout lub 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 
Powiązane problemy