1 # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
9 from ctypes import LibraryLoader
10 windll = LibraryLoader(ctypes.WinDLL)
11 from ctypes import wintypes
12 except (AttributeError, ImportError):
14 SetConsoleTextAttribute = lambda *_: None
15 winapi_test = lambda *_: None
17 from ctypes import byref, Structure, c_char, POINTER
19 COORD = wintypes._COORD
21 class CONSOLE_SCREEN_BUFFER_INFO(Structure):
22 """struct in wincon.h."""
25 ("dwCursorPosition", COORD),
26 ("wAttributes", wintypes.WORD),
27 ("srWindow", wintypes.SMALL_RECT),
28 ("dwMaximumWindowSize", COORD),
31 return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % (
32 self.dwSize.Y, self.dwSize.X
33 , self.dwCursorPosition.Y, self.dwCursorPosition.X
35 , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right
36 , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X
39 _GetStdHandle = windll.kernel32.GetStdHandle
40 _GetStdHandle.argtypes = [
43 _GetStdHandle.restype = wintypes.HANDLE
45 _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo
46 _GetConsoleScreenBufferInfo.argtypes = [
48 POINTER(CONSOLE_SCREEN_BUFFER_INFO),
50 _GetConsoleScreenBufferInfo.restype = wintypes.BOOL
52 _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute
53 _SetConsoleTextAttribute.argtypes = [
57 _SetConsoleTextAttribute.restype = wintypes.BOOL
59 _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition
60 _SetConsoleCursorPosition.argtypes = [
64 _SetConsoleCursorPosition.restype = wintypes.BOOL
66 _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA
67 _FillConsoleOutputCharacterA.argtypes = [
72 POINTER(wintypes.DWORD),
74 _FillConsoleOutputCharacterA.restype = wintypes.BOOL
76 _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute
77 _FillConsoleOutputAttribute.argtypes = [
82 POINTER(wintypes.DWORD),
84 _FillConsoleOutputAttribute.restype = wintypes.BOOL
86 _SetConsoleTitleW = windll.kernel32.SetConsoleTitleA
87 _SetConsoleTitleW.argtypes = [
90 _SetConsoleTitleW.restype = wintypes.BOOL
93 STDOUT: _GetStdHandle(STDOUT),
94 STDERR: _GetStdHandle(STDERR),
98 handle = handles[STDOUT]
99 csbi = CONSOLE_SCREEN_BUFFER_INFO()
100 success = _GetConsoleScreenBufferInfo(
104 def GetConsoleScreenBufferInfo(stream_id=STDOUT):
105 handle = handles[stream_id]
106 csbi = CONSOLE_SCREEN_BUFFER_INFO()
107 success = _GetConsoleScreenBufferInfo(
111 def SetConsoleTextAttribute(stream_id, attrs):
112 handle = handles[stream_id]
113 return _SetConsoleTextAttribute(handle, attrs)
115 def SetConsoleCursorPosition(stream_id, position, adjust=True):
116 position = COORD(*position)
117 # If the position is out of range, do nothing.
118 if position.Y <= 0 or position.X <= 0:
120 # Adjust for Windows' SetConsoleCursorPosition:
121 # 1. being 0-based, while ANSI is 1-based.
122 # 2. expecting (x,y), while ANSI uses (y,x).
123 adjusted_position = COORD(position.Y - 1, position.X - 1)
125 # Adjust for viewport's scroll position
126 sr = GetConsoleScreenBufferInfo(STDOUT).srWindow
127 adjusted_position.Y += sr.Top
128 adjusted_position.X += sr.Left
129 # Resume normal processing
130 handle = handles[stream_id]
131 return _SetConsoleCursorPosition(handle, adjusted_position)
133 def FillConsoleOutputCharacter(stream_id, char, length, start):
134 handle = handles[stream_id]
135 char = c_char(char.encode())
136 length = wintypes.DWORD(length)
137 num_written = wintypes.DWORD(0)
138 # Note that this is hard-coded for ANSI (vs wide) bytes.
139 success = _FillConsoleOutputCharacterA(
140 handle, char, length, start, byref(num_written))
141 return num_written.value
143 def FillConsoleOutputAttribute(stream_id, attr, length, start):
144 ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )'''
145 handle = handles[stream_id]
146 attribute = wintypes.WORD(attr)
147 length = wintypes.DWORD(length)
148 num_written = wintypes.DWORD(0)
149 # Note that this is hard-coded for ANSI (vs wide) bytes.
150 return _FillConsoleOutputAttribute(
151 handle, attribute, length, start, byref(num_written))
153 def SetConsoleTitle(title):
154 return _SetConsoleTitleW(title)