win32.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. # Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file.
  2. # from winbase.h
  3. STDOUT = -11
  4. STDERR = -12
  5. ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
  6. try:
  7. import ctypes
  8. from ctypes import LibraryLoader
  9. windll = LibraryLoader(ctypes.WinDLL)
  10. from ctypes import wintypes
  11. except (AttributeError, ImportError):
  12. windll = None
  13. SetConsoleTextAttribute = lambda *_: None
  14. winapi_test = lambda *_: None
  15. else:
  16. from ctypes import byref, Structure, c_char, POINTER
  17. COORD = wintypes._COORD
  18. class CONSOLE_SCREEN_BUFFER_INFO(Structure):
  19. """struct in wincon.h."""
  20. _fields_ = [
  21. ("dwSize", COORD),
  22. ("dwCursorPosition", COORD),
  23. ("wAttributes", wintypes.WORD),
  24. ("srWindow", wintypes.SMALL_RECT),
  25. ("dwMaximumWindowSize", COORD),
  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. _GetStdHandle = windll.kernel32.GetStdHandle
  36. _GetStdHandle.argtypes = [
  37. wintypes.DWORD,
  38. ]
  39. _GetStdHandle.restype = wintypes.HANDLE
  40. _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo
  41. _GetConsoleScreenBufferInfo.argtypes = [
  42. wintypes.HANDLE,
  43. POINTER(CONSOLE_SCREEN_BUFFER_INFO),
  44. ]
  45. _GetConsoleScreenBufferInfo.restype = wintypes.BOOL
  46. _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute
  47. _SetConsoleTextAttribute.argtypes = [
  48. wintypes.HANDLE,
  49. wintypes.WORD,
  50. ]
  51. _SetConsoleTextAttribute.restype = wintypes.BOOL
  52. _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition
  53. _SetConsoleCursorPosition.argtypes = [
  54. wintypes.HANDLE,
  55. COORD,
  56. ]
  57. _SetConsoleCursorPosition.restype = wintypes.BOOL
  58. _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA
  59. _FillConsoleOutputCharacterA.argtypes = [
  60. wintypes.HANDLE,
  61. c_char,
  62. wintypes.DWORD,
  63. COORD,
  64. POINTER(wintypes.DWORD),
  65. ]
  66. _FillConsoleOutputCharacterA.restype = wintypes.BOOL
  67. _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute
  68. _FillConsoleOutputAttribute.argtypes = [
  69. wintypes.HANDLE,
  70. wintypes.WORD,
  71. wintypes.DWORD,
  72. COORD,
  73. POINTER(wintypes.DWORD),
  74. ]
  75. _FillConsoleOutputAttribute.restype = wintypes.BOOL
  76. _SetConsoleTitleW = windll.kernel32.SetConsoleTitleW
  77. _SetConsoleTitleW.argtypes = [
  78. wintypes.LPCWSTR
  79. ]
  80. _SetConsoleTitleW.restype = wintypes.BOOL
  81. _GetConsoleMode = windll.kernel32.GetConsoleMode
  82. _GetConsoleMode.argtypes = [
  83. wintypes.HANDLE,
  84. POINTER(wintypes.DWORD)
  85. ]
  86. _GetConsoleMode.restype = wintypes.BOOL
  87. _SetConsoleMode = windll.kernel32.SetConsoleMode
  88. _SetConsoleMode.argtypes = [
  89. wintypes.HANDLE,
  90. wintypes.DWORD
  91. ]
  92. _SetConsoleMode.restype = wintypes.BOOL
  93. def _winapi_test(handle):
  94. csbi = CONSOLE_SCREEN_BUFFER_INFO()
  95. success = _GetConsoleScreenBufferInfo(
  96. handle, byref(csbi))
  97. return bool(success)
  98. def winapi_test():
  99. return any(_winapi_test(h) for h in
  100. (_GetStdHandle(STDOUT), _GetStdHandle(STDERR)))
  101. def GetConsoleScreenBufferInfo(stream_id=STDOUT):
  102. handle = _GetStdHandle(stream_id)
  103. csbi = CONSOLE_SCREEN_BUFFER_INFO()
  104. success = _GetConsoleScreenBufferInfo(
  105. handle, byref(csbi))
  106. return csbi
  107. def SetConsoleTextAttribute(stream_id, attrs):
  108. handle = _GetStdHandle(stream_id)
  109. return _SetConsoleTextAttribute(handle, attrs)
  110. def SetConsoleCursorPosition(stream_id, position, adjust=True):
  111. position = COORD(*position)
  112. # If the position is out of range, do nothing.
  113. if position.Y <= 0 or position.X <= 0:
  114. return
  115. # Adjust for Windows' SetConsoleCursorPosition:
  116. # 1. being 0-based, while ANSI is 1-based.
  117. # 2. expecting (x,y), while ANSI uses (y,x).
  118. adjusted_position = COORD(position.Y - 1, position.X - 1)
  119. if adjust:
  120. # Adjust for viewport's scroll position
  121. sr = GetConsoleScreenBufferInfo(STDOUT).srWindow
  122. adjusted_position.Y += sr.Top
  123. adjusted_position.X += sr.Left
  124. # Resume normal processing
  125. handle = _GetStdHandle(stream_id)
  126. return _SetConsoleCursorPosition(handle, adjusted_position)
  127. def FillConsoleOutputCharacter(stream_id, char, length, start):
  128. handle = _GetStdHandle(stream_id)
  129. char = c_char(char.encode())
  130. length = wintypes.DWORD(length)
  131. num_written = wintypes.DWORD(0)
  132. # Note that this is hard-coded for ANSI (vs wide) bytes.
  133. success = _FillConsoleOutputCharacterA(
  134. handle, char, length, start, byref(num_written))
  135. return num_written.value
  136. def FillConsoleOutputAttribute(stream_id, attr, length, start):
  137. ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )'''
  138. handle = _GetStdHandle(stream_id)
  139. attribute = wintypes.WORD(attr)
  140. length = wintypes.DWORD(length)
  141. num_written = wintypes.DWORD(0)
  142. # Note that this is hard-coded for ANSI (vs wide) bytes.
  143. return _FillConsoleOutputAttribute(
  144. handle, attribute, length, start, byref(num_written))
  145. def SetConsoleTitle(title):
  146. return _SetConsoleTitleW(title)
  147. def GetConsoleMode(handle):
  148. mode = wintypes.DWORD()
  149. success = _GetConsoleMode(handle, byref(mode))
  150. if not success:
  151. raise ctypes.WinError()
  152. return mode.value
  153. def SetConsoleMode(handle, mode):
  154. success = _SetConsoleMode(handle, mode)
  155. if not success:
  156. raise ctypes.WinError()