| # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. |
| |
| # from winbase.h |
| STDOUT = -11 |
| STDERR = -12 |
| |
| 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 |
| |
| 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) |