[libvirt] [RFC PATCH 2/2] vbox: Implement virDomainSendKey

Dawid Zamirski dzamirski at datto.com
Thu Mar 19 21:43:57 UTC 2015


Since the holdtime is not supported by VBOX SDK, it's being simulated
by sleeping before sending the key-up codes. The key-up codes are
auto-generated based on XT codeset rules (adding of 0x80 to key-down)
which results in the same behavior as for QEMU implementation.
---
 src/vbox/vbox_common.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/vbox/vbox_common.h |   1 +
 2 files changed, 108 insertions(+)

diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c
index 0fb53aa..88bd226 100644
--- a/src/vbox/vbox_common.c
+++ b/src/vbox/vbox_common.c
@@ -33,6 +33,7 @@
 #include "virstring.h"
 #include "virfile.h"
 #include "virtime.h"
+#include "virkeycode.h"
 #include "snapshot_conf.h"
 #include "vbox_snapshot_conf.h"
 #include "fdstream.h"
@@ -7668,6 +7669,111 @@ vboxDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
     return ret;
 }
 
+static int
+vboxDomainSendKey(virDomainPtr dom,
+                  unsigned int codeset,
+                  unsigned int holdtime,
+                  unsigned int *keycodes,
+                  int nkeycodes,
+                  unsigned int flags)
+{
+    int ret = -1;
+    vboxGlobalData *data = dom->conn->privateData;
+    IConsole *console = NULL;
+    vboxIIDUnion iid;
+    IMachine *machine = NULL;
+    IKeyboard *keyboard = NULL;
+    PRInt32 *keyDownCodes = NULL;
+    PRInt32 *keyUpCodes = NULL;
+    PRUint32 codesStored = 0;
+    nsresult rc;
+    size_t i;
+    int keycode;
+
+    if (!data->vboxObj)
+        return ret;
+
+    virCheckFlags(0, -1);
+
+    keyDownCodes = (PRInt32 *) keycodes;
+
+    if (VIR_ALLOC_N(keyUpCodes, nkeycodes) < 0)
+        return ret;
+
+    /* translate keycodes to xt and generate keyup scancodes */
+    for (i = 0; i < nkeycodes; i++) {
+        if (codeset != VIR_KEYCODE_SET_XT) {
+            keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_XT,
+                                               keyDownCodes[i]);
+            if (keycode < 0) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("cannot translate keycode %u of %s codeset to"
+                                 " xt keycode"),
+                                 keyDownCodes[i],
+                                 virKeycodeSetTypeToString(codeset));
+                goto cleanup;
+            }
+            keyDownCodes[i] = keycode;
+        }
+
+        keyUpCodes[i] = keyDownCodes[i] + 0x80;
+    }
+
+    if (openSessionForMachine(data, dom->uuid, &iid, &machine, false) < 0)
+        goto cleanup;
+
+    rc = gVBoxAPI.UISession.OpenExisting(data, &iid, machine);
+
+    if (NS_FAILED(rc))
+        goto cleanup;
+
+    rc = gVBoxAPI.UISession.GetConsole(data->vboxSession, &console);
+
+    if (NS_FAILED(rc) || !console)
+        goto cleanup;
+
+    rc = gVBoxAPI.UIConsole.GetKeyboard(console, &keyboard);
+
+    if (NS_FAILED(rc))
+        goto cleanup;
+
+    rc = gVBoxAPI.UIKeyboard.PutScancodes(keyboard, nkeycodes, keyDownCodes,
+                                          &codesStored);
+
+    if (NS_FAILED(rc)) {
+        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                       _("Unable to send keyboard scancodes"));
+        goto cleanup;
+    }
+
+    /* since VBOX does not support holdtime, simulate it by sleeping and
+       then sending the release key scancodes */
+    if (holdtime > 0) {
+        usleep(holdtime * 1000);
+    }
+
+    rc = gVBoxAPI.UIKeyboard.PutScancodes(keyboard, nkeycodes, keyUpCodes,
+                                          &codesStored);
+
+    if (NS_FAILED(rc)) {
+        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                       _("Unable to send keyboard scan codes"));
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(keyUpCodes);
+    VBOX_RELEASE(keyboard);
+    VBOX_RELEASE(console);
+    gVBoxAPI.UISession.Close(data->vboxSession);
+    VBOX_RELEASE(machine);
+    vboxIIDUnalloc(&iid);
+
+    return ret;
+}
+
 
 /**
  * Function Tables
@@ -7742,6 +7848,7 @@ virHypervisorDriver vboxCommonDriver = {
     .nodeGetFreePages = vboxNodeGetFreePages, /* 1.2.6 */
     .nodeAllocPages = vboxNodeAllocPages, /* 1.2.9 */
     .domainHasManagedSaveImage = vboxDomainHasManagedSaveImage, /* 1.2.13 */
+    .domainSendKey = vboxDomainSendKey, /* 1.2.14 */
 };
 
 static void updateDriver(void)
diff --git a/src/vbox/vbox_common.h b/src/vbox/vbox_common.h
index d318921..ba19b1a 100644
--- a/src/vbox/vbox_common.h
+++ b/src/vbox/vbox_common.h
@@ -341,6 +341,7 @@ typedef nsISupports IHost;
 typedef nsISupports IHostNetworkInterface;
 typedef nsISupports IDHCPServer;
 typedef IMedium IHardDisk;
+typedef nsISupports IKeyboard;
 
 /* Macros for all vbox drivers. */
 
-- 
2.3.3




More information about the libvir-list mailing list