|
| 1 | +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. |
1 | 2 |
|
2 | 3 | # from winbase.h
|
3 | 4 | STDOUT = -11
|
4 | 5 | STDERR = -12
|
5 | 6 |
|
6 | 7 | try:
|
7 | 8 | from ctypes import windll
|
| 9 | + from ctypes import wintypes |
8 | 10 | except ImportError:
|
9 | 11 | windll = None
|
10 | 12 | SetConsoleTextAttribute = lambda *_: None
|
11 | 13 | else:
|
12 | 14 | from ctypes import (
|
13 |
| - byref, Structure, c_char, c_short, c_uint32, c_ushort |
| 15 | + byref, Structure, c_char, c_short, c_uint32, c_ushort, POINTER |
14 | 16 | )
|
15 | 17 |
|
16 |
| - handles = { |
17 |
| - STDOUT: windll.kernel32.GetStdHandle(STDOUT), |
18 |
| - STDERR: windll.kernel32.GetStdHandle(STDERR), |
19 |
| - } |
20 |
| - |
21 |
| - SHORT = c_short |
22 |
| - WORD = c_ushort |
23 |
| - DWORD = c_uint32 |
24 |
| - TCHAR = c_char |
25 |
| - |
26 |
| - class COORD(Structure): |
27 |
| - """struct in wincon.h""" |
28 |
| - _fields_ = [ |
29 |
| - ('X', SHORT), |
30 |
| - ('Y', SHORT), |
31 |
| - ] |
32 |
| - |
33 |
| - class SMALL_RECT(Structure): |
34 |
| - """struct in wincon.h.""" |
35 |
| - _fields_ = [ |
36 |
| - ("Left", SHORT), |
37 |
| - ("Top", SHORT), |
38 |
| - ("Right", SHORT), |
39 |
| - ("Bottom", SHORT), |
40 |
| - ] |
41 |
| - |
42 | 18 | class CONSOLE_SCREEN_BUFFER_INFO(Structure):
|
43 | 19 | """struct in wincon.h."""
|
44 | 20 | _fields_ = [
|
45 |
| - ("dwSize", COORD), |
46 |
| - ("dwCursorPosition", COORD), |
47 |
| - ("wAttributes", WORD), |
48 |
| - ("srWindow", SMALL_RECT), |
49 |
| - ("dwMaximumWindowSize", COORD), |
| 21 | + ("dwSize", wintypes._COORD), |
| 22 | + ("dwCursorPosition", wintypes._COORD), |
| 23 | + ("wAttributes", wintypes.WORD), |
| 24 | + ("srWindow", wintypes.SMALL_RECT), |
| 25 | + ("dwMaximumWindowSize", wintypes._COORD), |
50 | 26 | ]
|
| 27 | + def __str__(self): |
| 28 | + return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( |
| 29 | + self.dwSize.Y, self.dwSize.X |
| 30 | + , self.dwCursorPosition.Y, self.dwCursorPosition.X |
| 31 | + , self.wAttributes |
| 32 | + , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right |
| 33 | + , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X |
| 34 | + ) |
| 35 | + |
| 36 | + _GetStdHandle = windll.kernel32.GetStdHandle |
| 37 | + _GetStdHandle.argtypes = [ |
| 38 | + wintypes.DWORD, |
| 39 | + ] |
| 40 | + _GetStdHandle.restype = wintypes.HANDLE |
51 | 41 |
|
52 |
| - def GetConsoleScreenBufferInfo(stream_id): |
| 42 | + _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo |
| 43 | + _GetConsoleScreenBufferInfo.argtypes = [ |
| 44 | + wintypes.HANDLE, |
| 45 | + POINTER(CONSOLE_SCREEN_BUFFER_INFO), |
| 46 | + ] |
| 47 | + _GetConsoleScreenBufferInfo.restype = wintypes.BOOL |
| 48 | + |
| 49 | + _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute |
| 50 | + _SetConsoleTextAttribute.argtypes = [ |
| 51 | + wintypes.HANDLE, |
| 52 | + wintypes.WORD, |
| 53 | + ] |
| 54 | + _SetConsoleTextAttribute.restype = wintypes.BOOL |
| 55 | + |
| 56 | + _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition |
| 57 | + _SetConsoleCursorPosition.argtypes = [ |
| 58 | + wintypes.HANDLE, |
| 59 | + wintypes._COORD, |
| 60 | + ] |
| 61 | + _SetConsoleCursorPosition.restype = wintypes.BOOL |
| 62 | + |
| 63 | + _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA |
| 64 | + _FillConsoleOutputCharacterA.argtypes = [ |
| 65 | + wintypes.HANDLE, |
| 66 | + c_char, |
| 67 | + wintypes.DWORD, |
| 68 | + wintypes._COORD, |
| 69 | + POINTER(wintypes.DWORD), |
| 70 | + ] |
| 71 | + _FillConsoleOutputCharacterA.restype = wintypes.BOOL |
| 72 | + |
| 73 | + _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute |
| 74 | + _FillConsoleOutputAttribute.argtypes = [ |
| 75 | + wintypes.HANDLE, |
| 76 | + wintypes.WORD, |
| 77 | + wintypes.DWORD, |
| 78 | + wintypes._COORD, |
| 79 | + POINTER(wintypes.DWORD), |
| 80 | + ] |
| 81 | + _FillConsoleOutputAttribute.restype = wintypes.BOOL |
| 82 | + |
| 83 | + handles = { |
| 84 | + STDOUT: _GetStdHandle(STDOUT), |
| 85 | + STDERR: _GetStdHandle(STDERR), |
| 86 | + } |
| 87 | + |
| 88 | + def GetConsoleScreenBufferInfo(stream_id=STDOUT): |
53 | 89 | handle = handles[stream_id]
|
54 | 90 | csbi = CONSOLE_SCREEN_BUFFER_INFO()
|
55 |
| - success = windll.kernel32.GetConsoleScreenBufferInfo( |
| 91 | + success = _GetConsoleScreenBufferInfo( |
56 | 92 | handle, byref(csbi))
|
57 |
| - # This fails when imported via setup.py when installing using 'pip' |
58 |
| - # presumably the fix is that running setup.py should not trigger all |
59 |
| - # this activity. |
60 |
| - # assert success |
61 | 93 | return csbi
|
62 | 94 |
|
63 | 95 | def SetConsoleTextAttribute(stream_id, attrs):
|
64 | 96 | handle = handles[stream_id]
|
65 |
| - success = windll.kernel32.SetConsoleTextAttribute(handle, attrs) |
66 |
| - assert success |
| 97 | + return _SetConsoleTextAttribute(handle, attrs) |
67 | 98 |
|
68 | 99 | def SetConsoleCursorPosition(stream_id, position):
|
| 100 | + position = wintypes._COORD(*position) |
| 101 | + # If the position is out of range, do nothing. |
| 102 | + if position.Y <= 0 or position.X <= 0: |
| 103 | + return |
| 104 | + # Adjust for Windows' SetConsoleCursorPosition: |
| 105 | + # 1. being 0-based, while ANSI is 1-based. |
| 106 | + # 2. expecting (x,y), while ANSI uses (y,x). |
| 107 | + adjusted_position = wintypes._COORD(position.Y - 1, position.X - 1) |
| 108 | + # Adjust for viewport's scroll position |
| 109 | + sr = GetConsoleScreenBufferInfo(STDOUT).srWindow |
| 110 | + adjusted_position.Y += sr.Top |
| 111 | + adjusted_position.X += sr.Left |
| 112 | + # Resume normal processing |
69 | 113 | handle = handles[stream_id]
|
70 |
| - position = COORD(*position) |
71 |
| - success = windll.kernel32.SetConsoleCursorPosition(handle, position) |
72 |
| - assert success |
| 114 | + return _SetConsoleCursorPosition(handle, adjusted_position) |
73 | 115 |
|
74 | 116 | def FillConsoleOutputCharacter(stream_id, char, length, start):
|
75 | 117 | handle = handles[stream_id]
|
76 |
| - char = TCHAR(char) |
77 |
| - length = DWORD(length) |
78 |
| - start = COORD(*start) |
79 |
| - num_written = DWORD(0) |
80 |
| - # AttributeError: function 'FillConsoleOutputCharacter' not found |
81 |
| - # could it just be that my types are wrong? |
82 |
| - success = windll.kernel32.FillConsoleOutputCharacter( |
| 118 | + char = c_char(char) |
| 119 | + length = wintypes.DWORD(length) |
| 120 | + num_written = wintypes.DWORD(0) |
| 121 | + # Note that this is hard-coded for ANSI (vs wide) bytes. |
| 122 | + success = _FillConsoleOutputCharacterA( |
83 | 123 | handle, char, length, start, byref(num_written))
|
84 |
| - assert success |
85 | 124 | return num_written.value
|
86 | 125 |
|
87 |
| - |
88 |
| -if __name__=='__main__': |
89 |
| - x = GetConsoleScreenBufferInfo(STDOUT) |
90 |
| - print(x.dwSize) |
91 |
| - print(x.dwCursorPosition) |
92 |
| - print(x.wAttributes) |
93 |
| - print(x.srWindow) |
94 |
| - print(x.dwMaximumWindowSize) |
95 |
| - |
| 126 | + def FillConsoleOutputAttribute(stream_id, attr, length, start): |
| 127 | + ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )''' |
| 128 | + handle = handles[stream_id] |
| 129 | + attribute = wintypes.WORD(attr) |
| 130 | + length = wintypes.DWORD(length) |
| 131 | + num_written = wintypes.DWORD(0) |
| 132 | + # Note that this is hard-coded for ANSI (vs wide) bytes. |
| 133 | + return _FillConsoleOutputAttribute( |
| 134 | + handle, attribute, length, start, byref(num_written)) |
0 commit comments