github.com/angdraug/packer@v1.3.2/common/bootcommand/vnc_driver.go (about) 1 package bootcommand 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "strings" 8 "time" 9 "unicode" 10 11 "github.com/hashicorp/packer/common" 12 ) 13 14 const KeyLeftShift uint32 = 0xFFE1 15 16 type VNCKeyEvent interface { 17 KeyEvent(uint32, bool) error 18 } 19 20 type vncDriver struct { 21 c VNCKeyEvent 22 interval time.Duration 23 specialMap map[string]uint32 24 // keyEvent can set this error which will prevent it from continuing 25 err error 26 } 27 28 func NewVNCDriver(c VNCKeyEvent, interval time.Duration) *vncDriver { 29 // We delay (default 100ms) between each key event to allow for CPU or 30 // network latency. See PackerKeyEnv for tuning. 31 keyInterval := common.PackerKeyDefault 32 if delay, err := time.ParseDuration(os.Getenv(common.PackerKeyEnv)); err == nil { 33 keyInterval = delay 34 } 35 // override interval based on builder-specific override. 36 if interval > time.Duration(0) { 37 keyInterval = interval 38 } 39 40 // Scancodes reference: https://github.com/qemu/qemu/blob/master/ui/vnc_keysym.h 41 sMap := make(map[string]uint32) 42 sMap["bs"] = 0xFF08 43 sMap["del"] = 0xFFFF 44 sMap["down"] = 0xFF54 45 sMap["end"] = 0xFF57 46 sMap["enter"] = 0xFF0D 47 sMap["esc"] = 0xFF1B 48 sMap["f1"] = 0xFFBE 49 sMap["f2"] = 0xFFBF 50 sMap["f3"] = 0xFFC0 51 sMap["f4"] = 0xFFC1 52 sMap["f5"] = 0xFFC2 53 sMap["f6"] = 0xFFC3 54 sMap["f7"] = 0xFFC4 55 sMap["f8"] = 0xFFC5 56 sMap["f9"] = 0xFFC6 57 sMap["f10"] = 0xFFC7 58 sMap["f11"] = 0xFFC8 59 sMap["f12"] = 0xFFC9 60 sMap["home"] = 0xFF50 61 sMap["insert"] = 0xFF63 62 sMap["left"] = 0xFF51 63 sMap["leftalt"] = 0xFFE9 64 sMap["leftctrl"] = 0xFFE3 65 sMap["leftshift"] = 0xFFE1 66 sMap["leftsuper"] = 0xFFEB 67 sMap["menu"] = 0xFF67 68 sMap["pagedown"] = 0xFF56 69 sMap["pageup"] = 0xFF55 70 sMap["return"] = 0xFF0D 71 sMap["right"] = 0xFF53 72 sMap["rightalt"] = 0xFFEA 73 sMap["rightctrl"] = 0xFFE4 74 sMap["rightshift"] = 0xFFE2 75 sMap["rightsuper"] = 0xFFEC 76 sMap["spacebar"] = 0x020 77 sMap["tab"] = 0xFF09 78 sMap["up"] = 0xFF52 79 80 return &vncDriver{ 81 c: c, 82 interval: keyInterval, 83 specialMap: sMap, 84 } 85 } 86 87 func (d *vncDriver) keyEvent(k uint32, down bool) error { 88 if d.err != nil { 89 return nil 90 } 91 if err := d.c.KeyEvent(k, down); err != nil { 92 d.err = err 93 return err 94 } 95 time.Sleep(d.interval) 96 return nil 97 } 98 99 // Flush does nothing here 100 func (d *vncDriver) Flush() error { 101 return nil 102 } 103 104 func (d *vncDriver) SendKey(key rune, action KeyAction) error { 105 keyShift := unicode.IsUpper(key) || strings.ContainsRune(shiftedChars, key) 106 keyCode := uint32(key) 107 log.Printf("Sending char '%c', code 0x%X, shift %v", key, keyCode, keyShift) 108 109 switch action { 110 case KeyOn: 111 if keyShift { 112 d.keyEvent(KeyLeftShift, true) 113 } 114 d.keyEvent(keyCode, true) 115 case KeyOff: 116 if keyShift { 117 d.keyEvent(KeyLeftShift, false) 118 } 119 d.keyEvent(keyCode, false) 120 case KeyPress: 121 if keyShift { 122 d.keyEvent(KeyLeftShift, true) 123 } 124 d.keyEvent(keyCode, true) 125 d.keyEvent(keyCode, false) 126 if keyShift { 127 d.keyEvent(KeyLeftShift, false) 128 } 129 } 130 return d.err 131 } 132 133 func (d *vncDriver) SendSpecial(special string, action KeyAction) error { 134 keyCode, ok := d.specialMap[special] 135 if !ok { 136 return fmt.Errorf("special %s not found.", special) 137 } 138 log.Printf("Special code '<%s>' found, replacing with: 0x%X", special, keyCode) 139 140 switch action { 141 case KeyOn: 142 d.keyEvent(keyCode, true) 143 case KeyOff: 144 d.keyEvent(keyCode, false) 145 case KeyPress: 146 d.keyEvent(keyCode, true) 147 d.keyEvent(keyCode, false) 148 } 149 150 return d.err 151 }