137 lines
3.7 KiB
Go
137 lines
3.7 KiB
Go
package bootcommand
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
"unicode"
|
|
|
|
"github.com/hashicorp/packer/common"
|
|
"golang.org/x/mobile/event/key"
|
|
)
|
|
|
|
// SendUsbScanCodes will be called to send codes to the VM
|
|
type SendUsbScanCodes func(k key.Code, down bool) error
|
|
|
|
type usbDriver struct {
|
|
sendImpl SendUsbScanCodes
|
|
interval time.Duration
|
|
specialMap map[string]key.Code
|
|
scancodeMap map[rune]key.Code
|
|
}
|
|
|
|
func NewUSBDriver(send SendUsbScanCodes, interval time.Duration) *usbDriver {
|
|
// 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
|
|
}
|
|
|
|
special := map[string]key.Code{
|
|
"enter": key.CodeReturnEnter,
|
|
"return": key.CodeReturnEnter,
|
|
"esc": key.CodeEscape,
|
|
"bs": key.CodeDeleteBackspace,
|
|
"del": key.CodeDeleteForward,
|
|
"tab": key.CodeTab,
|
|
"f1": key.CodeF1,
|
|
"f2": key.CodeF2,
|
|
"f3": key.CodeF3,
|
|
"f4": key.CodeF4,
|
|
"f5": key.CodeF5,
|
|
"f6": key.CodeF6,
|
|
"f7": key.CodeF7,
|
|
"f8": key.CodeF8,
|
|
"f9": key.CodeF9,
|
|
"f10": key.CodeF10,
|
|
"f11": key.CodeF11,
|
|
"f12": key.CodeF12,
|
|
"insert": key.CodeInsert,
|
|
"home": key.CodeHome,
|
|
"end": key.CodeEnd,
|
|
"pageUp": key.CodePageUp,
|
|
"pageDown": key.CodePageDown,
|
|
"left": key.CodeLeftArrow,
|
|
"right": key.CodeRightArrow,
|
|
"up": key.CodeUpArrow,
|
|
"down": key.CodeDownArrow,
|
|
"leftalt": key.CodeLeftAlt,
|
|
"leftctrl": key.CodeLeftControl,
|
|
"leftshift": key.CodeLeftShift,
|
|
"rightalt": key.CodeRightAlt,
|
|
"rightctrl": key.CodeRightControl,
|
|
"rightshift": key.CodeRightShift,
|
|
"leftsuper": key.CodeLeftGUI,
|
|
"rightsuper": key.CodeRightGUI,
|
|
"spacebar": key.CodeSpacebar,
|
|
}
|
|
|
|
scancodeIndex := make(map[string]key.Code)
|
|
scancodeIndex["abcdefghijklmnopqrstuvwxyz"] = key.CodeA
|
|
scancodeIndex["ABCDEFGHIJKLMNOPQRSTUVWXYZ"] = key.CodeA
|
|
scancodeIndex["1234567890"] = key.Code1
|
|
scancodeIndex["!@#$%^&*()"] = key.Code1
|
|
scancodeIndex[" "] = key.CodeSpacebar
|
|
scancodeIndex["-=[]\\"] = key.CodeHyphenMinus
|
|
scancodeIndex["_+{}|"] = key.CodeHyphenMinus
|
|
scancodeIndex[";'`,./"] = key.CodeSemicolon
|
|
scancodeIndex[":\"~<>?"] = key.CodeSemicolon
|
|
|
|
var scancodeMap = make(map[rune]key.Code)
|
|
for chars, start := range scancodeIndex {
|
|
for i, r := range chars {
|
|
scancodeMap[r] = start + key.Code(i)
|
|
}
|
|
}
|
|
|
|
return &usbDriver{
|
|
sendImpl: send,
|
|
specialMap: special,
|
|
interval: keyInterval,
|
|
scancodeMap: scancodeMap,
|
|
}
|
|
}
|
|
|
|
func (d *usbDriver) keyEvent(k key.Code, down bool) error {
|
|
if err := d.sendImpl(k, down); err != nil {
|
|
return err
|
|
}
|
|
time.Sleep(d.interval)
|
|
return nil
|
|
}
|
|
|
|
func (d *usbDriver) Flush() error {
|
|
return nil
|
|
}
|
|
|
|
func (d *usbDriver) SendKey(k rune, action KeyAction) error {
|
|
keyShift := unicode.IsUpper(k) || strings.ContainsRune(shiftedChars, k)
|
|
keyCode := d.scancodeMap[k]
|
|
log.Printf("Sending char '%c', code %s, shift %v", k, keyCode, keyShift)
|
|
return d.keyEvent(keyCode, keyShift)
|
|
}
|
|
|
|
func (d *usbDriver) SendSpecial(special string, action KeyAction) (err error) {
|
|
keyCode, ok := d.specialMap[special]
|
|
if !ok {
|
|
return fmt.Errorf("special %s not found.", special)
|
|
}
|
|
log.Printf("Special code '<%s>' found, replacing with: %s", special, keyCode)
|
|
|
|
switch action {
|
|
case KeyOn:
|
|
err = d.keyEvent(keyCode, true)
|
|
case KeyOff, KeyPress:
|
|
err = d.keyEvent(keyCode, false)
|
|
}
|
|
|
|
return err
|
|
}
|