github.com/vmware/govmomi@v0.51.0/cli/vm/keystrokes.go (about)

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