On Wed, May 25, 2011 at 05:37:51PM +0800, Lai Jiangshan wrote: > Signed-off-by: Lai Jiangshan <laijs@xxxxxxxxxxx> > --- > tools/virsh.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > tools/virsh.pod | 4 ++ > 2 files changed, 107 insertions(+), 0 deletions(-) > > diff --git a/tools/virsh.c b/tools/virsh.c > index 80cffac..505a821 100644 > --- a/tools/virsh.c > +++ b/tools/virsh.c > @@ -33,6 +33,8 @@ > #include <signal.h> > #include <poll.h> > > +#include <libvirt/virtkeys.h> > + > #include <libxml/parser.h> > #include <libxml/tree.h> > #include <libxml/xpath.h> > @@ -3010,6 +3012,106 @@ cmdInjectNMI(vshControl *ctl, const vshCmd *cmd) > } > > /* > + * "send-key" command > + */ > +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" > + " Examples:\n\n" > + " virsh # send-key <domain> 37 18 21\n" > + " virsh # send-key <domain> --holdtime 1000 0x15 18 0xf\n" > + {NULL, NULL} > +}; As mentioned in my earlier message, it is probably desirable for this to use key strings by default, since that is more friendly for the admin. Either have an explicit flag to enable use of key values, or perhaps can auto-detect them. > +static const vshCmdOptDef opts_send_key[] = { > + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, > + {"codeset", VSH_OT_STRING, VSH_OFLAG_REQ_OPT, N_("the codeset of keycodes, default:linux")}, > + {"holdtime", VSH_OT_INT, VSH_OFLAG_REQ_OPT, > + N_("the time (in millsecond) how long the keys will be held")}, > + {"keycode", VSH_OT_ARGV, VSH_OFLAG_REQ, N_("the key code")}, > + {NULL, 0, 0, NULL} > +}; > + > +static int get_integer_keycode(const char *key_name) > +{ > + long val; > + char *endptr; > + > + val = strtol(key_name, &endptr, 0); > + if (*endptr != '\0' || val > 255 || val <= 0) > + return -1; > + > + return val; > +} > + > +static bool > +cmdSendKey(vshControl *ctl, const vshCmd *cmd) > +{ > + virDomainPtr dom; > + int ret = false; > + const char *codeset_option; > + int codeset; > + int holdtime; > + int count = 0; > + const vshCmdOpt *opt; > + int keycode; > + unsigned int keycodes[MAX_SEND_KEY]; > + > + if (!vshConnectionUsability(ctl, ctl->conn)) > + return false; > + > + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) > + return false; > + > + if (vshCommandOptString(cmd, "codeset", &codeset_option) <= 0) > + codeset_option = "default"; > + > + if (vshCommandOptInt(cmd, "holdtime", &holdtime) <= 0) > + holdtime = 0; > + > + if (STREQ(codeset_option, "default") || STREQ(codeset_option, "linux")) { > + codeset = LIBVIRT_KEYCODE_LINUX; > + } else if (STREQ(codeset_option, "diriver_default")) { > + codeset = LIBVIRT_KEYCODE_DRIVER_DEFAULT; As mentioned, I don't think we want 'driver_default' as a use case. > + } else if (STREQ(codeset_option, "xt")) { > + codeset = LIBVIRT_KEYCODE_XT; > + } else if (STREQ(codeset_option, "atset1")) { > + codeset = LIBVIRT_KEYCODE_ATSET1; > + } else if (STREQ(codeset_option, "atset2")) { > + codeset = LIBVIRT_KEYCODE_ATSET2; > + } else if (STREQ(codeset_option, "atset3")) { > + codeset = LIBVIRT_KEYCODE_ATSET3; > + } else { > + vshError(ctl, _("unknown codeset: '%s'"), codeset_option); > + goto free_domain; > + } > + > + for_each_variable_arg(cmd, opt) { > + if (count == MAX_SEND_KEY) { > + vshError(ctl, _("too many keycode")); > + goto free_domain; > + } > + > + if ((keycode = get_integer_keycode(opt->data)) > 0) > + goto get_keycode; > + > + vshError(ctl, _("invalid keycode: '%s'"), opt->data); > + goto free_domain; > + > +get_keycode: > + keycodes[count] = keycode; > + count++; > + } > + > + if (!(virDomainSendKey(dom, codeset, holdtime, count, keycodes, 0) < 0)) > + ret = true; > + > +free_domain: > + virDomainFree(dom); > + return ret; > +} > + > +/* > * "setmemory" command > */ > static const vshCmdInfo info_setmem[] = { > @@ -10807,6 +10909,7 @@ static const vshCmdDef domManagementCmds[] = { > {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml, 0}, > {"edit", cmdEdit, opts_edit, info_edit, 0}, > {"inject-nmi", cmdInjectNMI, opts_inject_nmi, info_inject_nmi, 0}, > + {"send-key", cmdSendKey, opts_send_key, info_send_key}, > {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave, 0}, > {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, > info_managedsaveremove, 0}, > diff --git a/tools/virsh.pod b/tools/virsh.pod > index ef01f41..beef608 100644 > --- a/tools/virsh.pod > +++ b/tools/virsh.pod > @@ -294,6 +294,10 @@ scheduling by the hypervisor. > > Inject NMI to the guest > > +=item B<send-key> I<domain-id> I<--codeset> B<codeset> I<--holdtime> B<holdtime> B<keycode>... > + > +Send keys to the guest > + > =item B<shutdown> > > The domain is in the process of shutting down, i.e. the guest operating system > -- > 1.7.4.4 > -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list