2023-03-18 12:55:22 +01:00
|
|
|
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
|
|
|
|
|
|
|
|
# from winbase.h
|
|
|
|
STDOUT = -11
|
|
|
|
STDERR = -12
|
|
|
|
|
2023-06-15 20:22:20 +02:00
|
|
|
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
|
|
|
|
|
2023-03-18 12:55:22 +01:00
|
|
|
try:
|
|
|
|
import ctypes
|
|
|
|
from ctypes import LibraryLoader
|
|
|
|
windll = LibraryLoader(ctypes.WinDLL)
|
|
|
|
from ctypes import wintypes
|
|
|
|
except (AttributeError, ImportError):
|
|
|
|
windll = None
|
|
|
|
SetConsoleTextAttribute = lambda *_: None
|
|
|
|
winapi_test = lambda *_: None
|
|
|
|
else:
|
|
|
|
from ctypes import byref, Structure, c_char, POINTER
|
|
|
|
|
|
|
|
COORD = wintypes._COORD
|
|
|
|
|
|
|
|
class CONSOLE_SCREEN_BUFFER_INFO(Structure):
|
|
|
|
"""struct in wincon.h."""
|
|
|
|
_fields_ = [
|
|
|
|
("dwSize", COORD),
|
|
|
|
("dwCursorPosition", COORD),
|
|
|
|
("wAttributes", wintypes.WORD),
|
|
|
|
("srWindow", wintypes.SMALL_RECT),
|
|
|
|
("dwMaximumWindowSize", COORD),
|
|
|
|
]
|
|
|
|
def __str__(self):
|
|
|
|
return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % (
|
|
|
|
self.dwSize.Y, self.dwSize.X
|
|
|
|
, self.dwCursorPosition.Y, self.dwCursorPosition.X
|
|
|
|
, self.wAttributes
|
|
|
|
, self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right
|
|
|
|
, self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X
|
|
|
|
)
|
|
|
|
|
|
|
|
_GetStdHandle = windll.kernel32.GetStdHandle
|
|
|
|
_GetStdHandle.argtypes = [
|
|
|
|
wintypes.DWORD,
|
|
|
|
]
|
|
|
|
_GetStdHandle.restype = wintypes.HANDLE
|
|
|
|
|
|
|
|
_GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo
|
|
|
|
_GetConsoleScreenBufferInfo.argtypes = [
|
|
|
|
wintypes.HANDLE,
|
|
|
|
POINTER(CONSOLE_SCREEN_BUFFER_INFO),
|
|
|
|
]
|
|
|
|
_GetConsoleScreenBufferInfo.restype = wintypes.BOOL
|
|
|
|
|
|
|
|
_SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute
|
|
|
|
_SetConsoleTextAttribute.argtypes = [
|
|
|
|
wintypes.HANDLE,
|
|
|
|
wintypes.WORD,
|
|
|
|
]
|
|
|
|
_SetConsoleTextAttribute.restype = wintypes.BOOL
|
|
|
|
|
|
|
|
_SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition
|
|
|
|
_SetConsoleCursorPosition.argtypes = [
|
|
|
|
wintypes.HANDLE,
|
|
|
|
COORD,
|
|
|
|
]
|
|
|
|
_SetConsoleCursorPosition.restype = wintypes.BOOL
|
|
|
|
|
|
|
|
_FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA
|
|
|
|
_FillConsoleOutputCharacterA.argtypes = [
|
|
|
|
wintypes.HANDLE,
|
|
|
|
c_char,
|
|
|
|
wintypes.DWORD,
|
|
|
|
COORD,
|
|
|
|
POINTER(wintypes.DWORD),
|
|
|
|
]
|
|
|
|
_FillConsoleOutputCharacterA.restype = wintypes.BOOL
|
|
|
|
|
|
|
|
_FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute
|
|
|
|
_FillConsoleOutputAttribute.argtypes = [
|
|
|
|
wintypes.HANDLE,
|
|
|
|
wintypes.WORD,
|
|
|
|
wintypes.DWORD,
|
|
|
|
COORD,
|
|
|
|
POINTER(wintypes.DWORD),
|
|
|
|
]
|
|
|
|
_FillConsoleOutputAttribute.restype = wintypes.BOOL
|
|
|
|
|
|
|
|
_SetConsoleTitleW = windll.kernel32.SetConsoleTitleW
|
|
|
|
_SetConsoleTitleW.argtypes = [
|
|
|
|
wintypes.LPCWSTR
|
|
|
|
]
|
|
|
|
_SetConsoleTitleW.restype = wintypes.BOOL
|
|
|
|
|
2023-06-15 20:22:20 +02:00
|
|
|
_GetConsoleMode = windll.kernel32.GetConsoleMode
|
|
|
|
_GetConsoleMode.argtypes = [
|
|
|
|
wintypes.HANDLE,
|
|
|
|
POINTER(wintypes.DWORD)
|
|
|
|
]
|
|
|
|
_GetConsoleMode.restype = wintypes.BOOL
|
|
|
|
|
|
|
|
_SetConsoleMode = windll.kernel32.SetConsoleMode
|
|
|
|
_SetConsoleMode.argtypes = [
|
|
|
|
wintypes.HANDLE,
|
|
|
|
wintypes.DWORD
|
|
|
|
]
|
|
|
|
_SetConsoleMode.restype = wintypes.BOOL
|
|
|
|
|
2023-03-18 12:55:22 +01:00
|
|
|
def _winapi_test(handle):
|
|
|
|
csbi = CONSOLE_SCREEN_BUFFER_INFO()
|
|
|
|
success = _GetConsoleScreenBufferInfo(
|
|
|
|
handle, byref(csbi))
|
|
|
|
return bool(success)
|
|
|
|
|
|
|
|
def winapi_test():
|
|
|
|
return any(_winapi_test(h) for h in
|
|
|
|
(_GetStdHandle(STDOUT), _GetStdHandle(STDERR)))
|
|
|
|
|
|
|
|
def GetConsoleScreenBufferInfo(stream_id=STDOUT):
|
|
|
|
handle = _GetStdHandle(stream_id)
|
|
|
|
csbi = CONSOLE_SCREEN_BUFFER_INFO()
|
|
|
|
success = _GetConsoleScreenBufferInfo(
|
|
|
|
handle, byref(csbi))
|
|
|
|
return csbi
|
|
|
|
|
|
|
|
def SetConsoleTextAttribute(stream_id, attrs):
|
|
|
|
handle = _GetStdHandle(stream_id)
|
|
|
|
return _SetConsoleTextAttribute(handle, attrs)
|
|
|
|
|
|
|
|
def SetConsoleCursorPosition(stream_id, position, adjust=True):
|
|
|
|
position = COORD(*position)
|
|
|
|
# If the position is out of range, do nothing.
|
|
|
|
if position.Y <= 0 or position.X <= 0:
|
|
|
|
return
|
|
|
|
# Adjust for Windows' SetConsoleCursorPosition:
|
|
|
|
# 1. being 0-based, while ANSI is 1-based.
|
|
|
|
# 2. expecting (x,y), while ANSI uses (y,x).
|
|
|
|
adjusted_position = COORD(position.Y - 1, position.X - 1)
|
|
|
|
if adjust:
|
|
|
|
# Adjust for viewport's scroll position
|
|
|
|
sr = GetConsoleScreenBufferInfo(STDOUT).srWindow
|
|
|
|
adjusted_position.Y += sr.Top
|
|
|
|
adjusted_position.X += sr.Left
|
|
|
|
# Resume normal processing
|
|
|
|
handle = _GetStdHandle(stream_id)
|
|
|
|
return _SetConsoleCursorPosition(handle, adjusted_position)
|
|
|
|
|
|
|
|
def FillConsoleOutputCharacter(stream_id, char, length, start):
|
|
|
|
handle = _GetStdHandle(stream_id)
|
|
|
|
char = c_char(char.encode())
|
|
|
|
length = wintypes.DWORD(length)
|
|
|
|
num_written = wintypes.DWORD(0)
|
|
|
|
# Note that this is hard-coded for ANSI (vs wide) bytes.
|
|
|
|
success = _FillConsoleOutputCharacterA(
|
|
|
|
handle, char, length, start, byref(num_written))
|
|
|
|
return num_written.value
|
|
|
|
|
|
|
|
def FillConsoleOutputAttribute(stream_id, attr, length, start):
|
|
|
|
''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )'''
|
|
|
|
handle = _GetStdHandle(stream_id)
|
|
|
|
attribute = wintypes.WORD(attr)
|
|
|
|
length = wintypes.DWORD(length)
|
|
|
|
num_written = wintypes.DWORD(0)
|
|
|
|
# Note that this is hard-coded for ANSI (vs wide) bytes.
|
|
|
|
return _FillConsoleOutputAttribute(
|
|
|
|
handle, attribute, length, start, byref(num_written))
|
|
|
|
|
|
|
|
def SetConsoleTitle(title):
|
|
|
|
return _SetConsoleTitleW(title)
|
2023-06-15 20:22:20 +02:00
|
|
|
|
|
|
|
def GetConsoleMode(handle):
|
|
|
|
mode = wintypes.DWORD()
|
|
|
|
success = _GetConsoleMode(handle, byref(mode))
|
|
|
|
if not success:
|
|
|
|
raise ctypes.WinError()
|
|
|
|
return mode.value
|
|
|
|
|
|
|
|
def SetConsoleMode(handle, mode):
|
|
|
|
success = _SetConsoleMode(handle, mode)
|
|
|
|
if not success:
|
|
|
|
raise ctypes.WinError()
|