This commit adds support for virDomainSendKey. It also serves as an
example of how to use the new method invocation APIs with a single
"simple" type parameter.
---
src/hyperv/hyperv_driver.c | 85 ++++++++++++++++++++++++++++++++++
src/hyperv/hyperv_wmi.c | 7 +++
src/hyperv/hyperv_wmi.h | 3 +-
src/hyperv/hyperv_wmi_generator.input | 86 +++++++++++++++++++++++++++++++++++
4 files changed, 180 insertions(+), 1 deletion(-)
diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
index 0ca5971..9562d5a 100644
--- a/src/hyperv/hyperv_driver.c
+++ b/src/hyperv/hyperv_driver.c
@@ -35,6 +35,7 @@
#include "hyperv_wmi.h"
#include "openwsman.h"
#include "virstring.h"
+#include "virkeycode.h"
#define VIR_FROM_THIS VIR_FROM_HYPERV
@@ -1373,6 +1374,89 @@ hypervConnectListAllDomains(virConnectPtr conn,
#undef MATCH
+static int
+hypervDomainSendKey(virDomainPtr domain, unsigned int codeset,
+ unsigned int holdtime ATTRIBUTE_UNUSED, unsigned int *keycodes,
+ int nkeycodes, unsigned int flags)
+{
+ int result = -1;
+ size_t i = 0;
+ int keycode = 0;
+ int *translatedKeycodes = NULL;
+ hypervPrivate *priv = domain->conn->privateData;
+ char uuid_string[VIR_UUID_STRING_BUFLEN];
+ char *selector = NULL;
+ Msvm_ComputerSystem *computerSystem = NULL;
+ Msvm_Keyboard *keyboard = NULL;
+ virBuffer query = VIR_BUFFER_INITIALIZER;
+ hypervInvokeParamsListPtr params = NULL;
+
+ virCheckFlags(0, -1);
+
+ virUUIDFormat(domain->uuid, uuid_string);
+
+ if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0)
+ goto cleanup;
+
+ virBufferAsprintf(&query,
+ "associators of "
+ "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\","
+ "Name=\"%s\"} "
+ "where ResultClass = Msvm_Keyboard",
+ uuid_string);
+
+
+ if (hypervGetMsvmKeyboardList(priv, &query, &keyboard) < 0)
+ goto cleanup;
+
+ /* translate keycodes to xt and generate keyup scancodes. */
+ translatedKeycodes = (int *) keycodes;
+ for (i = 0; i < nkeycodes; i++) {
+ if (codeset != VIR_KEYCODE_SET_WIN32) {
+ keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_WIN32,
+ translatedKeycodes[i]);
+
+ if (keycode < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Could not translate keycode"));
+ goto cleanup;
+ }
+ translatedKeycodes[i] = keycode;
+ }
+ }
+
+ if (virAsprintf(&selector,
+ "CreationClassName=Msvm_Keyboard&DeviceID=%s&"
+ "SystemCreationClassName=Msvm_ComputerSystem&"
+ "SystemName=%s", keyboard->data.common->DeviceID, uuid_string) < 0)
+ goto cleanup;
+
+ /* type the keys */
+ for (i = 0; i < nkeycodes; i++) {
+ char keycodeStr[sizeof(int) * 3 + 2];
+ snprintf(keycodeStr, sizeof(keycodeStr), "%d", translatedKeycodes[i]);
+
+ /* params obj takes ownership of selector */
+ params = hypervInitInvokeParamsList(priv, "TypeKey", selector,
+ Msvm_Keyboard_WmiInfo);
+ if (hypervAddSimpleParam(params, "keyCode", keycodeStr) < 0)
+ goto cleanup;
+
+ if (hypervInvokeMethod(priv, params, NULL) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not press key %d"),
+ translatedKeycodes[i]);
+ goto cleanup;
+ }
+ }
+
+ result = 0;
+
+ cleanup:
+ hypervFreeObject(priv, (hypervObject *) keyboard);
+ hypervFreeObject(priv, (hypervObject *) computerSystem);
+ virBufferFreeAndReset(&query);
+ return result;
+}
static virHypervisorDriver hypervHypervisorDriver = {
@@ -1408,6 +1492,7 @@ static virHypervisorDriver hypervHypervisorDriver = {
.domainManagedSave = hypervDomainManagedSave, /* 0.9.5 */
.domainHasManagedSaveImage = hypervDomainHasManagedSaveImage, /* 0.9.5 */
.domainManagedSaveRemove = hypervDomainManagedSaveRemove, /* 0.9.5 */
+ .domainSendKey = hypervDomainSendKey, /* TODO: version */
.connectIsAlive = hypervConnectIsAlive, /* 0.9.8 */
};
diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c
index deea907..df248e0 100644
--- a/src/hyperv/hyperv_wmi.c
+++ b/src/hyperv/hyperv_wmi.c
@@ -1323,6 +1323,13 @@ hypervGetMsvmMemorySettingDataList(hypervPrivate *priv, virBufferPtr query,
(hypervObject **) list);
}
+int hypervGetMsvmKeyboardList(hypervPrivate *priv, virBufferPtr query,
+ Msvm_Keyboard **list)
+{
+ return hypervGetWmiClassList(priv, Msvm_Keyboard_WmiInfo, query,
+ (hypervObject **) list);
+}
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h
index 4196f51..740bdcb 100644
--- a/src/hyperv/hyperv_wmi.h
+++ b/src/hyperv/hyperv_wmi.h
@@ -217,7 +217,8 @@ int hypervGetMsvmProcessorSettingDataList(hypervPrivate *priv,
int hypervGetMsvmMemorySettingDataList(hypervPrivate *priv, virBufferPtr query,
Msvm_MemorySettingData **list);
-
+int hypervGetMsvmKeyboardList(hypervPrivate *priv, virBufferPtr query,
+ Msvm_Keyboard **list);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Msvm_ComputerSystem
diff --git a/src/hyperv/hyperv_wmi_generator.input b/src/hyperv/hyperv_wmi_generator.input
index d7f819e..4ccda04 100644
--- a/src/hyperv/hyperv_wmi_generator.input
+++ b/src/hyperv/hyperv_wmi_generator.input
@@ -956,3 +956,89 @@ class Msvm_VirtualHardDiskSettingData
uint32 PhysicalSectorSize
string VirtualDiskId
end
+
+class Msvm_Keyboard
+ string Caption
+ string Description
+ string ElementName
+ datetime InstallDate
+ string Name
+ uint16 OperationalStatus[]
+ string StatusDescriptions[]
+ string Status
+ uint16 HealthState
+ uint16 EnabledState
+ string OtherEnabledState
+ uint16 RequestedState
+ uint16 EnabledDefault
+ datetime TimeOfLastStateChange
+ string SystemCreationClassName
+ string SystemName
+ string CreationClassName
+ string DeviceID
+ boolean PowerManagementSupported
+ uint16 PowerManagementCapabilities[]
+ uint16 Availability
+ uint16 StatusInfo
+ uint32 LastErrorCode
+ string ErrorDescription
+ boolean ErrorCleared
+ string OtherIdentifyingInfo[]
+ uint64 PowerOnHours
+ uint64 TotalPowerOnHours
+ string IdentifyingDescriptions[]
+ uint16 AdditionalAvailability[]
+ uint64 MaxQuiesceTime
+ uint16 LocationIndicator
+ boolean IsLocked
+ string Layout
+ uint16 NumberOfFunctionKeys
+ uint16 Password
+end
+
+
+class v2/Msvm_Keyboard
+ string InstanceID
+ string Caption
+ string Description
+ string ElementName
+ datetime InstallDate
+ string Name
+ uint16 OperationalStatus[]
+ string StatusDescriptions[]
+ string Status
+ uint16 HealthState
+ uint16 CommunicationStatus
+ uint16 DetailedStatus
+ uint16 OperatingStatus
+ uint16 PrimaryStatus
+ uint16 EnabledState
+ string OtherEnabledState
+ uint16 RequestedState
+ uint16 EnabledDefault
+ datetime TimeOfLastStateChange
+ uint16 AvailableRequestedStates[]
+ uint16 TransitioningToState
+ string SystemCreationClassName
+ string SystemName
+ string CreationClassName
+ string DeviceID
+ boolean PowerManagementSupported
+ uint16 PowerManagementCapabilities[]
+ uint16 Availability
+ uint16 StatusInfo
+ uint32 LastErrorCode
+ string ErrorDescription
+ boolean ErrorCleared
+ string OtherIdentifyingInfo[]
+ uint64 PowerOnHours
+ uint64 TotalPowerOnHours
+ string IdentifyingDescriptions[]
+ uint16 AdditionalAvailability[]
+ uint64 MaxQuiesceTime
+ boolean IsLocked
+ string Layout
+ uint16 NumberOfFunctionKeys
+ uint16 Password
+ boolean UnicodeSupported
+end
--
2.9.3
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
2017-04-24 20:19 GMT+02:00 Sri Ramanujam <sramanujam@datto.com>:
> This commit adds support for virDomainSendKey. It also serves as an
> example of how to use the new method invocation APIs with a single
> "simple" type parameter.
> ---
> src/hyperv/hyperv_driver.c | 85 ++++++++++++++++++++++++++++++++++
> src/hyperv/hyperv_wmi.c | 7 +++
> src/hyperv/hyperv_wmi.h | 3 +-
> src/hyperv/hyperv_wmi_generator.input | 86 +++++++++++++++++++++++++++++++++++
> 4 files changed, 180 insertions(+), 1 deletion(-)
>
> diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
> index 0ca5971..9562d5a 100644
> --- a/src/hyperv/hyperv_driver.c
> +++ b/src/hyperv/hyperv_driver.c
> @@ -35,6 +35,7 @@
> #include "hyperv_wmi.h"
> #include "openwsman.h"
> #include "virstring.h"
> +#include "virkeycode.h"
>
> #define VIR_FROM_THIS VIR_FROM_HYPERV
>
> @@ -1373,6 +1374,89 @@ hypervConnectListAllDomains(virConnectPtr conn,
> #undef MATCH
>
>
> +static int
> +hypervDomainSendKey(virDomainPtr domain, unsigned int codeset,
> + unsigned int holdtime ATTRIBUTE_UNUSED, unsigned int *keycodes,
> + int nkeycodes, unsigned int flags)
> +{
> + int result = -1;
> + size_t i = 0;
> + int keycode = 0;
> + int *translatedKeycodes = NULL;
> + hypervPrivate *priv = domain->conn->privateData;
> + char uuid_string[VIR_UUID_STRING_BUFLEN];
> + char *selector = NULL;
> + Msvm_ComputerSystem *computerSystem = NULL;
> + Msvm_Keyboard *keyboard = NULL;
> + virBuffer query = VIR_BUFFER_INITIALIZER;
> + hypervInvokeParamsListPtr params = NULL;
> +
> + virCheckFlags(0, -1);
> +
> + virUUIDFormat(domain->uuid, uuid_string);
> +
> + if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0)
> + goto cleanup;
> +
> + virBufferAsprintf(&query,
> + "associators of "
> + "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\","
> + "Name=\"%s\"} "
> + "where ResultClass = Msvm_Keyboard",
> + uuid_string);
> +
> +
Unnecessary extra empty line.
> + if (hypervGetMsvmKeyboardList(priv, &query, &keyboard) < 0)
> + goto cleanup;
> +
> + /* translate keycodes to xt and generate keyup scancodes. */
> + translatedKeycodes = (int *) keycodes;
You cannot translate the keycodes in-place. For the VBox and QEMU
drivers this is kind of okay, because they are always behind the
remote driver. But for the Hyper-V driver this is different. You're
directly modifying user provided memory here. This is not okay, you
need to make a copy of the keycodes before translating them.
> + for (i = 0; i < nkeycodes; i++) {
> + if (codeset != VIR_KEYCODE_SET_WIN32) {
> + keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_WIN32,
> + translatedKeycodes[i]);
> +
> + if (keycode < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Could not translate keycode"));
> + goto cleanup;
> + }
> + translatedKeycodes[i] = keycode;
> + }
> + }
> +
> + if (virAsprintf(&selector,
> + "CreationClassName=Msvm_Keyboard&DeviceID=%s&"
> + "SystemCreationClassName=Msvm_ComputerSystem&"
> + "SystemName=%s", keyboard->data.common->DeviceID, uuid_string) < 0)
> + goto cleanup;
> +
> + /* type the keys */
> + for (i = 0; i < nkeycodes; i++) {
> + char keycodeStr[sizeof(int) * 3 + 2];
Use "char keycodeStr[INT_BUFSIZE_BOUND(int)];" instead.
> + snprintf(keycodeStr, sizeof(keycodeStr), "%d", translatedKeycodes[i]);
> +
> + /* params obj takes ownership of selector */
> + params = hypervInitInvokeParamsList(priv, "TypeKey", selector,
> + Msvm_Keyboard_WmiInfo);
> + if (hypervAddSimpleParam(params, "keyCode", keycodeStr) < 0)
> + goto cleanup;
> +
> + if (hypervInvokeMethod(priv, params, NULL) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not press key %d"),
> + translatedKeycodes[i]);
> + goto cleanup;
> + }
This is not correct. If virDomainSendKey is called with more than one
keycode than all those keys have to be pressed at once. This allows to
send key combination e.g. Alt+F4. But the way you invoke the TypeKey
function here will just send them one after another. Also you
currently don't handle holdtime.
I think you can make both things work by using
PressKey/Sleep/ReleaseKey instead of TypeKey. See how the VBox driver
does it:
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/vbox/vbox_common.c#l7551
--
Matthias Bolte
http://photron.blogspot.com
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
© 2016 - 2026 Red Hat, Inc.