...
1
2
3 package winterm
4
5 import (
6 "fmt"
7 "os"
8 "strconv"
9 "strings"
10 "syscall"
11
12 "github.com/Azure/go-ansiterm"
13 windows "golang.org/x/sys/windows"
14 )
15
16
17
18 const (
19 VK_PRIOR = 0x21
20 VK_NEXT = 0x22
21 VK_END = 0x23
22 VK_HOME = 0x24
23 VK_LEFT = 0x25
24 VK_UP = 0x26
25 VK_RIGHT = 0x27
26 VK_DOWN = 0x28
27 VK_SELECT = 0x29
28 VK_PRINT = 0x2A
29 VK_EXECUTE = 0x2B
30 VK_SNAPSHOT = 0x2C
31 VK_INSERT = 0x2D
32 VK_DELETE = 0x2E
33 VK_HELP = 0x2F
34 VK_F1 = 0x70
35 VK_F2 = 0x71
36 VK_F3 = 0x72
37 VK_F4 = 0x73
38 VK_F5 = 0x74
39 VK_F6 = 0x75
40 VK_F7 = 0x76
41 VK_F8 = 0x77
42 VK_F9 = 0x78
43 VK_F10 = 0x79
44 VK_F11 = 0x7A
45 VK_F12 = 0x7B
46
47 RIGHT_ALT_PRESSED = 0x0001
48 LEFT_ALT_PRESSED = 0x0002
49 RIGHT_CTRL_PRESSED = 0x0004
50 LEFT_CTRL_PRESSED = 0x0008
51 SHIFT_PRESSED = 0x0010
52 NUMLOCK_ON = 0x0020
53 SCROLLLOCK_ON = 0x0040
54 CAPSLOCK_ON = 0x0080
55 ENHANCED_KEY = 0x0100
56 )
57
58 type ansiCommand struct {
59 CommandBytes []byte
60 Command string
61 Parameters []string
62 IsSpecial bool
63 }
64
65 func newAnsiCommand(command []byte) *ansiCommand {
66
67 if isCharacterSelectionCmdChar(command[1]) {
68
69 return &ansiCommand{
70 CommandBytes: command,
71 Command: string(command),
72 IsSpecial: true,
73 }
74 }
75
76
77 lastCharIndex := len(command) - 1
78
79 ac := &ansiCommand{
80 CommandBytes: command,
81 Command: string(command[lastCharIndex]),
82 IsSpecial: false,
83 }
84
85
86 if lastCharIndex != 0 {
87 start := 1
88
89 if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY {
90 start++
91 }
92
93 ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP)
94 }
95
96 return ac
97 }
98
99 func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 {
100 if index < 0 || index >= len(ac.Parameters) {
101 return defaultValue
102 }
103
104 param, err := strconv.ParseInt(ac.Parameters[index], 10, 16)
105 if err != nil {
106 return defaultValue
107 }
108
109 return int16(param)
110 }
111
112 func (ac *ansiCommand) String() string {
113 return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
114 bytesToHex(ac.CommandBytes),
115 ac.Command,
116 strings.Join(ac.Parameters, "\",\""))
117 }
118
119
120
121 func isAnsiCommandChar(b byte) bool {
122 switch {
123 case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY:
124 return true
125 case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM:
126
127 return true
128 case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL:
129
130 return true
131 }
132 return false
133 }
134
135 func isXtermOscSequence(command []byte, current byte) bool {
136 return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL)
137 }
138
139 func isCharacterSelectionCmdChar(b byte) bool {
140 return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3)
141 }
142
143
144 func bytesToHex(b []byte) string {
145 hex := make([]string, len(b))
146 for i, ch := range b {
147 hex[i] = fmt.Sprintf("%X", ch)
148 }
149 return strings.Join(hex, "")
150 }
151
152
153
154 func ensureInRange(n int16, min int16, max int16) int16 {
155 if n < min {
156 return min
157 } else if n > max {
158 return max
159 } else {
160 return n
161 }
162 }
163
164 func GetStdFile(nFile int) (*os.File, uintptr) {
165 var file *os.File
166
167
168
169
170 switch uint32(nFile) {
171 case windows.STD_INPUT_HANDLE:
172 file = os.Stdin
173 case windows.STD_OUTPUT_HANDLE:
174 file = os.Stdout
175 case windows.STD_ERROR_HANDLE:
176 file = os.Stderr
177 default:
178 switch nFile {
179 case syscall.STD_INPUT_HANDLE:
180 file = os.Stdin
181 case syscall.STD_OUTPUT_HANDLE:
182 file = os.Stdout
183 case syscall.STD_ERROR_HANDLE:
184 file = os.Stderr
185 default:
186 panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
187 }
188 }
189
190 fd, err := syscall.GetStdHandle(nFile)
191 if err != nil {
192 panic(fmt.Errorf("Invalid standard handle identifier: %v -- %v", nFile, err))
193 }
194
195 return file, uintptr(fd)
196 }
197
View as plain text