// +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()) }