github.com/vmware/govmomi@v0.43.0/govc/vm/keystrokes.go (about)

     1  /*
     2  Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package vm
    18  
    19  import (
    20  	"context"
    21  	"flag"
    22  	"fmt"
    23  	"sort"
    24  	"strconv"
    25  	"strings"
    26  
    27  	"github.com/vmware/govmomi/govc/cli"
    28  	"github.com/vmware/govmomi/govc/flags"
    29  	"github.com/vmware/govmomi/object"
    30  	"github.com/vmware/govmomi/vim25/types"
    31  )
    32  
    33  type hidKey struct {
    34  	Code         int32
    35  	ShiftPressed bool
    36  }
    37  
    38  // stolen from
    39  // https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2#file-usb_hid_keys-h-L110
    40  const (
    41  	KEY_MOD_LCTRL          = 0x01
    42  	KEY_MOD_LSHIFT         = 0x02
    43  	KEY_MOD_LALT           = 0x04
    44  	KEY_MOD_LMETA          = 0x08
    45  	KEY_MOD_RCTRL          = 0x10
    46  	KEY_MOD_RSHIFT         = 0x20
    47  	KEY_MOD_RALT           = 0x40
    48  	KEY_MOD_RMETA          = 0x80
    49  	KEY_NONE               = 0x00
    50  	KEY_ERR_OVF            = 0x01
    51  	KEY_A                  = 0x04
    52  	KEY_B                  = 0x05
    53  	KEY_C                  = 0x06
    54  	KEY_D                  = 0x07
    55  	KEY_E                  = 0x08
    56  	KEY_F                  = 0x09
    57  	KEY_G                  = 0x0a
    58  	KEY_H                  = 0x0b
    59  	KEY_I                  = 0x0c
    60  	KEY_J                  = 0x0d
    61  	KEY_K                  = 0x0e
    62  	KEY_L                  = 0x0f
    63  	KEY_M                  = 0x10
    64  	KEY_N                  = 0x11
    65  	KEY_O                  = 0x12
    66  	KEY_P                  = 0x13
    67  	KEY_Q                  = 0x14
    68  	KEY_R                  = 0x15
    69  	KEY_S                  = 0x16
    70  	KEY_T                  = 0x17
    71  	KEY_U                  = 0x18
    72  	KEY_V                  = 0x19
    73  	KEY_W                  = 0x1a
    74  	KEY_X                  = 0x1b
    75  	KEY_Y                  = 0x1c
    76  	KEY_Z                  = 0x1d
    77  	KEY_1                  = 0x1e
    78  	KEY_2                  = 0x1f
    79  	KEY_3                  = 0x20
    80  	KEY_4                  = 0x21
    81  	KEY_5                  = 0x22
    82  	KEY_6                  = 0x23
    83  	KEY_7                  = 0x24
    84  	KEY_8                  = 0x25
    85  	KEY_9                  = 0x26
    86  	KEY_0                  = 0x27
    87  	KEY_ENTER              = 0x28
    88  	KEY_ESC                = 0x29
    89  	KEY_BACKSPACE          = 0x2a
    90  	KEY_TAB                = 0x2b
    91  	KEY_SPACE              = 0x2c
    92  	KEY_MINUS              = 0x2d
    93  	KEY_EQUAL              = 0x2e
    94  	KEY_LEFTBRACE          = 0x2f
    95  	KEY_RIGHTBRACE         = 0x30
    96  	KEY_BACKSLASH          = 0x31
    97  	KEY_HASHTILDE          = 0x32
    98  	KEY_SEMICOLON          = 0x33
    99  	KEY_APOSTROPHE         = 0x34
   100  	KEY_GRAVE              = 0x35
   101  	KEY_COMMA              = 0x36
   102  	KEY_DOT                = 0x37
   103  	KEY_SLASH              = 0x38
   104  	KEY_CAPSLOCK           = 0x39
   105  	KEY_F1                 = 0x3a
   106  	KEY_F2                 = 0x3b
   107  	KEY_F3                 = 0x3c
   108  	KEY_F4                 = 0x3d
   109  	KEY_F5                 = 0x3e
   110  	KEY_F6                 = 0x3f
   111  	KEY_F7                 = 0x40
   112  	KEY_F8                 = 0x41
   113  	KEY_F9                 = 0x42
   114  	KEY_F10                = 0x43
   115  	KEY_F11                = 0x44
   116  	KEY_F12                = 0x45
   117  	KEY_SYSRQ              = 0x46
   118  	KEY_SCROLLLOCK         = 0x47
   119  	KEY_PAUSE              = 0x48
   120  	KEY_INSERT             = 0x49
   121  	KEY_HOME               = 0x4a
   122  	KEY_PAGEUP             = 0x4b
   123  	KEY_DELETE             = 0x4c
   124  	KEY_END                = 0x4d
   125  	KEY_PAGEDOWN           = 0x4e
   126  	KEY_RIGHT              = 0x4f
   127  	KEY_LEFT               = 0x50
   128  	KEY_DOWN               = 0x51
   129  	KEY_UP                 = 0x52
   130  	KEY_NUMLOCK            = 0x53
   131  	KEY_KPSLASH            = 0x54
   132  	KEY_KPASTERISK         = 0x55
   133  	KEY_KPMINUS            = 0x56
   134  	KEY_KPPLUS             = 0x57
   135  	KEY_KPENTER            = 0x58
   136  	KEY_KP1                = 0x59
   137  	KEY_KP2                = 0x5a
   138  	KEY_KP3                = 0x5b
   139  	KEY_KP4                = 0x5c
   140  	KEY_KP5                = 0x5d
   141  	KEY_KP6                = 0x5e
   142  	KEY_KP7                = 0x5f
   143  	KEY_KP8                = 0x60
   144  	KEY_KP9                = 0x61
   145  	KEY_KP0                = 0x62
   146  	KEY_KPDOT              = 0x63
   147  	KEY_102ND              = 0x64
   148  	KEY_COMPOSE            = 0x65
   149  	KEY_POWER              = 0x66
   150  	KEY_KPEQUAL            = 0x67
   151  	KEY_F13                = 0x68
   152  	KEY_F14                = 0x69
   153  	KEY_F15                = 0x6a
   154  	KEY_F16                = 0x6b
   155  	KEY_F17                = 0x6c
   156  	KEY_F18                = 0x6d
   157  	KEY_F19                = 0x6e
   158  	KEY_F20                = 0x6f
   159  	KEY_F21                = 0x70
   160  	KEY_F22                = 0x71
   161  	KEY_F23                = 0x72
   162  	KEY_F24                = 0x73
   163  	KEY_OPEN               = 0x74
   164  	KEY_HELP               = 0x75
   165  	KEY_PROPS              = 0x76
   166  	KEY_FRONT              = 0x77
   167  	KEY_STOP               = 0x78
   168  	KEY_AGAIN              = 0x79
   169  	KEY_UNDO               = 0x7a
   170  	KEY_CUT                = 0x7b
   171  	KEY_COPY               = 0x7c
   172  	KEY_PASTE              = 0x7d
   173  	KEY_FIND               = 0x7e
   174  	KEY_MUTE               = 0x7f
   175  	KEY_VOLUMEUP           = 0x80
   176  	KEY_VOLUMEDOWN         = 0x81
   177  	KEY_KPCOMMA            = 0x85
   178  	KEY_RO                 = 0x87
   179  	KEY_KATAKANAHIRAGANA   = 0x88
   180  	KEY_YEN                = 0x89
   181  	KEY_HENKAN             = 0x8a
   182  	KEY_MUHENKAN           = 0x8b
   183  	KEY_KPJPCOMMA          = 0x8c
   184  	KEY_HANGEUL            = 0x90
   185  	KEY_HANJA              = 0x91
   186  	KEY_KATAKANA           = 0x92
   187  	KEY_HIRAGANA           = 0x93
   188  	KEY_ZENKAKUHANKAKU     = 0x94
   189  	KEY_KPLEFTPAREN        = 0xb6
   190  	KEY_KPRIGHTPAREN       = 0xb7
   191  	KEY_LEFTCTRL           = 0xe0
   192  	KEY_LEFTSHIFT          = 0xe1
   193  	KEY_LEFTALT            = 0xe2
   194  	KEY_LEFTMETA           = 0xe3
   195  	KEY_RIGHTCTRL          = 0xe4
   196  	KEY_RIGHTSHIFT         = 0xe5
   197  	KEY_RIGHTALT           = 0xe6
   198  	KEY_RIGHTMETA          = 0xe7
   199  	KEY_MEDIA_PLAYPAUSE    = 0xe8
   200  	KEY_MEDIA_STOPCD       = 0xe9
   201  	KEY_MEDIA_PREVIOUSSONG = 0xea
   202  	KEY_MEDIA_NEXTSONG     = 0xeb
   203  	KEY_MEDIA_EJECTCD      = 0xec
   204  	KEY_MEDIA_VOLUMEUP     = 0xed
   205  	KEY_MEDIA_VOLUMEDOWN   = 0xee
   206  	KEY_MEDIA_MUTE         = 0xef
   207  	KEY_MEDIA_WWW          = 0xf0
   208  	KEY_MEDIA_BACK         = 0xf1
   209  	KEY_MEDIA_FORWARD      = 0xf2
   210  	KEY_MEDIA_STOP         = 0xf3
   211  	KEY_MEDIA_FIND         = 0xf4
   212  	KEY_MEDIA_SCROLLUP     = 0xf5
   213  	KEY_MEDIA_SCROLLDOWN   = 0xf6
   214  	KEY_MEDIA_EDIT         = 0xf7
   215  	KEY_MEDIA_SLEEP        = 0xf8
   216  	KEY_MEDIA_COFFEE       = 0xf9
   217  	KEY_MEDIA_REFRESH      = 0xfa
   218  	KEY_MEDIA_CALC         = 0xfb
   219  )
   220  
   221  var hidKeyMap = map[string]int32{
   222  	"KEY_MOD_LCTRL":          KEY_MOD_LCTRL,
   223  	"KEY_MOD_LSHIFT":         KEY_MOD_LSHIFT,
   224  	"KEY_MOD_LALT":           KEY_MOD_LALT,
   225  	"KEY_MOD_LMETA":          KEY_MOD_LMETA,
   226  	"KEY_MOD_RCTRL":          KEY_MOD_RCTRL,
   227  	"KEY_MOD_RSHIFT":         KEY_MOD_RSHIFT,
   228  	"KEY_MOD_RALT":           KEY_MOD_RALT,
   229  	"KEY_MOD_RMETA":          KEY_MOD_RMETA,
   230  	"KEY_NONE":               KEY_NONE,
   231  	"KEY_ERR_OVF":            KEY_ERR_OVF,
   232  	"KEY_A":                  KEY_A,
   233  	"KEY_B":                  KEY_B,
   234  	"KEY_C":                  KEY_C,
   235  	"KEY_D":                  KEY_D,
   236  	"KEY_E":                  KEY_E,
   237  	"KEY_F":                  KEY_F,
   238  	"KEY_G":                  KEY_G,
   239  	"KEY_H":                  KEY_H,
   240  	"KEY_I":                  KEY_I,
   241  	"KEY_J":                  KEY_J,
   242  	"KEY_K":                  KEY_K,
   243  	"KEY_L":                  KEY_L,
   244  	"KEY_M":                  KEY_M,
   245  	"KEY_N":                  KEY_N,
   246  	"KEY_O":                  KEY_O,
   247  	"KEY_P":                  KEY_P,
   248  	"KEY_Q":                  KEY_Q,
   249  	"KEY_R":                  KEY_R,
   250  	"KEY_S":                  KEY_S,
   251  	"KEY_T":                  KEY_T,
   252  	"KEY_U":                  KEY_U,
   253  	"KEY_V":                  KEY_V,
   254  	"KEY_W":                  KEY_W,
   255  	"KEY_X":                  KEY_X,
   256  	"KEY_Y":                  KEY_Y,
   257  	"KEY_Z":                  KEY_Z,
   258  	"KEY_1":                  KEY_1,
   259  	"KEY_2":                  KEY_2,
   260  	"KEY_3":                  KEY_3,
   261  	"KEY_4":                  KEY_4,
   262  	"KEY_5":                  KEY_5,
   263  	"KEY_6":                  KEY_6,
   264  	"KEY_7":                  KEY_7,
   265  	"KEY_8":                  KEY_8,
   266  	"KEY_9":                  KEY_9,
   267  	"KEY_0":                  KEY_0,
   268  	"KEY_ENTER":              KEY_ENTER,
   269  	"KEY_ESC":                KEY_ESC,
   270  	"KEY_BACKSPACE":          KEY_BACKSPACE,
   271  	"KEY_TAB":                KEY_TAB,
   272  	"KEY_SPACE":              KEY_SPACE,
   273  	"KEY_MINUS":              KEY_MINUS,
   274  	"KEY_EQUAL":              KEY_EQUAL,
   275  	"KEY_LEFTBRACE":          KEY_LEFTBRACE,
   276  	"KEY_RIGHTBRACE":         KEY_RIGHTBRACE,
   277  	"KEY_BACKSLASH":          KEY_BACKSLASH,
   278  	"KEY_HASHTILDE":          KEY_HASHTILDE,
   279  	"KEY_SEMICOLON":          KEY_SEMICOLON,
   280  	"KEY_APOSTROPHE":         KEY_APOSTROPHE,
   281  	"KEY_GRAVE":              KEY_GRAVE,
   282  	"KEY_COMMA":              KEY_COMMA,
   283  	"KEY_DOT":                KEY_DOT,
   284  	"KEY_SLASH":              KEY_SLASH,
   285  	"KEY_CAPSLOCK":           KEY_CAPSLOCK,
   286  	"KEY_F1":                 KEY_F1,
   287  	"KEY_F2":                 KEY_F2,
   288  	"KEY_F3":                 KEY_F3,
   289  	"KEY_F4":                 KEY_F4,
   290  	"KEY_F5":                 KEY_F5,
   291  	"KEY_F6":                 KEY_F6,
   292  	"KEY_F7":                 KEY_F7,
   293  	"KEY_F8":                 KEY_F8,
   294  	"KEY_F9":                 KEY_F9,
   295  	"KEY_F10":                KEY_F10,
   296  	"KEY_F11":                KEY_F11,
   297  	"KEY_F12":                KEY_F12,
   298  	"KEY_SYSRQ":              KEY_SYSRQ,
   299  	"KEY_SCROLLLOCK":         KEY_SCROLLLOCK,
   300  	"KEY_PAUSE":              KEY_PAUSE,
   301  	"KEY_INSERT":             KEY_INSERT,
   302  	"KEY_HOME":               KEY_HOME,
   303  	"KEY_PAGEUP":             KEY_PAGEUP,
   304  	"KEY_DELETE":             KEY_DELETE,
   305  	"KEY_END":                KEY_END,
   306  	"KEY_PAGEDOWN":           KEY_PAGEDOWN,
   307  	"KEY_RIGHT":              KEY_RIGHT,
   308  	"KEY_LEFT":               KEY_LEFT,
   309  	"KEY_DOWN":               KEY_DOWN,
   310  	"KEY_UP":                 KEY_UP,
   311  	"KEY_NUMLOCK":            KEY_NUMLOCK,
   312  	"KEY_KPSLASH":            KEY_KPSLASH,
   313  	"KEY_KPASTERISK":         KEY_KPASTERISK,
   314  	"KEY_KPMINUS":            KEY_KPMINUS,
   315  	"KEY_KPPLUS":             KEY_KPPLUS,
   316  	"KEY_KPENTER":            KEY_KPENTER,
   317  	"KEY_KP1":                KEY_KP1,
   318  	"KEY_KP2":                KEY_KP2,
   319  	"KEY_KP3":                KEY_KP3,
   320  	"KEY_KP4":                KEY_KP4,
   321  	"KEY_KP5":                KEY_KP5,
   322  	"KEY_KP6":                KEY_KP6,
   323  	"KEY_KP7":                KEY_KP7,
   324  	"KEY_KP8":                KEY_KP8,
   325  	"KEY_KP9":                KEY_KP9,
   326  	"KEY_KP0":                KEY_KP0,
   327  	"KEY_KPDOT":              KEY_KPDOT,
   328  	"KEY_102ND":              KEY_102ND,
   329  	"KEY_COMPOSE":            KEY_COMPOSE,
   330  	"KEY_POWER":              KEY_POWER,
   331  	"KEY_KPEQUAL":            KEY_KPEQUAL,
   332  	"KEY_F13":                KEY_F13,
   333  	"KEY_F14":                KEY_F14,
   334  	"KEY_F15":                KEY_F15,
   335  	"KEY_F16":                KEY_F16,
   336  	"KEY_F17":                KEY_F17,
   337  	"KEY_F18":                KEY_F18,
   338  	"KEY_F19":                KEY_F19,
   339  	"KEY_F20":                KEY_F20,
   340  	"KEY_F21":                KEY_F21,
   341  	"KEY_F22":                KEY_F22,
   342  	"KEY_F23":                KEY_F23,
   343  	"KEY_F24":                KEY_F24,
   344  	"KEY_OPEN":               KEY_OPEN,
   345  	"KEY_HELP":               KEY_HELP,
   346  	"KEY_PROPS":              KEY_PROPS,
   347  	"KEY_FRONT":              KEY_FRONT,
   348  	"KEY_STOP":               KEY_STOP,
   349  	"KEY_AGAIN":              KEY_AGAIN,
   350  	"KEY_UNDO":               KEY_UNDO,
   351  	"KEY_CUT":                KEY_CUT,
   352  	"KEY_COPY":               KEY_COPY,
   353  	"KEY_PASTE":              KEY_PASTE,
   354  	"KEY_FIND":               KEY_FIND,
   355  	"KEY_MUTE":               KEY_MUTE,
   356  	"KEY_VOLUMEUP":           KEY_VOLUMEUP,
   357  	"KEY_VOLUMEDOWN":         KEY_VOLUMEDOWN,
   358  	"KEY_KPCOMMA":            KEY_KPCOMMA,
   359  	"KEY_RO":                 KEY_RO,
   360  	"KEY_KATAKANAHIRAGANA":   KEY_KATAKANAHIRAGANA,
   361  	"KEY_YEN":                KEY_YEN,
   362  	"KEY_HENKAN":             KEY_HENKAN,
   363  	"KEY_MUHENKAN":           KEY_MUHENKAN,
   364  	"KEY_KPJPCOMMA":          KEY_KPJPCOMMA,
   365  	"KEY_HANGEUL":            KEY_HANGEUL,
   366  	"KEY_HANJA":              KEY_HANJA,
   367  	"KEY_KATAKANA":           KEY_KATAKANA,
   368  	"KEY_HIRAGANA":           KEY_HIRAGANA,
   369  	"KEY_ZENKAKUHANKAKU":     KEY_ZENKAKUHANKAKU,
   370  	"KEY_KPLEFTPAREN":        KEY_KPLEFTPAREN,
   371  	"KEY_KPRIGHTPAREN":       KEY_KPRIGHTPAREN,
   372  	"KEY_LEFTCTRL":           KEY_LEFTCTRL,
   373  	"KEY_LEFTSHIFT":          KEY_LEFTSHIFT,
   374  	"KEY_LEFTALT":            KEY_LEFTALT,
   375  	"KEY_LEFTMETA":           KEY_LEFTMETA,
   376  	"KEY_RIGHTCTRL":          KEY_RIGHTCTRL,
   377  	"KEY_RIGHTSHIFT":         KEY_RIGHTSHIFT,
   378  	"KEY_RIGHTALT":           KEY_RIGHTALT,
   379  	"KEY_RIGHTMETA":          KEY_RIGHTMETA,
   380  	"KEY_MEDIA_PLAYPAUSE":    KEY_MEDIA_PLAYPAUSE,
   381  	"KEY_MEDIA_STOPCD":       KEY_MEDIA_STOPCD,
   382  	"KEY_MEDIA_PREVIOUSSONG": KEY_MEDIA_PREVIOUSSONG,
   383  	"KEY_MEDIA_NEXTSONG":     KEY_MEDIA_NEXTSONG,
   384  	"KEY_MEDIA_EJECTCD":      KEY_MEDIA_EJECTCD,
   385  	"KEY_MEDIA_VOLUMEUP":     KEY_MEDIA_VOLUMEUP,
   386  	"KEY_MEDIA_VOLUMEDOWN":   KEY_MEDIA_VOLUMEDOWN,
   387  	"KEY_MEDIA_MUTE":         KEY_MEDIA_MUTE,
   388  	"KEY_MEDIA_WWW":          KEY_MEDIA_WWW,
   389  	"KEY_MEDIA_BACK":         KEY_MEDIA_BACK,
   390  	"KEY_MEDIA_FORWARD":      KEY_MEDIA_FORWARD,
   391  	"KEY_MEDIA_STOP":         KEY_MEDIA_STOP,
   392  	"KEY_MEDIA_FIND":         KEY_MEDIA_FIND,
   393  	"KEY_MEDIA_SCROLLUP":     KEY_MEDIA_SCROLLUP,
   394  	"KEY_MEDIA_SCROLLDOWN":   KEY_MEDIA_SCROLLDOWN,
   395  	"KEY_MEDIA_EDIT":         KEY_MEDIA_EDIT,
   396  	"KEY_MEDIA_SLEEP":        KEY_MEDIA_SLEEP,
   397  	"KEY_MEDIA_COFFEE":       KEY_MEDIA_COFFEE,
   398  	"KEY_MEDIA_REFRESH":      KEY_MEDIA_REFRESH,
   399  	"KEY_MEDIA_CALC":         KEY_MEDIA_CALC,
   400  }
   401  
   402  var hidCharacterMap = map[string]hidKey{
   403  	"a": {KEY_A, false},
   404  	"b": {KEY_B, false},
   405  	"c": {KEY_C, false},
   406  	"d": {KEY_D, false},
   407  	"e": {KEY_E, false},
   408  	"f": {KEY_F, false},
   409  	"g": {KEY_G, false},
   410  	"h": {KEY_H, false},
   411  	"i": {KEY_I, false},
   412  	"j": {KEY_J, false},
   413  	"k": {KEY_K, false},
   414  	"l": {KEY_L, false},
   415  	"m": {KEY_M, false},
   416  	"n": {KEY_N, false},
   417  	"o": {KEY_O, false},
   418  	"p": {KEY_P, false},
   419  	"q": {KEY_Q, false},
   420  	"r": {KEY_R, false},
   421  	"s": {KEY_S, false},
   422  	"t": {KEY_T, false},
   423  	"u": {KEY_U, false},
   424  	"v": {KEY_V, false},
   425  	"w": {KEY_W, false},
   426  	"x": {KEY_X, false},
   427  	"y": {KEY_Y, false},
   428  	"z": {KEY_Z, false},
   429  	"1": {KEY_1, false},
   430  	"2": {KEY_2, false},
   431  	"3": {KEY_3, false},
   432  	"4": {KEY_4, false},
   433  	"5": {KEY_5, false},
   434  	"6": {KEY_6, false},
   435  	"7": {KEY_7, false},
   436  	"8": {KEY_8, false},
   437  	"9": {KEY_9, false},
   438  	"0": {KEY_0, false},
   439  	"A": {KEY_A, true},
   440  	"B": {KEY_B, true},
   441  	"C": {KEY_C, true},
   442  	"D": {KEY_D, true},
   443  	"E": {KEY_E, true},
   444  	"F": {KEY_F, true},
   445  	"G": {KEY_G, true},
   446  	"H": {KEY_H, true},
   447  	"I": {KEY_I, true},
   448  	"J": {KEY_J, true},
   449  	"K": {KEY_K, true},
   450  	"L": {KEY_L, true},
   451  	"M": {KEY_M, true},
   452  	"N": {KEY_N, true},
   453  	"O": {KEY_O, true},
   454  	"P": {KEY_P, true},
   455  	"Q": {KEY_Q, true},
   456  	"R": {KEY_R, true},
   457  	"S": {KEY_S, true},
   458  	"T": {KEY_T, true},
   459  	"U": {KEY_U, true},
   460  	"V": {KEY_V, true},
   461  	"W": {KEY_W, true},
   462  	"X": {KEY_X, true},
   463  	"Y": {KEY_Y, true},
   464  	"Z": {KEY_Z, true},
   465  	"!": {KEY_1, true},
   466  	"@": {KEY_2, true},
   467  	"#": {KEY_3, true},
   468  	"$": {KEY_4, true},
   469  	"%": {KEY_5, true},
   470  	"^": {KEY_6, true},
   471  	"&": {KEY_7, true},
   472  	"*": {KEY_8, true},
   473  	"(": {KEY_9, true},
   474  	")": {KEY_0, true},
   475  	" ": {KEY_SPACE, false},
   476  	"-": {KEY_MINUS, false},
   477  	"_": {KEY_MINUS, true},
   478  	"=": {KEY_EQUAL, false},
   479  	"+": {KEY_EQUAL, true},
   480  	"[": {KEY_LEFTBRACE, false},
   481  	"{": {KEY_LEFTBRACE, true},
   482  	"]": {KEY_RIGHTBRACE, false},
   483  	"}": {KEY_RIGHTBRACE, true},
   484  	`\`: {KEY_BACKSLASH, false},
   485  	"|": {KEY_BACKSLASH, true},
   486  	";": {KEY_SEMICOLON, false},
   487  	":": {KEY_SEMICOLON, true},
   488  	"'": {KEY_APOSTROPHE, false},
   489  	`"`: {KEY_APOSTROPHE, true},
   490  	"`": {KEY_GRAVE, false},
   491  	"~": {KEY_GRAVE, true},
   492  	",": {KEY_COMMA, false},
   493  	"<": {KEY_COMMA, true},
   494  	".": {KEY_DOT, false},
   495  	">": {KEY_DOT, true},
   496  	"/": {KEY_SLASH, false},
   497  	"?": {KEY_SLASH, true},
   498  }
   499  
   500  type keystrokes struct {
   501  	*flags.VirtualMachineFlag
   502  
   503  	UsbHidCodeValue int32
   504  	UsbHidCodes     string
   505  	UsbHidString    string
   506  	LeftControl     bool
   507  	LeftShift       bool
   508  	LeftAlt         bool
   509  	LeftGui         bool
   510  	RightControl    bool
   511  	RightShift      bool
   512  	RightAlt        bool
   513  	RightGui        bool
   514  }
   515  
   516  func init() {
   517  	cli.Register("vm.keystrokes", &keystrokes{})
   518  }
   519  
   520  func (cmd *keystrokes) Register(ctx context.Context, f *flag.FlagSet) {
   521  	cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
   522  	cmd.VirtualMachineFlag.Register(ctx, f)
   523  
   524  	f.StringVar(&cmd.UsbHidString, "s", "", "Raw String to Send")
   525  	f.StringVar(&cmd.UsbHidCodes, "c", "", "USB HID Codes (hex) or aliases, comma separated")
   526  	f.Var(flags.NewInt32(&cmd.UsbHidCodeValue), "r", "Raw USB HID Code Value (int32)")
   527  	f.BoolVar(&cmd.LeftControl, "lc", false, "Enable/Disable Left Control")
   528  	f.BoolVar(&cmd.LeftShift, "ls", false, "Enable/Disable Left Shift")
   529  	f.BoolVar(&cmd.LeftAlt, "la", false, "Enable/Disable Left Alt")
   530  	f.BoolVar(&cmd.LeftGui, "lg", false, "Enable/Disable Left Gui")
   531  	f.BoolVar(&cmd.RightControl, "rc", false, "Enable/Disable Right Control")
   532  	f.BoolVar(&cmd.RightShift, "rs", false, "Enable/Disable Right Shift")
   533  	f.BoolVar(&cmd.RightAlt, "ra", false, "Enable/Disable Right Alt")
   534  	f.BoolVar(&cmd.RightGui, "rg", false, "Enable/Disable Right Gui")
   535  }
   536  
   537  func (cmd *keystrokes) Usage() string {
   538  	return "VM"
   539  }
   540  
   541  func (cmd *keystrokes) Description() string {
   542  	description := `Send Keystrokes to VM.
   543  
   544  Examples:
   545   Default Scenario
   546    govc vm.keystrokes -vm $vm -s "root" 	# writes 'root' to the console
   547    govc vm.keystrokes -vm $vm -c 0x15 	# writes an 'r' to the console
   548    govc vm.keystrokes -vm $vm -r 1376263 # writes an 'r' to the console
   549    govc vm.keystrokes -vm $vm -c 0x28 	# presses ENTER on the console
   550    govc vm.keystrokes -vm $vm -c 0x4c -la=true -lc=true 	# sends CTRL+ALT+DEL to console
   551    govc vm.keystrokes -vm $vm -c 0x15,KEY_ENTER # writes an 'r' to the console and press ENTER
   552  
   553  List of available aliases:
   554  `
   555  	keys := make([]string, 0)
   556  	for key, _ := range hidKeyMap {
   557  		keys = append(keys, key)
   558  	}
   559  	sort.Strings(keys)
   560  	for i, key := range keys {
   561  		if i > 0 {
   562  			description += ", "
   563  		}
   564  		description += key
   565  	}
   566  	return description + "\n"
   567  }
   568  
   569  func (cmd *keystrokes) Process(ctx context.Context) error {
   570  	if err := cmd.VirtualMachineFlag.Process(ctx); err != nil {
   571  		return err
   572  	}
   573  	return nil
   574  }
   575  
   576  func (cmd *keystrokes) Run(ctx context.Context, f *flag.FlagSet) error {
   577  	vm, err := cmd.VirtualMachine()
   578  	if err != nil {
   579  		return err
   580  	}
   581  
   582  	if vm == nil {
   583  		return flag.ErrHelp
   584  	}
   585  
   586  	err = cmd.processUserInput(ctx, vm)
   587  	if err != nil {
   588  		return err
   589  	}
   590  	return nil
   591  }
   592  
   593  func (cmd *keystrokes) processUserInput(ctx context.Context, vm *object.VirtualMachine) error {
   594  	if err := cmd.checkValidInputs(); err != nil {
   595  		return err
   596  	}
   597  
   598  	codes, err := cmd.processUsbCode()
   599  
   600  	if err != nil {
   601  		return err
   602  	}
   603  
   604  	var keyEventArray []types.UsbScanCodeSpecKeyEvent
   605  	for _, code := range codes {
   606  		leftShiftSetting := false
   607  		if code.ShiftPressed || cmd.LeftShift {
   608  			leftShiftSetting = true
   609  		}
   610  		modifiers := types.UsbScanCodeSpecModifierType{
   611  			LeftControl:  &cmd.LeftControl,
   612  			LeftShift:    &leftShiftSetting,
   613  			LeftAlt:      &cmd.LeftAlt,
   614  			LeftGui:      &cmd.LeftGui,
   615  			RightControl: &cmd.RightControl,
   616  			RightShift:   &cmd.RightShift,
   617  			RightAlt:     &cmd.RightAlt,
   618  			RightGui:     &cmd.RightGui,
   619  		}
   620  		keyEvent := types.UsbScanCodeSpecKeyEvent{
   621  			UsbHidCode: code.Code,
   622  			Modifiers:  &modifiers,
   623  		}
   624  		keyEventArray = append(keyEventArray, keyEvent)
   625  	}
   626  
   627  	spec := types.UsbScanCodeSpec{
   628  		KeyEvents: keyEventArray,
   629  	}
   630  
   631  	_, err = vm.PutUsbScanCodes(ctx, spec)
   632  
   633  	return err
   634  }
   635  
   636  func (cmd *keystrokes) processUsbCode() ([]hidKey, error) {
   637  	if cmd.rawCodeProvided() {
   638  		return []hidKey{{cmd.UsbHidCodeValue, false}}, nil
   639  	}
   640  
   641  	if cmd.hexCodeProvided() {
   642  		var retKeyArray []hidKey
   643  		for _, c := range strings.Split(cmd.UsbHidCodes, ",") {
   644  			var s int32
   645  			lookupvalue, ok := hidKeyMap[c]
   646  			if ok {
   647  				s = intToHidCode(lookupvalue)
   648  			} else {
   649  				var err error
   650  				s, err = hexStringToHidCode(c)
   651  				if err != nil {
   652  					return nil, err
   653  				}
   654  			}
   655  			retKeyArray = append(retKeyArray, hidKey{s, false})
   656  		}
   657  		return retKeyArray, nil
   658  	}
   659  
   660  	if cmd.stringProvided() {
   661  		var retKeyArray []hidKey
   662  		for _, c := range cmd.UsbHidString {
   663  			lookupValue, ok := hidCharacterMap[string(c)]
   664  			if !ok {
   665  				return nil, fmt.Errorf("invalid Character %s in String: %s", string(c), cmd.UsbHidString)
   666  			}
   667  			lookupValue.Code = intToHidCode(lookupValue.Code)
   668  			retKeyArray = append(retKeyArray, lookupValue)
   669  		}
   670  		return retKeyArray, nil
   671  	}
   672  	return nil, nil
   673  }
   674  
   675  func hexStringToHidCode(hex string) (int32, error) {
   676  	s, err := strconv.ParseInt(hex, 0, 32)
   677  	if err != nil {
   678  		return 0, err
   679  	}
   680  	return intToHidCode(int32(s)), nil
   681  }
   682  
   683  func intToHidCode(v int32) int32 {
   684  	var s int32 = v << 16
   685  	s |= 7
   686  	return s
   687  }
   688  
   689  func (cmd *keystrokes) checkValidInputs() error {
   690  	// poor man's boolean XOR -> A xor B xor C = A'BC' + AB'C' + A'B'C + ABC
   691  	if (!cmd.rawCodeProvided() && cmd.hexCodeProvided() && !cmd.stringProvided()) || // A'BC'
   692  		(cmd.rawCodeProvided() && !cmd.hexCodeProvided() && !cmd.stringProvided()) || // AB'C'
   693  		(!cmd.rawCodeProvided() && !cmd.hexCodeProvided() && cmd.stringProvided()) || // A'B'C
   694  		(cmd.rawCodeProvided() && cmd.hexCodeProvided() && cmd.stringProvided()) { // ABC
   695  		return nil
   696  	}
   697  	return fmt.Errorf("specify only 1 argument")
   698  }
   699  
   700  func (cmd keystrokes) rawCodeProvided() bool {
   701  	return cmd.UsbHidCodeValue != 0
   702  }
   703  
   704  func (cmd keystrokes) hexCodeProvided() bool {
   705  	return cmd.UsbHidCodes != ""
   706  }
   707  
   708  func (cmd keystrokes) stringProvided() bool {
   709  	return cmd.UsbHidString != ""
   710  }