Abstract vbox driver into PC-AT driver.

This commit is contained in:
Matthew Hooker 2018-04-12 15:59:07 -07:00
parent e4af71858f
commit 99d61920d0
No known key found for this signature in database
GPG Key ID: 7B5F933D9CE8C6A1
5 changed files with 161 additions and 147 deletions

View File

@ -3,11 +3,7 @@ package common
import (
"context"
"fmt"
"log"
"strings"
"time"
"unicode"
"unicode/utf8"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/common/boot_command"
@ -72,10 +68,16 @@ func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
s.VMName,
}
d := &VBoxBCDriver{
driver,
vmName,
sendCodes := func(codes []string) error {
args := []string{"controlvm", vmName, "keyboardputscancode"}
args = append(args, codes...)
if err := driver.VBoxManage(args...); err != nil {
return err
}
return nil
}
d := bootcommand.NewPCATDriver(sendCodes)
ui.Say("Typing the boot command...")
for i, command := range s.BootCommand {
@ -116,128 +118,3 @@ func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
}
func (*StepTypeBootCommand) Cleanup(multistep.StateBag) {}
type VBoxBCDriver struct {
driver Driver
vmName string
}
func (d *VBoxBCDriver) sendCode(codes []string) error {
args := []string{"controlvm", d.vmName, "keyboardputscancode"}
args = append(args, codes...)
if err := d.driver.VBoxManage(args...); err != nil {
return err
}
return nil
}
func (d *VBoxBCDriver) SendKey(key rune, action bootcommand.KeyAction) error {
shiftedChars := "~!@#$%^&*()_+{}|:\"<>?"
scancodeIndex := make(map[string]uint)
scancodeIndex["1234567890-="] = 0x02
scancodeIndex["!@#$%^&*()_+"] = 0x02
scancodeIndex["qwertyuiop[]"] = 0x10
scancodeIndex["QWERTYUIOP{}"] = 0x10
scancodeIndex["asdfghjkl;'`"] = 0x1e
scancodeIndex[`ASDFGHJKL:"~`] = 0x1e
scancodeIndex[`\zxcvbnm,./`] = 0x2b
scancodeIndex["|ZXCVBNM<>?"] = 0x2b
scancodeIndex[" "] = 0x39
scancodeMap := make(map[rune]uint)
for chars, start := range scancodeIndex {
var i uint = 0
for len(chars) > 0 {
r, size := utf8.DecodeRuneInString(chars)
chars = chars[size:]
scancodeMap[r] = start + i
i += 1
}
}
keyShift := unicode.IsUpper(key) || strings.ContainsRune(shiftedChars, key)
var scancode []string
if action&(bootcommand.KeyOn|bootcommand.KeyPress) != 0 {
scancodeInt := scancodeMap[key]
if keyShift {
scancode = append(scancode, "2a")
}
scancode = append(scancode, fmt.Sprintf("%02x", scancodeInt))
}
if action&(bootcommand.KeyOff|bootcommand.KeyPress) != 0 {
scancodeInt := scancodeMap[key] + 0x80
if keyShift {
scancode = append(scancode, "aa")
}
scancode = append(scancode, fmt.Sprintf("%02x", scancodeInt))
}
for _, sc := range scancode {
log.Printf("Sending char '%c', code '%s', shift %v", key, sc, keyShift)
}
d.sendCode(scancode)
return nil
}
func (d *VBoxBCDriver) SendSpecial(special string, action bootcommand.KeyAction) error {
// special contains on/off tuples
sMap := make(map[string][]string)
sMap["bs"] = []string{"0e", "8e"}
sMap["del"] = []string{"e053", "e0d3"}
sMap["enter"] = []string{"1c", "9c"}
sMap["esc"] = []string{"01", "81"}
sMap["f1"] = []string{"3b", "bb"}
sMap["f2"] = []string{"3c", "bc"}
sMap["f3"] = []string{"3d", "bd"}
sMap["f4"] = []string{"3e", "be"}
sMap["f5"] = []string{"3f", "bf"}
sMap["f6"] = []string{"40", "c0"}
sMap["f7"] = []string{"41", "c1"}
sMap["f8"] = []string{"42", "c2"}
sMap["f9"] = []string{"43", "c3"}
sMap["f10"] = []string{"44", "c4"}
sMap["f11"] = []string{"57", "d7"}
sMap["f12"] = []string{"58", "d8"}
sMap["return"] = []string{"1c", "9c"}
sMap["tab"] = []string{"0f", "8f"}
sMap["up"] = []string{"e048", "e0c8"}
sMap["down"] = []string{"e050", "e0d0"}
sMap["left"] = []string{"e04b", "e0cb"}
sMap["right"] = []string{"e04d", "e0cd"}
sMap["spacebar"] = []string{"39", "b9"}
sMap["insert"] = []string{"e052", "e0d2"}
sMap["home"] = []string{"e047", "e0c7"}
sMap["end"] = []string{"e04f", "e0cf"}
sMap["pageUp"] = []string{"e049", "e0c9"}
sMap["pageDown"] = []string{"e051", "e0d1"}
sMap["leftAlt"] = []string{"38", "b8"}
sMap["leftCtrl"] = []string{"1d", "9d"}
sMap["leftShift"] = []string{"2a", "aa"}
sMap["rightAlt"] = []string{"e038", "e0b8"}
sMap["rightCtrl"] = []string{"e01d", "e09d"}
sMap["rightShift"] = []string{"36", "b6"}
sMap["leftSuper"] = []string{"e05b", "e0db"}
sMap["rightSuper"] = []string{"e05c", "e0dc"}
keyCode, ok := sMap[special]
if !ok {
return fmt.Errorf("special %s not found.", special)
}
switch action {
case bootcommand.KeyOn:
d.sendCode([]string{keyCode[0]})
case bootcommand.KeyOff:
d.sendCode([]string{keyCode[1]})
case bootcommand.KeyPress:
d.sendCode(keyCode)
}
return nil
}

View File

@ -11,6 +11,7 @@ import (
/*
TODO:
* tests
* fix vbox tests
* comments
* lower-case specials
* check that `<del>` works on parallels. It's different now.
@ -50,12 +51,6 @@ func (k KeyAction) String() string {
panic(fmt.Sprintf("Unknwon KeyAction %d", k))
}
// BCDriver is our access to the VM we want to type boot commands to
type BCDriver interface {
SendKey(key rune, action KeyAction) error
SendSpecial(special string, action KeyAction) error
}
type expression interface {
Do(context.Context, BCDriver) error
}

View File

@ -0,0 +1,9 @@
package bootcommand
const shiftedChars = "~!@#$%^&*()_+{}|:\"<>?"
// BCDriver is our access to the VM we want to type boot commands to
type BCDriver interface {
SendKey(key rune, action KeyAction) error
SendSpecial(special string, action KeyAction) error
}

View File

@ -0,0 +1,134 @@
package bootcommand
import (
"fmt"
"log"
"strings"
"unicode"
"unicode/utf8"
)
type SendCodeFunc func([]string) error
type pcATDriver struct {
//driver Driver
//vmName string
send SendCodeFunc
specialMap map[string][]string
scancodeMap map[rune]byte
}
func NewPCATDriver(send SendCodeFunc) *pcATDriver {
// sMap contains on/off tuples
sMap := make(map[string][]string)
sMap["bs"] = []string{"0e", "8e"}
sMap["del"] = []string{"e053", "e0d3"}
sMap["enter"] = []string{"1c", "9c"}
sMap["esc"] = []string{"01", "81"}
sMap["f1"] = []string{"3b", "bb"}
sMap["f2"] = []string{"3c", "bc"}
sMap["f3"] = []string{"3d", "bd"}
sMap["f4"] = []string{"3e", "be"}
sMap["f5"] = []string{"3f", "bf"}
sMap["f6"] = []string{"40", "c0"}
sMap["f7"] = []string{"41", "c1"}
sMap["f8"] = []string{"42", "c2"}
sMap["f9"] = []string{"43", "c3"}
sMap["f10"] = []string{"44", "c4"}
sMap["f11"] = []string{"57", "d7"}
sMap["f12"] = []string{"58", "d8"}
sMap["return"] = []string{"1c", "9c"}
sMap["tab"] = []string{"0f", "8f"}
sMap["up"] = []string{"e048", "e0c8"}
sMap["down"] = []string{"e050", "e0d0"}
sMap["left"] = []string{"e04b", "e0cb"}
sMap["right"] = []string{"e04d", "e0cd"}
sMap["spacebar"] = []string{"39", "b9"}
sMap["insert"] = []string{"e052", "e0d2"}
sMap["home"] = []string{"e047", "e0c7"}
sMap["end"] = []string{"e04f", "e0cf"}
sMap["pageUp"] = []string{"e049", "e0c9"}
sMap["pageDown"] = []string{"e051", "e0d1"}
sMap["leftAlt"] = []string{"38", "b8"}
sMap["leftCtrl"] = []string{"1d", "9d"}
sMap["leftShift"] = []string{"2a", "aa"}
sMap["rightAlt"] = []string{"e038", "e0b8"}
sMap["rightCtrl"] = []string{"e01d", "e09d"}
sMap["rightShift"] = []string{"36", "b6"}
sMap["leftSuper"] = []string{"e05b", "e0db"}
sMap["rightSuper"] = []string{"e05c", "e0dc"}
scancodeIndex := make(map[string]byte)
scancodeIndex["1234567890-="] = 0x02
scancodeIndex["!@#$%^&*()_+"] = 0x02
scancodeIndex["qwertyuiop[]"] = 0x10
scancodeIndex["QWERTYUIOP{}"] = 0x10
scancodeIndex["asdfghjkl;'`"] = 0x1e
scancodeIndex[`ASDFGHJKL:"~`] = 0x1e
scancodeIndex[`\zxcvbnm,./`] = 0x2b
scancodeIndex["|ZXCVBNM<>?"] = 0x2b
scancodeIndex[" "] = 0x39
scancodeMap := make(map[rune]byte)
for chars, start := range scancodeIndex {
var i byte = 0
for len(chars) > 0 {
r, size := utf8.DecodeRuneInString(chars)
chars = chars[size:]
scancodeMap[r] = start + i
i += 1
}
}
return &pcATDriver{
send: send,
specialMap: sMap,
scancodeMap: scancodeMap,
}
}
func (d *pcATDriver) SendKey(key rune, action KeyAction) error {
keyShift := unicode.IsUpper(key) || strings.ContainsRune(shiftedChars, key)
var scancode []string
if action&(KeyOn|KeyPress) != 0 {
scancodeInt := d.scancodeMap[key]
if keyShift {
scancode = append(scancode, "2a")
}
scancode = append(scancode, fmt.Sprintf("%02x", scancodeInt))
}
if action&(KeyOff|KeyPress) != 0 {
scancodeInt := d.scancodeMap[key] + 0x80
if keyShift {
scancode = append(scancode, "aa")
}
scancode = append(scancode, fmt.Sprintf("%02x", scancodeInt))
}
for _, sc := range scancode {
log.Printf("Sending char '%c', code '%s', shift %v", key, sc, keyShift)
}
return d.send(scancode)
}
func (d *pcATDriver) SendSpecial(special string, action KeyAction) (err error) {
keyCode, ok := d.specialMap[special]
if !ok {
return fmt.Errorf("special %s not found.", special)
}
switch action {
case KeyOn:
err = d.send([]string{keyCode[0]})
case KeyOff:
err = d.send([]string{keyCode[1]})
case KeyPress:
err = d.send(keyCode)
}
return
}

View File

@ -12,9 +12,16 @@ import (
vnc "github.com/mitchellh/go-vnc"
)
const shiftedChars = "~!@#$%^&*()_+{}|:\"<>?"
const KeyLeftShift uint32 = 0xFFE1
type bcDriver struct {
c *vnc.ClientConn
interval time.Duration
specialMap map[string]uint32
// keyEvent can set this error which will prevent it from continuing
err error
}
func NewVNCDriver(c *vnc.ClientConn) *bcDriver {
// We delay (default 100ms) between each key event to allow for CPU or
// network latency. See PackerKeyEnv for tuning.
@ -69,14 +76,6 @@ func NewVNCDriver(c *vnc.ClientConn) *bcDriver {
}
}
type bcDriver struct {
c *vnc.ClientConn
interval time.Duration
specialMap map[string]uint32
// keyEvent can set this error which will prevent it from continuing
err error
}
func (d *bcDriver) keyEvent(k uint32, down bool) error {
if d.err != nil {
return nil