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 }