summary refs log tree commit diff
path: root/vendor/github.com/chzyer/readline/windows_api.go
blob: 63f4f7b78fc6b148528c420a9043215ac5cd77c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// +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())
}