Eryk Sun added the comment:
cmd.exe enables virtual terminal mode, but only for itself. It disables VT mode
before starting other programs, and also at shutdown. It appears you've found a
bug in the case of "cmd.exe /c ...". You can get the same result via
os.system(''). It's failing to disable VT mode after it exits.
Enabling VT mode by default is potentially a problem because a console
buffer's mode is shared, inherited state. Adding a set_console_mode method on
console files would be a useful convenience to manage this state. There could
also be a couple IntFlag enums for the available input and output mode values.
Here's some code to enable VT mode in Windows 10 -- assuming you're not using
the legacy console. If you're using an older version of Windows, or the legacy
console in Windows 10, then enabling VT mode will fail as an invalid parameter.
This is handled by raising NotImplementedError. On success, it returns the
previous console mode, which can be restored by calling set_conout_mode(mode).
Depending on your needs, that could done in an atexit function.
import os
import msvcrt
import ctypes
from ctypes import wintypes
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
ERROR_INVALID_PARAMETER = 0x0057
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
def _check_bool(result, func, args):
if not result:
raise ctypes.WinError(ctypes.get_last_error())
return args
LPDWORD = ctypes.POINTER(wintypes.DWORD)
kernel32.GetConsoleMode.errcheck = _check_bool
kernel32.GetConsoleMode.argtypes = (wintypes.HANDLE, LPDWORD)
kernel32.SetConsoleMode.errcheck = _check_bool
kernel32.SetConsoleMode.argtypes = (wintypes.HANDLE, wintypes.DWORD)
def set_conout_mode(new_mode, mask=0xffffffff):
# don't assume StandardOutput is a console.
# open CONOUT$ instead
fdout = os.open('CONOUT$', os.O_RDWR)
try:
hout = msvcrt.get_osfhandle(fdout)
old_mode = wintypes.DWORD()
kernel32.GetConsoleMode(hout, ctypes.byref(old_mode))
mode = (new_mode & mask) | (old_mode.value & ~mask)
kernel32.SetConsoleMode(hout, mode)
return old_mode.value
finally:
os.close(fdout)
def enable_vt_mode():
mode = mask = ENABLE_VIRTUAL_TERMINAL_PROCESSING
try:
return set_conout_mode(mode, mask)
except WindowsError as e:
if e.winerror == ERROR_INVALID_PARAMETER:
raise NotImplementedError
raise
Please don't use the code in issue 29059. It's simpler, but there are several
problems with it. (1) There's no error handling. (2) It passes handles
incorrectly as 32-bit int values, for which ctypes in 64-bit Python 2 may
corrupt the high DWORD (if it works, it's only by accident; ctypes doesn't zero
the stack in ffi_prep_args). (3) It assumes the StandardOutput handle is a
console output buffer, but maybe it's a pipe or file, and the program has
manually opened CONOUT$ to write debug text in color. (4) It uses windll, which
causes problems when multiple libraries contend for the same functions (e.g.
some library may have set incompatible argtypes, restype, or errcheck values on
windll.kernel32.GetConsoleMode).
----------
nosy: +eryksun
_______________________________________
Python tracker <[email protected]>
<http://bugs.python.org/issue30075>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com