qemu driver just accept xt_kbd codeset's keycode, so the lib virtkey is used for translating keycodes from other codesets. Signed-off-by: Lai Jiangshan <laijs@xxxxxxxxxxxxxx> --- src/qemu/qemu_driver.c | 51 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 37 ++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.h | 6 +++++ src/qemu/qemu_monitor_json.c | 15 ++++++++++++ src/qemu/qemu_monitor_json.h | 5 ++++ src/qemu/qemu_monitor_text.c | 49 ++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 5 ++++ 7 files changed, 168 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 01587e8..994d7bd 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1761,6 +1761,56 @@ cleanup: return ret; } +static int qemuDomainSendKey(virDomainPtr domain, + unsigned int codeset, + unsigned int holdtime, + unsigned int *keycodes, + int nkeycodes, + unsigned int flags) +{ + struct qemud_driver *driver = domain->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + qemuDomainObjPrivatePtr priv; + + virCheckFlags(0, -1); + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, domain->uuid); + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(domain->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + priv = vm->privateData; + + if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + qemuDomainObjEnterMonitorWithDriver(driver, vm); + ret = qemuMonitorSendKey(priv->mon, codeset, holdtime, keycodes, nkeycodes); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (qemuDomainObjEndJob(vm) == 0) { + vm = NULL; + goto cleanup; + } + +cleanup: + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + static int qemudDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { @@ -8436,6 +8486,7 @@ static virDriver qemuDriver = { .domainMigratePerform3 = qemuDomainMigratePerform3, /* 0.9.2 */ .domainMigrateFinish3 = qemuDomainMigrateFinish3, /* 0.9.2 */ .domainMigrateConfirm3 = qemuDomainMigrateConfirm3, /* 0.9.2 */ + .domainSendKey = qemuDomainSendKey, /* 0.9.3 */ .domainBlockPull = qemuDomainBlockPull, /* 0.9.3 */ .domainBlockPullAll = qemuDomainBlockPullAll, /* 0.9.3 */ .domainBlockPullAbort = qemuDomainBlockPullAbort, /* 0.9.3 */ diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 89a3f64..e14703b 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -36,6 +36,7 @@ #include "memory.h" #include "logging.h" #include "files.h" +#include "virtkey.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -2369,6 +2370,42 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon) return ret; } +int qemuMonitorSendKey(qemuMonitorPtr mon, + unsigned int codeset, + unsigned int holdtime, + unsigned int *keycodes, + unsigned int nkeycodes) +{ + int ret; + + VIR_DEBUG("mon=%p, codeset=%s(%u), holdtime=%u, nkeycodes=%u", + mon, virKeycodeSetName(codeset), codeset, holdtime, nkeycodes); + + if (codeset != VIR_KEYCODE_SET_XT_KBD) { + int i; + int keycode; + + for (i = 0; i < nkeycodes; i++) { + keycode = virTranslateKeyCode(codeset, VIR_KEYCODE_SET_XT_KBD, + keycodes[i]); + if (keycode < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "can not translate " + "keycode %u of %s codeset to xt_kbd codeset " + "keycode", keycodes[i], + virKeycodeSetName(codeset)); + return -1; + } + keycodes[i] = keycode; + } + } + + if (mon->json) + ret = qemuMonitorJSONSendKey(mon, holdtime, keycodes, nkeycodes); + else + ret = qemuMonitorTextSendKey(mon, holdtime, keycodes, nkeycodes); + return ret; +} + int qemuMonitorScreendump(qemuMonitorPtr mon, const char *file) { diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 3bb0269..ed80c4b 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -462,6 +462,12 @@ int qemuMonitorBlockPull(qemuMonitorPtr mon, virDomainBlockPullInfoPtr info, int mode); +int qemuMonitorSendKey(qemuMonitorPtr mon, + unsigned int codeset, + unsigned int holdtime, + unsigned int *keycodes, + unsigned int nkeycodes); + /** * When running two dd process and using <> redirection, we need a * shell that will not truncate files. These two strings serve that diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 56ec65b..604f04c 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2661,6 +2661,21 @@ cleanup: return ret; } +int qemuMonitorJSONSendKey(qemuMonitorPtr mon, + unsigned int holdtime, + unsigned int *keycodes, + unsigned int nkeycodes) +{ + /* + * FIXME: qmp sendkey has not been implemented yet, + * and qmp API of it can not be anticipated, so we use hmp temporary. + */ + if (qemuMonitorCheckHMP(mon, "sendkey")) { + return qemuMonitorTextSendKey(mon, holdtime, keycodes, nkeycodes); + } else + return -1; +} + int qemuMonitorJSONScreendump(qemuMonitorPtr mon, const char *file) { diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 393d8fc..6023843 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -214,6 +214,11 @@ int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon, int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon); +int qemuMonitorJSONSendKey(qemuMonitorPtr mon, + unsigned int holdtime, + unsigned int *keycodes, + unsigned int nkeycodes); + int qemuMonitorJSONScreendump(qemuMonitorPtr mon, const char *file); diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index a16ea91..0221bf1 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -2720,6 +2720,55 @@ fail: return -1; } +int qemuMonitorTextSendKey(qemuMonitorPtr mon, + unsigned int holdtime, + unsigned int *keycodes, + unsigned int nkeycodes) +{ + int i; + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *cmd, *reply = NULL; + + if (nkeycodes > VIR_DOMAIN_SEND_KEY_MAX_KEYS || nkeycodes == 0) + return -1; + + virBufferAddLit(&buf, "sendkey "); + for (i = 0; i < nkeycodes; i++) { + if (keycodes[i] > 0xffff) { + qemuReportError(VIR_ERR_OPERATION_FAILED, + _("keycode %d is invalid: 0x%X"), + i, keycodes[i]); + virBufferFreeAndReset(&buf); + return -1; + } + + if (i) + virBufferAddChar(&buf, '-'); + virBufferAsprintf(&buf, "0x%02X", keycodes[i]); + } + + if (holdtime) + virBufferAsprintf(&buf, " %u", holdtime); + + if (virBufferError(&buf)) { + virReportOOMError(); + return -1; + } + + cmd = virBufferContentAndReset(&buf); + if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) { + qemuReportError(VIR_ERR_OPERATION_FAILED, + _("failed to send key using command '%s'"), + cmd); + VIR_FREE(cmd); + return -1; + } + + VIR_FREE(cmd); + VIR_FREE(reply); + return 0; +} + /* Returns -1 on error, -2 if not supported */ int qemuMonitorTextScreendump(qemuMonitorPtr mon, const char *file) { diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 4fa5064..5e0abcc 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -208,6 +208,11 @@ int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd, int qemuMonitorTextInjectNMI(qemuMonitorPtr mon); +int qemuMonitorTextSendKey(qemuMonitorPtr mon, + unsigned int holdtime, + unsigned int *keycodes, + unsigned int nkeycodes); + int qemuMonitorTextScreendump(qemuMonitorPtr mon, const char *file); int qemuMonitorTextBlockPull(qemuMonitorPtr mon, -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list