api.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // +build windows
  2. package winterm
  3. import (
  4. "fmt"
  5. "syscall"
  6. "unsafe"
  7. )
  8. //===========================================================================================================
  9. // IMPORTANT NOTE:
  10. //
  11. // The methods below make extensive use of the "unsafe" package to obtain the required pointers.
  12. // Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack
  13. // variables) the pointers reference *before* the API completes.
  14. //
  15. // As a result, in those cases, the code must hint that the variables remain in active by invoking the
  16. // dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer
  17. // require unsafe pointers.
  18. //
  19. // If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform
  20. // the garbage collector the variables remain in use if:
  21. //
  22. // -- The value is not a pointer (e.g., int32, struct)
  23. // -- The value is not referenced by the method after passing the pointer to Windows
  24. //
  25. // See http://golang.org/doc/go1.3.
  26. //===========================================================================================================
  27. var (
  28. kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
  29. getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo")
  30. setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo")
  31. setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition")
  32. setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
  33. getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
  34. setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
  35. scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA")
  36. setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute")
  37. setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo")
  38. writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW")
  39. readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW")
  40. waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject")
  41. )
  42. // Windows Console constants
  43. const (
  44. // Console modes
  45. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
  46. ENABLE_PROCESSED_INPUT = 0x0001
  47. ENABLE_LINE_INPUT = 0x0002
  48. ENABLE_ECHO_INPUT = 0x0004
  49. ENABLE_WINDOW_INPUT = 0x0008
  50. ENABLE_MOUSE_INPUT = 0x0010
  51. ENABLE_INSERT_MODE = 0x0020
  52. ENABLE_QUICK_EDIT_MODE = 0x0040
  53. ENABLE_EXTENDED_FLAGS = 0x0080
  54. ENABLE_PROCESSED_OUTPUT = 0x0001
  55. ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
  56. // Character attributes
  57. // Note:
  58. // -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
  59. // Clearing all foreground or background colors results in black; setting all creates white.
  60. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
  61. FOREGROUND_BLUE uint16 = 0x0001
  62. FOREGROUND_GREEN uint16 = 0x0002
  63. FOREGROUND_RED uint16 = 0x0004
  64. FOREGROUND_INTENSITY uint16 = 0x0008
  65. FOREGROUND_MASK uint16 = 0x000F
  66. BACKGROUND_BLUE uint16 = 0x0010
  67. BACKGROUND_GREEN uint16 = 0x0020
  68. BACKGROUND_RED uint16 = 0x0040
  69. BACKGROUND_INTENSITY uint16 = 0x0080
  70. BACKGROUND_MASK uint16 = 0x00F0
  71. COMMON_LVB_MASK uint16 = 0xFF00
  72. COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000
  73. COMMON_LVB_UNDERSCORE uint16 = 0x8000
  74. // Input event types
  75. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
  76. KEY_EVENT = 0x0001
  77. MOUSE_EVENT = 0x0002
  78. WINDOW_BUFFER_SIZE_EVENT = 0x0004
  79. MENU_EVENT = 0x0008
  80. FOCUS_EVENT = 0x0010
  81. // WaitForSingleObject return codes
  82. WAIT_ABANDONED = 0x00000080
  83. WAIT_FAILED = 0xFFFFFFFF
  84. WAIT_SIGNALED = 0x0000000
  85. WAIT_TIMEOUT = 0x00000102
  86. // WaitForSingleObject wait duration
  87. WAIT_INFINITE = 0xFFFFFFFF
  88. WAIT_ONE_SECOND = 1000
  89. WAIT_HALF_SECOND = 500
  90. WAIT_QUARTER_SECOND = 250
  91. )
  92. // Windows API Console types
  93. // -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
  94. // -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
  95. type (
  96. CHAR_INFO struct {
  97. UnicodeChar uint16
  98. Attributes uint16
  99. }
  100. CONSOLE_CURSOR_INFO struct {
  101. Size uint32
  102. Visible int32
  103. }
  104. CONSOLE_SCREEN_BUFFER_INFO struct {
  105. Size COORD
  106. CursorPosition COORD
  107. Attributes uint16
  108. Window SMALL_RECT
  109. MaximumWindowSize COORD
  110. }
  111. COORD struct {
  112. X int16
  113. Y int16
  114. }
  115. SMALL_RECT struct {
  116. Left int16
  117. Top int16
  118. Right int16
  119. Bottom int16
  120. }
  121. // INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
  122. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
  123. INPUT_RECORD struct {
  124. EventType uint16
  125. KeyEvent KEY_EVENT_RECORD
  126. }
  127. KEY_EVENT_RECORD struct {
  128. KeyDown int32
  129. RepeatCount uint16
  130. VirtualKeyCode uint16
  131. VirtualScanCode uint16
  132. UnicodeChar uint16
  133. ControlKeyState uint32
  134. }
  135. WINDOW_BUFFER_SIZE struct {
  136. Size COORD
  137. }
  138. )
  139. // boolToBOOL converts a Go bool into a Windows int32.
  140. func boolToBOOL(f bool) int32 {
  141. if f {
  142. return int32(1)
  143. } else {
  144. return int32(0)
  145. }
  146. }
  147. // GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor.
  148. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx.
  149. func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
  150. r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
  151. return checkError(r1, r2, err)
  152. }
  153. // SetConsoleCursorInfo sets the size and visiblity of the console cursor.
  154. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx.
  155. func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
  156. r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
  157. return checkError(r1, r2, err)
  158. }
  159. // SetConsoleCursorPosition location of the console cursor.
  160. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
  161. func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
  162. r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
  163. use(coord)
  164. return checkError(r1, r2, err)
  165. }
  166. // GetConsoleMode gets the console mode for given file descriptor
  167. // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
  168. func GetConsoleMode(handle uintptr) (mode uint32, err error) {
  169. err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
  170. return mode, err
  171. }
  172. // SetConsoleMode sets the console mode for given file descriptor
  173. // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
  174. func SetConsoleMode(handle uintptr, mode uint32) error {
  175. r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
  176. use(mode)
  177. return checkError(r1, r2, err)
  178. }
  179. // GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
  180. // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
  181. func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
  182. info := CONSOLE_SCREEN_BUFFER_INFO{}
  183. err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
  184. if err != nil {
  185. return nil, err
  186. }
  187. return &info, nil
  188. }
  189. func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
  190. r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
  191. use(scrollRect)
  192. use(clipRect)
  193. use(destOrigin)
  194. use(char)
  195. return checkError(r1, r2, err)
  196. }
  197. // SetConsoleScreenBufferSize sets the size of the console screen buffer.
  198. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
  199. func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
  200. r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
  201. use(coord)
  202. return checkError(r1, r2, err)
  203. }
  204. // SetConsoleTextAttribute sets the attributes of characters written to the
  205. // console screen buffer by the WriteFile or WriteConsole function.
  206. // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
  207. func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
  208. r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
  209. use(attribute)
  210. return checkError(r1, r2, err)
  211. }
  212. // SetConsoleWindowInfo sets the size and position of the console screen buffer's window.
  213. // Note that the size and location must be within and no larger than the backing console screen buffer.
  214. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
  215. func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
  216. r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
  217. use(isAbsolute)
  218. use(rect)
  219. return checkError(r1, r2, err)
  220. }
  221. // WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer.
  222. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
  223. func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
  224. r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
  225. use(buffer)
  226. use(bufferSize)
  227. use(bufferCoord)
  228. return checkError(r1, r2, err)
  229. }
  230. // ReadConsoleInput reads (and removes) data from the console input buffer.
  231. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
  232. func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
  233. r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
  234. use(buffer)
  235. return checkError(r1, r2, err)
  236. }
  237. // WaitForSingleObject waits for the passed handle to be signaled.
  238. // It returns true if the handle was signaled; false otherwise.
  239. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
  240. func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
  241. r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
  242. switch r1 {
  243. case WAIT_ABANDONED, WAIT_TIMEOUT:
  244. return false, nil
  245. case WAIT_SIGNALED:
  246. return true, nil
  247. }
  248. use(msWait)
  249. return false, err
  250. }
  251. // String helpers
  252. func (info CONSOLE_SCREEN_BUFFER_INFO) String() string {
  253. return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize)
  254. }
  255. func (coord COORD) String() string {
  256. return fmt.Sprintf("%v,%v", coord.X, coord.Y)
  257. }
  258. func (rect SMALL_RECT) String() string {
  259. return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom)
  260. }
  261. // checkError evaluates the results of a Windows API call and returns the error if it failed.
  262. func checkError(r1, r2 uintptr, err error) error {
  263. // Windows APIs return non-zero to indicate success
  264. if r1 != 0 {
  265. return nil
  266. }
  267. // Return the error if provided, otherwise default to EINVAL
  268. if err != nil {
  269. return err
  270. }
  271. return syscall.EINVAL
  272. }
  273. // coordToPointer converts a COORD into a uintptr (by fooling the type system).
  274. func coordToPointer(c COORD) uintptr {
  275. // Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass.
  276. return uintptr(*((*uint32)(unsafe.Pointer(&c))))
  277. }
  278. // use is a no-op, but the compiler cannot see that it is.
  279. // Calling use(p) ensures that p is kept live until that point.
  280. func use(p interface{}) {}