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.

152 lines
3.0 KiB

  1. // +build windows
  2. package readline
  3. import (
  4. "reflect"
  5. "syscall"
  6. "unsafe"
  7. )
  8. var (
  9. kernel = NewKernel()
  10. stdout = uintptr(syscall.Stdout)
  11. stdin = uintptr(syscall.Stdin)
  12. )
  13. type Kernel struct {
  14. SetConsoleCursorPosition,
  15. SetConsoleTextAttribute,
  16. FillConsoleOutputCharacterW,
  17. FillConsoleOutputAttribute,
  18. ReadConsoleInputW,
  19. GetConsoleScreenBufferInfo,
  20. GetConsoleCursorInfo,
  21. GetStdHandle CallFunc
  22. }
  23. type short int16
  24. type word uint16
  25. type dword uint32
  26. type wchar uint16
  27. type _COORD struct {
  28. x short
  29. y short
  30. }
  31. func (c *_COORD) ptr() uintptr {
  32. return uintptr(*(*int32)(unsafe.Pointer(c)))
  33. }
  34. const (
  35. EVENT_KEY = 0x0001
  36. EVENT_MOUSE = 0x0002
  37. EVENT_WINDOW_BUFFER_SIZE = 0x0004
  38. EVENT_MENU = 0x0008
  39. EVENT_FOCUS = 0x0010
  40. )
  41. type _KEY_EVENT_RECORD struct {
  42. bKeyDown int32
  43. wRepeatCount word
  44. wVirtualKeyCode word
  45. wVirtualScanCode word
  46. unicodeChar wchar
  47. dwControlKeyState dword
  48. }
  49. // KEY_EVENT_RECORD KeyEvent;
  50. // MOUSE_EVENT_RECORD MouseEvent;
  51. // WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
  52. // MENU_EVENT_RECORD MenuEvent;
  53. // FOCUS_EVENT_RECORD FocusEvent;
  54. type _INPUT_RECORD struct {
  55. EventType word
  56. Padding uint16
  57. Event [16]byte
  58. }
  59. type _CONSOLE_SCREEN_BUFFER_INFO struct {
  60. dwSize _COORD
  61. dwCursorPosition _COORD
  62. wAttributes word
  63. srWindow _SMALL_RECT
  64. dwMaximumWindowSize _COORD
  65. }
  66. type _SMALL_RECT struct {
  67. left short
  68. top short
  69. right short
  70. bottom short
  71. }
  72. type _CONSOLE_CURSOR_INFO struct {
  73. dwSize dword
  74. bVisible bool
  75. }
  76. type CallFunc func(u ...uintptr) error
  77. func NewKernel() *Kernel {
  78. k := &Kernel{}
  79. kernel32 := syscall.NewLazyDLL("kernel32.dll")
  80. v := reflect.ValueOf(k).Elem()
  81. t := v.Type()
  82. for i := 0; i < t.NumField(); i++ {
  83. name := t.Field(i).Name
  84. f := kernel32.NewProc(name)
  85. v.Field(i).Set(reflect.ValueOf(k.Wrap(f)))
  86. }
  87. return k
  88. }
  89. func (k *Kernel) Wrap(p *syscall.LazyProc) CallFunc {
  90. return func(args ...uintptr) error {
  91. var r0 uintptr
  92. var e1 syscall.Errno
  93. size := uintptr(len(args))
  94. if len(args) <= 3 {
  95. buf := make([]uintptr, 3)
  96. copy(buf, args)
  97. r0, _, e1 = syscall.Syscall(p.Addr(), size,
  98. buf[0], buf[1], buf[2])
  99. } else {
  100. buf := make([]uintptr, 6)
  101. copy(buf, args)
  102. r0, _, e1 = syscall.Syscall6(p.Addr(), size,
  103. buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
  104. )
  105. }
  106. if int(r0) == 0 {
  107. if e1 != 0 {
  108. return error(e1)
  109. } else {
  110. return syscall.EINVAL
  111. }
  112. }
  113. return nil
  114. }
  115. }
  116. func GetConsoleScreenBufferInfo() (*_CONSOLE_SCREEN_BUFFER_INFO, error) {
  117. t := new(_CONSOLE_SCREEN_BUFFER_INFO)
  118. err := kernel.GetConsoleScreenBufferInfo(
  119. stdout,
  120. uintptr(unsafe.Pointer(t)),
  121. )
  122. return t, err
  123. }
  124. func GetConsoleCursorInfo() (*_CONSOLE_CURSOR_INFO, error) {
  125. t := new(_CONSOLE_CURSOR_INFO)
  126. err := kernel.GetConsoleCursorInfo(stdout, uintptr(unsafe.Pointer(t)))
  127. return t, err
  128. }
  129. func SetConsoleCursorPosition(c *_COORD) error {
  130. return kernel.SetConsoleCursorPosition(stdout, c.ptr())
  131. }