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 }