It make send-key command more friendly for user. Signed-off-by: Lai Jiangshan <laijs@xxxxxxxxxxx> --- tools/virsh.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 221 insertions(+), 3 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 3bccc08..18ef4bb 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -3017,11 +3017,24 @@ cmdInjectNMI(vshControl *ctl, const vshCmd *cmd) static const vshCmdInfo info_send_key[] = { {"help", N_("Send keycodes to the guest")}, {"desc", N_("Send keycodes to the guest, the keycodes must be integers\n" + " or the qemu-style key strings for the \"xt:keystring\" codeset\n" " or the KEY_* strings listed below for the \"linux\" codeset.\n\n" + " Available codeset:\n" + " linux the keycodes specified in \n" + " /usr/include/linux/input.h(default)\n" + " default linux codeset will be used\n" + " driver_default the hypervisor default codeset will be used\n" + " xt XT(set1) scancode of standard AT keyboards and PS/2 keyboards\n" + " atset1 set1 scancode of standard AT keyboards and PS/2 keyboards\n" + " atset2 set2 scancode of standard AT keyboards and PS/2 keyboards\n" + " atset3 set3 scancode of standard AT keyboards and PS/2 keyboards\n" + " xt:keystring XT scancode, but <keycode>... must be the qemu-style key strings\n" + "\n" " Examples:\n\n" " virsh # send-key <domain> 37 18 21\n" " virsh # send-key <domain> --holdtime 1000 0x15 18 0xf\n" - " virsh # send-eky <domain> KEY_LEFTCTRL KEY_LEFTALT KEY_F1\n" + " virsh # send-key <domain> KEY_LEFTCTRL KEY_LEFTALT KEY_F1\n" + " virsh # send-key <domain> --codeset xt:keystring alt-sysrq h\n" "\n" " KEY_XXX strings for the \"linux\" codeset:\n" #define keycode(var, value) " " #var " = " #value "\n" @@ -3062,6 +3075,178 @@ static int get_integer_keycode(const char *key_name) return val; } + +typedef struct { + int keycode; + const char *name; +} KeyDef; + +static const KeyDef key_defs[] = { + { 0x2a, "shift" }, + { 0x36, "shift_r" }, + + { 0x38, "alt" }, + { 0xb8, "alt_r" }, + { 0x64, "altgr" }, + { 0xe4, "altgr_r" }, + { 0x1d, "ctrl" }, + { 0x9d, "ctrl_r" }, + + { 0xdd, "menu" }, + + { 0x01, "esc" }, + + { 0x02, "1" }, + { 0x03, "2" }, + { 0x04, "3" }, + { 0x05, "4" }, + { 0x06, "5" }, + { 0x07, "6" }, + { 0x08, "7" }, + { 0x09, "8" }, + { 0x0a, "9" }, + { 0x0b, "0" }, + { 0x0c, "minus" }, + { 0x0d, "equal" }, + { 0x0e, "backspace" }, + + { 0x0f, "tab" }, + { 0x10, "q" }, + { 0x11, "w" }, + { 0x12, "e" }, + { 0x13, "r" }, + { 0x14, "t" }, + { 0x15, "y" }, + { 0x16, "u" }, + { 0x17, "i" }, + { 0x18, "o" }, + { 0x19, "p" }, + { 0x1a, "bracket_left" }, + { 0x1b, "bracket_right" }, + { 0x1c, "ret" }, + + { 0x1e, "a" }, + { 0x1f, "s" }, + { 0x20, "d" }, + { 0x21, "f" }, + { 0x22, "g" }, + { 0x23, "h" }, + { 0x24, "j" }, + { 0x25, "k" }, + { 0x26, "l" }, + { 0x27, "semicolon" }, + { 0x28, "apostrophe" }, + { 0x29, "grave_accent" }, + + { 0x2b, "backslash" }, + { 0x2c, "z" }, + { 0x2d, "x" }, + { 0x2e, "c" }, + { 0x2f, "v" }, + { 0x30, "b" }, + { 0x31, "n" }, + { 0x32, "m" }, + { 0x33, "comma" }, + { 0x34, "dot" }, + { 0x35, "slash" }, + + { 0x37, "asterisk" }, + + { 0x39, "spc" }, + { 0x3a, "caps_lock" }, + { 0x3b, "f1" }, + { 0x3c, "f2" }, + { 0x3d, "f3" }, + { 0x3e, "f4" }, + { 0x3f, "f5" }, + { 0x40, "f6" }, + { 0x41, "f7" }, + { 0x42, "f8" }, + { 0x43, "f9" }, + { 0x44, "f10" }, + { 0x45, "num_lock" }, + { 0x46, "scroll_lock" }, + + { 0xb5, "kp_divide" }, + { 0x37, "kp_multiply" }, + { 0x4a, "kp_subtract" }, + { 0x4e, "kp_add" }, + { 0x9c, "kp_enter" }, + { 0x53, "kp_decimal" }, + { 0x54, "sysrq" }, + + { 0x52, "kp_0" }, + { 0x4f, "kp_1" }, + { 0x50, "kp_2" }, + { 0x51, "kp_3" }, + { 0x4b, "kp_4" }, + { 0x4c, "kp_5" }, + { 0x4d, "kp_6" }, + { 0x47, "kp_7" }, + { 0x48, "kp_8" }, + { 0x49, "kp_9" }, + + { 0x56, "<" }, + + { 0x57, "f11" }, + { 0x58, "f12" }, + + { 0xb7, "print" }, + + { 0xc7, "home" }, + { 0xc9, "pgup" }, + { 0xd1, "pgdn" }, + { 0xcf, "end" }, + + { 0xcb, "left" }, + { 0xc8, "up" }, + { 0xd0, "down" }, + { 0xcd, "right" }, + + { 0xd2, "insert" }, + { 0xd3, "delete" }, + + { 0xf0, "stop" }, + { 0xf1, "again" }, + { 0xf2, "props" }, + { 0xf3, "undo" }, + { 0xf4, "front" }, + { 0xf5, "copy" }, + { 0xf6, "open" }, + { 0xf7, "paste" }, + { 0xf8, "find" }, + { 0xf9, "cut" }, + { 0xfa, "lf" }, + { 0xfb, "help" }, + { 0xfc, "meta_l" }, + { 0xfd, "meta_r" }, + { 0xfe, "compose" }, + + { 0, NULL }, +}; + +static int get_xtkeystr_keycode(const char *key_name, unsigned int keyname_len) +{ + const KeyDef *p; + char *endp; + int ret; + + if (keyname_len == 0) + return -1; + + for(p = key_defs; p->name != NULL; p++) { + if (!strncmp(key_name, p->name, keyname_len)) + return p->keycode; + } + if (key_name[0] == '0' && (key_name[1] == 'x' || key_name[1] == 'X')) { + ret = strtoul(key_name, &endp, 0); + if (endp - key_name == keyname_len && ret >= 0x01 && ret <= 0xff) + return ret; + } + return -1; +} + + static bool cmdSendKey(vshControl *ctl, const vshCmd *cmd) { @@ -3073,6 +3258,7 @@ cmdSendKey(vshControl *ctl, const vshCmd *cmd) int count = 0; const vshCmdOpt *opt; int keycode; + int xt_keystring = 0; unsigned int keycodes[MAX_SEND_KEY]; if (!vshConnectionUsability(ctl, ctl->conn)) @@ -3099,6 +3285,9 @@ cmdSendKey(vshControl *ctl, const vshCmd *cmd) codeset = LIBVIRT_KEYCODE_ATSET2; } else if (STREQ(codeset_option, "atset3")) { codeset = LIBVIRT_KEYCODE_ATSET3; + } else if (STREQ(codeset_option, "xt:keystring")) { + codeset = LIBVIRT_KEYCODE_XT; + xt_keystring = 1; } else { vshError(ctl, _("unknown codeset: '%s'"), codeset_option); goto free_domain; @@ -3106,11 +3295,40 @@ cmdSendKey(vshControl *ctl, const vshCmd *cmd) for_each_variable_arg(cmd, opt) { if (count == MAX_SEND_KEY) { - vshError(ctl, _("too many keycode")); + vshError(ctl, _("too many keycodes")); goto free_domain; } - if ((keycode = get_linux_keycode(opt->data)) > 0) + if (codeset == LIBVIRT_KEYCODE_XT && xt_keystring == 1) { + const char *sep, *key_string = opt->data; + unsigned int keyname_len; + + for (;;) { + if (count == MAX_SEND_KEY) { + vshError(ctl, _("too many keycodes")); + goto free_domain; + } + + sep = strchr(key_string, '-'); + keyname_len = sep ? sep - key_string : strlen(key_string); + + keycode = get_xtkeystr_keycode(key_string, keyname_len); + if (keycode < 0) { + vshError(ctl, _("invalid keycode: '%s'"), opt->data); + goto free_domain; + } + + keycodes[count] = keycode; + count++; + if (!sep) + break; + key_string += keyname_len + 1; + } + continue; + } + + if (codeset == LIBVIRT_KEYCODE_LINUX && + (keycode = get_linux_keycode(opt->data)) > 0) goto get_keycode; if ((keycode = get_integer_keycode(opt->data)) > 0) -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list