/
vnc_driver.go
151 lines (136 loc) · 3.27 KB
/
vnc_driver.go
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
package bootcommand
import (
"fmt"
"log"
"os"
"strings"
"time"
"unicode"
"github.com/hashicorp/packer/common"
)
const KeyLeftShift uint32 = 0xFFE1
type VNCKeyEvent interface {
KeyEvent(uint32, bool) error
}
type vncDriver struct {
c VNCKeyEvent
interval time.Duration
specialMap map[string]uint32
// keyEvent can set this error which will prevent it from continuing
err error
}
func NewVNCDriver(c VNCKeyEvent, interval time.Duration) *vncDriver {
// We delay (default 100ms) between each key event to allow for CPU or
// network latency. See PackerKeyEnv for tuning.
keyInterval := common.PackerKeyDefault
if delay, err := time.ParseDuration(os.Getenv(common.PackerKeyEnv)); err == nil {
keyInterval = delay
}
// override interval based on builder-specific override.
if interval > time.Duration(0) {
keyInterval = interval
}
// Scancodes reference: https://github.com/qemu/qemu/blob/master/ui/vnc_keysym.h
sMap := make(map[string]uint32)
sMap["bs"] = 0xFF08
sMap["del"] = 0xFFFF
sMap["down"] = 0xFF54
sMap["end"] = 0xFF57
sMap["enter"] = 0xFF0D
sMap["esc"] = 0xFF1B
sMap["f1"] = 0xFFBE
sMap["f2"] = 0xFFBF
sMap["f3"] = 0xFFC0
sMap["f4"] = 0xFFC1
sMap["f5"] = 0xFFC2
sMap["f6"] = 0xFFC3
sMap["f7"] = 0xFFC4
sMap["f8"] = 0xFFC5
sMap["f9"] = 0xFFC6
sMap["f10"] = 0xFFC7
sMap["f11"] = 0xFFC8
sMap["f12"] = 0xFFC9
sMap["home"] = 0xFF50
sMap["insert"] = 0xFF63
sMap["left"] = 0xFF51
sMap["leftalt"] = 0xFFE9
sMap["leftctrl"] = 0xFFE3
sMap["leftshift"] = 0xFFE1
sMap["leftsuper"] = 0xFFEB
sMap["menu"] = 0xFF67
sMap["pagedown"] = 0xFF56
sMap["pageup"] = 0xFF55
sMap["return"] = 0xFF0D
sMap["right"] = 0xFF53
sMap["rightalt"] = 0xFFEA
sMap["rightctrl"] = 0xFFE4
sMap["rightshift"] = 0xFFE2
sMap["rightsuper"] = 0xFFEC
sMap["spacebar"] = 0x020
sMap["tab"] = 0xFF09
sMap["up"] = 0xFF52
return &vncDriver{
c: c,
interval: keyInterval,
specialMap: sMap,
}
}
func (d *vncDriver) keyEvent(k uint32, down bool) error {
if d.err != nil {
return nil
}
if err := d.c.KeyEvent(k, down); err != nil {
d.err = err
return err
}
time.Sleep(d.interval)
return nil
}
// Flush does nothing here
func (d *vncDriver) Flush() error {
return nil
}
func (d *vncDriver) SendKey(key rune, action KeyAction) error {
keyShift := unicode.IsUpper(key) || strings.ContainsRune(shiftedChars, key)
keyCode := uint32(key)
log.Printf("Sending char '%c', code 0x%X, shift %v", key, keyCode, keyShift)
switch action {
case KeyOn:
if keyShift {
d.keyEvent(KeyLeftShift, true)
}
d.keyEvent(keyCode, true)
case KeyOff:
if keyShift {
d.keyEvent(KeyLeftShift, false)
}
d.keyEvent(keyCode, false)
case KeyPress:
if keyShift {
d.keyEvent(KeyLeftShift, true)
}
d.keyEvent(keyCode, true)
d.keyEvent(keyCode, false)
if keyShift {
d.keyEvent(KeyLeftShift, false)
}
}
return d.err
}
func (d *vncDriver) SendSpecial(special string, action KeyAction) error {
keyCode, ok := d.specialMap[special]
if !ok {
return fmt.Errorf("special %s not found.", special)
}
log.Printf("Special code '<%s>' found, replacing with: 0x%X", special, keyCode)
switch action {
case KeyOn:
d.keyEvent(keyCode, true)
case KeyOff:
d.keyEvent(keyCode, false)
case KeyPress:
d.keyEvent(keyCode, true)
d.keyEvent(keyCode, false)
}
return d.err
}