api.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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_AUTO_POSITION = 0x0100
  55. ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200
  56. ENABLE_PROCESSED_OUTPUT = 0x0001
  57. ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
  58. ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
  59. DISABLE_NEWLINE_AUTO_RETURN = 0x0008
  60. ENABLE_LVB_GRID_WORLDWIDE = 0x0010
  61. // Character attributes
  62. // Note:
  63. // -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
  64. // Clearing all foreground or background colors results in black; setting all creates white.
  65. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
  66. FOREGROUND_BLUE uint16 = 0x0001
  67. FOREGROUND_GREEN uint16 = 0x0002
  68. FOREGROUND_RED uint16 = 0x0004
  69. FOREGROUND_INTENSITY uint16 = 0x0008
  70. FOREGROUND_MASK uint16 = 0x000F
  71. BACKGROUND_BLUE uint16 = 0x0010
  72. BACKGROUND_GREEN uint16 = 0x0020
  73. BACKGROUND_RED uint16 = 0x0040
  74. BACKGROUND_INTENSITY uint16 = 0x0080
  75. BACKGROUND_MASK uint16 = 0x00F0
  76. COMMON_LVB_MASK uint16 = 0xFF00
  77. COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000
  78. COMMON_LVB_UNDERSCORE uint16 = 0x8000
  79. // Input event types
  80. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
  81. KEY_EVENT = 0x0001
  82. MOUSE_EVENT = 0x0002
  83. WINDOW_BUFFER_SIZE_EVENT = 0x0004
  84. MENU_EVENT = 0x0008
  85. FOCUS_EVENT = 0x0010
  86. // WaitForSingleObject return codes
  87. WAIT_ABANDONED = 0x00000080
  88. WAIT_FAILED = 0xFFFFFFFF
  89. WAIT_SIGNALED = 0x0000000
  90. WAIT_TIMEOUT = 0x00000102
  91. // WaitForSingleObject wait duration
  92. WAIT_INFINITE = 0xFFFFFFFF
  93. WAIT_ONE_SECOND = 1000
  94. WAIT_HALF_SECOND = 500
  95. WAIT_QUARTER_SECOND = 250
  96. )
  97. // Windows API Console types
  98. // -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
  99. // -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
  100. type (
  101. CHAR_INFO struct {
  102. UnicodeChar uint16
  103. Attributes uint16
  104. }
  105. CONSOLE_CURSOR_INFO struct {
  106. Size uint32
  107. Visible int32
  108. }
  109. CONSOLE_SCREEN_BUFFER_INFO struct {
  110. Size COORD
  111. CursorPosition COORD
  112. Attributes uint16
  113. Window SMALL_RECT
  114. MaximumWindowSize COORD
  115. }
  116. COORD struct {
  117. X int16
  118. Y int16
  119. }
  120. SMALL_RECT struct {
  121. Left int16
  122. Top int16
  123. Right int16
  124. Bottom int16
  125. }
  126. // INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
  127. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
  128. INPUT_RECORD struct {
  129. EventType uint16
  130. KeyEvent KEY_EVENT_RECORD
  131. }
  132. KEY_EVENT_RECORD struct {
  133. KeyDown int32
  134. RepeatCount uint16
  135. VirtualKeyCode uint16
  136. VirtualScanCode uint16
  137. UnicodeChar uint16
  138. ControlKeyState uint32
  139. }
  140. WINDOW_BUFFER_SIZE struct {
  141. Size COORD
  142. }
  143. )
  144. // boolToBOOL converts a Go bool into a Windows int32.
  145. func boolToBOOL(f bool) int32 {
  146. if f {
  147. return int32(1)
  148. } else {
  149. return int32(0)
  150. }
  151. }
  152. // GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor.
  153. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx.
  154. func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
  155. r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
  156. return checkError(r1, r2, err)
  157. }
  158. // SetConsoleCursorInfo sets the size and visiblity of the console cursor.
  159. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx.
  160. func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
  161. r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
  162. return checkError(r1, r2, err)
  163. }
  164. // SetConsoleCursorPosition location of the console cursor.
  165. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
  166. func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
  167. r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
  168. use(coord)
  169. return checkError(r1, r2, err)
  170. }
  171. // GetConsoleMode gets the console mode for given file descriptor
  172. // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
  173. func GetConsoleMode(handle uintptr) (mode uint32, err error) {
  174. err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
  175. return mode, err
  176. }
  177. // SetConsoleMode sets the console mode for given file descriptor
  178. // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
  179. func SetConsoleMode(handle uintptr, mode uint32) error {
  180. r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
  181. use(mode)
  182. return checkError(r1, r2, err)
  183. }
  184. // GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
  185. // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
  186. func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
  187. info := CONSOLE_SCREEN_BUFFER_INFO{}
  188. err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
  189. if err != nil {
  190. return nil, err
  191. }
  192. return &info, nil
  193. }
  194. func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
  195. r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
  196. use(scrollRect)
  197. use(clipRect)
  198. use(destOrigin)
  199. use(char)
  200. return checkError(r1, r2, err)
  201. }
  202. // SetConsoleScreenBufferSize sets the size of the console screen buffer.
  203. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
  204. func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
  205. r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
  206. use(coord)
  207. return checkError(r1, r2, err)
  208. }
  209. // SetConsoleTextAttribute sets the attributes of characters written to the
  210. // console screen buffer by the WriteFile or WriteConsole function.
  211. // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
  212. func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
  213. r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
  214. use(attribute)
  215. return checkError(r1, r2, err)
  216. }
  217. // SetConsoleWindowInfo sets the size and position of the console screen buffer's window.
  218. // Note that the size and location must be within and no larger than the backing console screen buffer.
  219. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
  220. func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
  221. r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
  222. use(isAbsolute)
  223. use(rect)
  224. return checkError(r1, r2, err)
  225. }
  226. // WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer.
  227. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
  228. func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
  229. r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
  230. use(buffer)
  231. use(bufferSize)
  232. use(bufferCoord)
  233. return checkError(r1, r2, err)
  234. }
  235. // ReadConsoleInput reads (and removes) data from the console input buffer.
  236. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
  237. func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
  238. r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
  239. use(buffer)
  240. return checkError(r1, r2, err)
  241. }
  242. // WaitForSingleObject waits for the passed handle to be signaled.
  243. // It returns true if the handle was signaled; false otherwise.
  244. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
  245. func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
  246. r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
  247. switch r1 {
  248. case WAIT_ABANDONED, WAIT_TIMEOUT:
  249. return false, nil
  250. case WAIT_SIGNALED:
  251. return true, nil
  252. }
  253. use(msWait)
  254. return false, err
  255. }
  256. // String helpers
  257. func (info CONSOLE_SCREEN_BUFFER_INFO) String() string {
  258. return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize)
  259. }
  260. func (coord COORD) String() string {
  261. return fmt.Sprintf("%v,%v", coord.X, coord.Y)
  262. }
  263. func (rect SMALL_RECT) String() string {
  264. return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom)
  265. }
  266. // checkError evaluates the results of a Windows API call and returns the error if it failed.
  267. func checkError(r1, r2 uintptr, err error) error {
  268. // Windows APIs return non-zero to indicate success
  269. if r1 != 0 {
  270. return nil
  271. }
  272. // Return the error if provided, otherwise default to EINVAL
  273. if err != nil {
  274. return err
  275. }
  276. return syscall.EINVAL
  277. }
  278. // coordToPointer converts a COORD into a uintptr (by fooling the type system).
  279. func coordToPointer(c COORD) uintptr {
  280. // Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass.
  281. return uintptr(*((*uint32)(unsafe.Pointer(&c))))
  282. }
  283. // use is a no-op, but the compiler cannot see that it is.
  284. // Calling use(p) ensures that p is kept live until that point.
  285. func use(p interface{}) {}