You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

win32.py 5.3KB

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