github.com/mitchellh/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  }