| // +build windows |
| |
| package readline |
| |
| import ( |
| "reflect" |
| "syscall" |
| "unsafe" |
| ) |
| |
| var ( |
| kernel = NewKernel() |
| stdout = uintptr(syscall.Stdout) |
| stdin = uintptr(syscall.Stdin) |
| ) |
| |
| type Kernel struct { |
| SetConsoleCursorPosition, |
| SetConsoleTextAttribute, |
| FillConsoleOutputCharacterW, |
| FillConsoleOutputAttribute, |
| ReadConsoleInputW, |
| GetConsoleScreenBufferInfo, |
| GetConsoleCursorInfo, |
| GetStdHandle CallFunc |
| } |
| |
| type short int16 |
| type word uint16 |
| type dword uint32 |
| type wchar uint16 |
| |
| type _COORD struct { |
| x short |
| y short |
| } |
| |
| func (c *_COORD) ptr() uintptr { |
| return uintptr(*(*int32)(unsafe.Pointer(c))) |
| } |
| |
| const ( |
| EVENT_KEY = 0x0001 |
| EVENT_MOUSE = 0x0002 |
| EVENT_WINDOW_BUFFER_SIZE = 0x0004 |
| EVENT_MENU = 0x0008 |
| EVENT_FOCUS = 0x0010 |
| ) |
| |
| type _KEY_EVENT_RECORD struct { |
| bKeyDown int32 |
| wRepeatCount word |
| wVirtualKeyCode word |
| wVirtualScanCode word |
| unicodeChar wchar |
| dwControlKeyState dword |
| } |
| |
| // KEY_EVENT_RECORD KeyEvent; |
| // MOUSE_EVENT_RECORD MouseEvent; |
| // WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; |
| // MENU_EVENT_RECORD MenuEvent; |
| // FOCUS_EVENT_RECORD FocusEvent; |
| type _INPUT_RECORD struct { |
| EventType word |
| Padding uint16 |
| Event [16]byte |
| } |
| |
| type _CONSOLE_SCREEN_BUFFER_INFO struct { |
| dwSize _COORD |
| dwCursorPosition _COORD |
| wAttributes word |
| srWindow _SMALL_RECT |
| dwMaximumWindowSize _COORD |
| } |
| |
| type _SMALL_RECT struct { |
| left short |
| top short |
| right short |
| bottom short |
| } |
| |
| type _CONSOLE_CURSOR_INFO struct { |
| dwSize dword |
| bVisible bool |
| } |
| |
| type CallFunc func(u ...uintptr) error |
| |
| func NewKernel() *Kernel { |
| k := &Kernel{} |
| kernel32 := syscall.NewLazyDLL("kernel32.dll") |
| v := reflect.ValueOf(k).Elem() |
| t := v.Type() |
| for i := 0; i < t.NumField(); i++ { |
| name := t.Field(i).Name |
| f := kernel32.NewProc(name) |
| v.Field(i).Set(reflect.ValueOf(k.Wrap(f))) |
| } |
| return k |
| } |
| |
| func (k *Kernel) Wrap(p *syscall.LazyProc) CallFunc { |
| return func(args ...uintptr) error { |
| var r0 uintptr |
| var e1 syscall.Errno |
| size := uintptr(len(args)) |
| if len(args) <= 3 { |
| buf := make([]uintptr, 3) |
| copy(buf, args) |
| r0, _, e1 = syscall.Syscall(p.Addr(), size, |
| buf[0], buf[1], buf[2]) |
| } else { |
| buf := make([]uintptr, 6) |
| copy(buf, args) |
| r0, _, e1 = syscall.Syscall6(p.Addr(), size, |
| buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], |
| ) |
| } |
| |
| if int(r0) == 0 { |
| if e1 != 0 { |
| return error(e1) |
| } else { |
| return syscall.EINVAL |
| } |
| } |
| return nil |
| } |
| |
| } |
| |
| func GetConsoleScreenBufferInfo() (*_CONSOLE_SCREEN_BUFFER_INFO, error) { |
| t := new(_CONSOLE_SCREEN_BUFFER_INFO) |
| err := kernel.GetConsoleScreenBufferInfo( |
| stdout, |
| uintptr(unsafe.Pointer(t)), |
| ) |
| return t, err |
| } |
| |
| func GetConsoleCursorInfo() (*_CONSOLE_CURSOR_INFO, error) { |
| t := new(_CONSOLE_CURSOR_INFO) |
| err := kernel.GetConsoleCursorInfo(stdout, uintptr(unsafe.Pointer(t))) |
| return t, err |
| } |
| |
| func SetConsoleCursorPosition(c *_COORD) error { |
| return kernel.SetConsoleCursorPosition(stdout, c.ptr()) |
| } |