Abstract vbox driver into PC-AT driver.
This commit is contained in:
parent
e4af71858f
commit
99d61920d0
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue