cursor_windows.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package terminal
  2. import (
  3. "bytes"
  4. "syscall"
  5. "unsafe"
  6. )
  7. var COORDINATE_SYSTEM_BEGIN Short = 0
  8. // shared variable to save the cursor location from CursorSave()
  9. var cursorLoc Coord
  10. type Cursor struct {
  11. In FileReader
  12. Out FileWriter
  13. }
  14. func (c *Cursor) Up(n int) {
  15. c.cursorMove(0, n)
  16. }
  17. func (c *Cursor) Down(n int) {
  18. c.cursorMove(0, -1*n)
  19. }
  20. func (c *Cursor) Forward(n int) {
  21. c.cursorMove(n, 0)
  22. }
  23. func (c *Cursor) Back(n int) {
  24. c.cursorMove(-1*n, 0)
  25. }
  26. // save the cursor location
  27. func (c *Cursor) Save() {
  28. cursorLoc, _ = c.Location(nil)
  29. }
  30. func (c *Cursor) Restore() {
  31. handle := syscall.Handle(c.Out.Fd())
  32. // restore it to the original position
  33. procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursorLoc))))
  34. }
  35. func (cur Coord) CursorIsAtLineEnd(size *Coord) bool {
  36. return cur.X == size.X
  37. }
  38. func (cur Coord) CursorIsAtLineBegin() bool {
  39. return cur.X == 0
  40. }
  41. func (c *Cursor) cursorMove(x int, y int) {
  42. handle := syscall.Handle(c.Out.Fd())
  43. var csbi consoleScreenBufferInfo
  44. procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
  45. var cursor Coord
  46. cursor.X = csbi.cursorPosition.X + Short(x)
  47. cursor.Y = csbi.cursorPosition.Y + Short(y)
  48. procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor))))
  49. }
  50. func (c *Cursor) NextLine(n int) {
  51. c.Up(n)
  52. c.HorizontalAbsolute(0)
  53. }
  54. func (c *Cursor) PreviousLine(n int) {
  55. c.Down(n)
  56. c.HorizontalAbsolute(0)
  57. }
  58. // for comparability purposes between windows
  59. // in windows we don't have to print out a new line
  60. func (c *Cursor) MoveNextLine(cur Coord, terminalSize *Coord) {
  61. c.NextLine(1)
  62. }
  63. func (c *Cursor) HorizontalAbsolute(x int) {
  64. handle := syscall.Handle(c.Out.Fd())
  65. var csbi consoleScreenBufferInfo
  66. procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
  67. var cursor Coord
  68. cursor.X = Short(x)
  69. cursor.Y = csbi.cursorPosition.Y
  70. if csbi.size.X < cursor.X {
  71. cursor.X = csbi.size.X
  72. }
  73. procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor))))
  74. }
  75. func (c *Cursor) Show() {
  76. handle := syscall.Handle(c.Out.Fd())
  77. var cci consoleCursorInfo
  78. procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
  79. cci.visible = 1
  80. procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
  81. }
  82. func (c *Cursor) Hide() {
  83. handle := syscall.Handle(c.Out.Fd())
  84. var cci consoleCursorInfo
  85. procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
  86. cci.visible = 0
  87. procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
  88. }
  89. func (c *Cursor) Location(buf *bytes.Buffer) (Coord, error) {
  90. handle := syscall.Handle(c.Out.Fd())
  91. var csbi consoleScreenBufferInfo
  92. procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
  93. return csbi.cursorPosition, nil
  94. }
  95. func (c *Cursor) Size(buf *bytes.Buffer) (*Coord, error) {
  96. handle := syscall.Handle(c.Out.Fd())
  97. var csbi consoleScreenBufferInfo
  98. procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
  99. // windows' coordinate system begins at (0, 0)
  100. csbi.size.X--
  101. csbi.size.Y--
  102. return &csbi.size, nil
  103. }