1
2
3
4 package windowsconsole
5
6 import (
7 "bytes"
8 "errors"
9 "fmt"
10 "io"
11 "os"
12 "strings"
13 "unsafe"
14
15 ansiterm "github.com/Azure/go-ansiterm"
16 "github.com/Azure/go-ansiterm/winterm"
17 )
18
19 const (
20 escapeSequence = ansiterm.KEY_ESC_CSI
21 )
22
23
24 type ansiReader struct {
25 file *os.File
26 fd uintptr
27 buffer []byte
28 cbBuffer int
29 command []byte
30 }
31
32
33
34 func NewAnsiReader(nFile int) io.ReadCloser {
35 file, fd := winterm.GetStdFile(nFile)
36 return &ansiReader{
37 file: file,
38 fd: fd,
39 command: make([]byte, 0, ansiterm.ANSI_MAX_CMD_LENGTH),
40 buffer: make([]byte, 0),
41 }
42 }
43
44
45 func (ar *ansiReader) Close() (err error) {
46 return ar.file.Close()
47 }
48
49
50 func (ar *ansiReader) Fd() uintptr {
51 return ar.fd
52 }
53
54
55 func (ar *ansiReader) Read(p []byte) (int, error) {
56 if len(p) == 0 {
57 return 0, nil
58 }
59
60
61 if len(ar.buffer) > 0 {
62 originalLength := len(ar.buffer)
63 copiedLength := copy(p, ar.buffer)
64
65 if copiedLength == originalLength {
66 ar.buffer = make([]byte, 0, len(p))
67 } else {
68 ar.buffer = ar.buffer[copiedLength:]
69 }
70
71 return copiedLength, nil
72 }
73
74
75 events, err := readInputEvents(ar, len(p))
76 if err != nil {
77 return 0, err
78 } else if len(events) == 0 {
79 return 0, nil
80 }
81
82 keyBytes := translateKeyEvents(events, []byte(escapeSequence))
83
84
85 if len(keyBytes) > len(p) {
86 ar.buffer = keyBytes[len(p):]
87 keyBytes = keyBytes[:len(p)]
88 } else if len(keyBytes) == 0 {
89 return 0, nil
90 }
91
92 copiedLength := copy(p, keyBytes)
93 if copiedLength != len(keyBytes) {
94 return 0, errors.New("unexpected copy length encountered")
95 }
96
97 return copiedLength, nil
98 }
99
100
101 func readInputEvents(ar *ansiReader, maxBytes int) ([]winterm.INPUT_RECORD, error) {
102
103
104
105
106 recordSize := int(unsafe.Sizeof(*((*winterm.INPUT_RECORD)(unsafe.Pointer(&maxBytes)))))
107 countRecords := maxBytes / recordSize
108 if countRecords > ansiterm.MAX_INPUT_EVENTS {
109 countRecords = ansiterm.MAX_INPUT_EVENTS
110 } else if countRecords == 0 {
111 countRecords = 1
112 }
113
114
115 events := make([]winterm.INPUT_RECORD, countRecords)
116 nEvents := uint32(0)
117 eventsExist, err := winterm.WaitForSingleObject(ar.fd, winterm.WAIT_INFINITE)
118 if err != nil {
119 return nil, err
120 }
121
122 if eventsExist {
123 err = winterm.ReadConsoleInput(ar.fd, events, &nEvents)
124 if err != nil {
125 return nil, err
126 }
127 }
128
129
130 return events[:nEvents], nil
131 }
132
133
134
135 var arrowKeyMapPrefix = map[uint16]string{
136 winterm.VK_UP: "%s%sA",
137 winterm.VK_DOWN: "%s%sB",
138 winterm.VK_RIGHT: "%s%sC",
139 winterm.VK_LEFT: "%s%sD",
140 }
141
142 var keyMapPrefix = map[uint16]string{
143 winterm.VK_UP: "\x1B[%sA",
144 winterm.VK_DOWN: "\x1B[%sB",
145 winterm.VK_RIGHT: "\x1B[%sC",
146 winterm.VK_LEFT: "\x1B[%sD",
147 winterm.VK_HOME: "\x1B[1%s~",
148 winterm.VK_END: "\x1B[4%s~",
149 winterm.VK_INSERT: "\x1B[2%s~",
150 winterm.VK_DELETE: "\x1B[3%s~",
151 winterm.VK_PRIOR: "\x1B[5%s~",
152 winterm.VK_NEXT: "\x1B[6%s~",
153 winterm.VK_F1: "",
154 winterm.VK_F2: "",
155 winterm.VK_F3: "\x1B[13%s~",
156 winterm.VK_F4: "\x1B[14%s~",
157 winterm.VK_F5: "\x1B[15%s~",
158 winterm.VK_F6: "\x1B[17%s~",
159 winterm.VK_F7: "\x1B[18%s~",
160 winterm.VK_F8: "\x1B[19%s~",
161 winterm.VK_F9: "\x1B[20%s~",
162 winterm.VK_F10: "\x1B[21%s~",
163 winterm.VK_F11: "\x1B[23%s~",
164 winterm.VK_F12: "\x1B[24%s~",
165 }
166
167
168 func translateKeyEvents(events []winterm.INPUT_RECORD, escapeSequence []byte) []byte {
169 var buffer bytes.Buffer
170 for _, event := range events {
171 if event.EventType == winterm.KEY_EVENT && event.KeyEvent.KeyDown != 0 {
172 buffer.WriteString(keyToString(&event.KeyEvent, escapeSequence))
173 }
174 }
175
176 return buffer.Bytes()
177 }
178
179
180 func keyToString(keyEvent *winterm.KEY_EVENT_RECORD, escapeSequence []byte) string {
181 if keyEvent.UnicodeChar == 0 {
182 return formatVirtualKey(keyEvent.VirtualKeyCode, keyEvent.ControlKeyState, escapeSequence)
183 }
184
185 _, alt, control := getControlKeys(keyEvent.ControlKeyState)
186 if control {
187
188
189
190
191
192
193
194 }
195
196
197 if !control && alt {
198 return ansiterm.KEY_ESC_N + strings.ToLower(string(rune(keyEvent.UnicodeChar)))
199 }
200
201 return string(rune(keyEvent.UnicodeChar))
202 }
203
204
205 func formatVirtualKey(key uint16, controlState uint32, escapeSequence []byte) string {
206 shift, alt, control := getControlKeys(controlState)
207 modifier := getControlKeysModifier(shift, alt, control)
208
209 if format, ok := arrowKeyMapPrefix[key]; ok {
210 return fmt.Sprintf(format, escapeSequence, modifier)
211 }
212
213 if format, ok := keyMapPrefix[key]; ok {
214 return fmt.Sprintf(format, modifier)
215 }
216
217 return ""
218 }
219
220
221 func getControlKeys(controlState uint32) (shift, alt, control bool) {
222 shift = 0 != (controlState & winterm.SHIFT_PRESSED)
223 alt = 0 != (controlState & (winterm.LEFT_ALT_PRESSED | winterm.RIGHT_ALT_PRESSED))
224 control = 0 != (controlState & (winterm.LEFT_CTRL_PRESSED | winterm.RIGHT_CTRL_PRESSED))
225 return shift, alt, control
226 }
227
228
229 func getControlKeysModifier(shift, alt, control bool) string {
230 if shift && alt && control {
231 return ansiterm.KEY_CONTROL_PARAM_8
232 }
233 if alt && control {
234 return ansiterm.KEY_CONTROL_PARAM_7
235 }
236 if shift && control {
237 return ansiterm.KEY_CONTROL_PARAM_6
238 }
239 if control {
240 return ansiterm.KEY_CONTROL_PARAM_5
241 }
242 if shift && alt {
243 return ansiterm.KEY_CONTROL_PARAM_4
244 }
245 if alt {
246 return ansiterm.KEY_CONTROL_PARAM_3
247 }
248 if shift {
249 return ansiterm.KEY_CONTROL_PARAM_2
250 }
251 return ""
252 }
253
View as plain text