summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorvboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2022-12-13 13:06:03 +0000
committervboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2022-12-13 13:06:03 +0000
commit052943bd62b6a951b825f5558a295815438d68b2 (patch)
tree927c3556146a65abfee80b6f8243aecd0adb6cc5 /src
parent6d66ccb28908fac4d88bd73cefb01892ab7b026e (diff)
downloadVirtualBox-svn-052943bd62b6a951b825f5558a295815438d68b2.tar.gz
VMMDev mouse: bugref:10285: Introduce extended host mouse pointer state.
Provide VMMDev mouse with buttons and H/V wheel movement state. Extended state can be now fetched from host in scope of VMMDevReqMouseStatusEx request. Currently only Linux Additions utilize this functionality. git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@97790 cfe28804-0f27-0410-a406-dd0f0b0b656f
Diffstat (limited to 'src')
-rw-r--r--src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c212
-rw-r--r--src/VBox/Devices/VMMDev/VMMDev.cpp71
-rw-r--r--src/VBox/Devices/VMMDev/VMMDevState.h9
-rw-r--r--src/VBox/Main/include/MouseImpl.h2
-rw-r--r--src/VBox/Main/src-client/MouseImpl.cpp20
5 files changed, 267 insertions, 47 deletions
diff --git a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c
index b10be363380..065b3a20d5c 100644
--- a/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c
+++ b/src/VBox/Additions/common/VBoxGuest/VBoxGuest-linux.c
@@ -104,6 +104,11 @@
# define kuid_t uid_t
#endif
+#ifdef VBOXGUEST_WITH_INPUT_DRIVER
+/** The name of input pointing device for mouse integration. */
+# define VBOX_INPUT_DEVICE_NAME "VirtualBox mouse integration"
+#endif
+
/*********************************************************************************************************************************
* Internal Functions *
@@ -147,9 +152,8 @@ static wait_queue_head_t g_PollEventQueue;
/** Asynchronous notification stuff. */
static struct fasync_struct *g_pFAsyncQueue;
#ifdef VBOXGUEST_WITH_INPUT_DRIVER
-/** Pre-allocated mouse status VMMDev request for use in the IRQ
- * handler. */
-static VMMDevReqMouseStatus *g_pMouseStatusReq;
+/** Pre-allocated mouse status VMMDev requests for use in the IRQ handler. */
+static VMMDevReqMouseStatusEx *g_pMouseStatusReqEx;
#endif
#if RTLNX_VER_MIN(2,6,0)
/** Whether we've create the logger or not. */
@@ -420,6 +424,15 @@ static void vgdrvLinuxTermISR(void)
#ifdef VBOXGUEST_WITH_INPUT_DRIVER
+/**
+ * Check if extended mouse pointer state request protocol is currently used by driver.
+ *
+ * @returns True if extended protocol is used, False otherwise.
+ */
+static bool vgdrvLinuxUsesMouseStatusEx(void)
+{
+ return g_pMouseStatusReqEx->Core.header.requestType == VMMDevReq_GetMouseStatusEx;
+}
/**
* Reports the mouse integration status to the host.
@@ -449,7 +462,9 @@ static int vgdrvLinuxSetMouseStatus(uint32_t fStatus)
*/
static int vboxguestOpenInputDevice(struct input_dev *pDev)
{
- int rc = vgdrvLinuxSetMouseStatus(VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_NEW_PROTOCOL);
+ int rc = vgdrvLinuxSetMouseStatus( VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE
+ | VMMDEV_MOUSE_NEW_PROTOCOL
+ | (vgdrvLinuxUsesMouseStatusEx() ? VMMDEV_MOUSE_GUEST_USES_FULL_STATE_PROTOCOL : 0));
if (RT_FAILURE(rc))
return ENODEV;
NOREF(pDev);
@@ -470,16 +485,58 @@ static void vboxguestCloseInputDevice(struct input_dev *pDev)
/**
+ * Free corresponding mouse status request structure.
+ */
+static void vgdrvLinuxFreeMouseStatusReq(void)
+{
+ VbglR0GRFree(&g_pMouseStatusReqEx->Core.header);
+ g_pMouseStatusReqEx = NULL;
+}
+
+/**
* Creates the kernel input device.
*/
static int __init vgdrvLinuxCreateInputDevice(void)
{
- int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&g_pMouseStatusReq, sizeof(*g_pMouseStatusReq), VMMDevReq_GetMouseStatus);
+ /* Try to allocate legacy request data first, and check if host supports extended protocol. */
+ int rc = VbglR0GRAlloc((VMMDevRequestHeader **)&g_pMouseStatusReqEx, sizeof(VMMDevReqMouseStatus), VMMDevReq_GetMouseStatus);
+ if (RT_SUCCESS(rc))
+ {
+ /* Check if host supports extended mouse state reporting. */
+ g_pMouseStatusReqEx->Core.mouseFeatures = 0;
+ rc = VbglR0GRPerform(&g_pMouseStatusReqEx->Core.header);
+ if (RT_SUCCESS(rc))
+ {
+ if (g_pMouseStatusReqEx->Core.mouseFeatures & VMMDEV_MOUSE_HOST_USES_FULL_STATE_PROTOCOL)
+ {
+ VMMDevReqMouseStatusEx *pReqEx = NULL;
+ rc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReqEx, sizeof(*pReqEx), VMMDevReq_GetMouseStatusEx);
+ if (RT_SUCCESS(rc))
+ {
+ /* De-allocate legacy request data, */
+ VbglR0GRFree(&g_pMouseStatusReqEx->Core.header);
+ /* ..and switch to extended requests. */
+ g_pMouseStatusReqEx = pReqEx;
+ LogRel(("Host supports full mouse state reporting, switching to extended mouse integration protocol\n"));
+ }
+ else
+ LogRel(("Host supports full mouse state reporting, but feature cannot be initialized, switching to legacy mouse integration protocol\n"));
+ }
+ else
+ LogRel(("Host does not support full mouse state reporting, switching to legacy mouse integration protocol\n"));
+ }
+ else
+ LogRel(("Unable to get host mouse capabilities, switching to legacy mouse integration protocol\n"));
+ }
+ else
+ rc = -ENOMEM;
+
if (RT_SUCCESS(rc))
{
g_pInputDevice = input_allocate_device();
if (g_pInputDevice)
{
+ g_pInputDevice->name = VBOX_INPUT_DEVICE_NAME;
g_pInputDevice->id.bustype = BUS_PCI;
g_pInputDevice->id.vendor = VMMDEV_VENDORID;
g_pInputDevice->id.product = VMMDEV_DEVICEID;
@@ -491,32 +548,46 @@ static int __init vgdrvLinuxCreateInputDevice(void)
# else
g_pInputDevice->dev.parent = &g_pPciDev->dev;
# endif
- rc = input_register_device(g_pInputDevice);
- if (rc == 0)
- {
- /* Do what one of our competitors apparently does as that works. */
- ASMBitSet(g_pInputDevice->evbit, EV_ABS);
- ASMBitSet(g_pInputDevice->evbit, EV_KEY);
+ /* Set up input device capabilities. */
+ ASMBitSet(g_pInputDevice->evbit, EV_ABS);
# ifdef EV_SYN
- ASMBitSet(g_pInputDevice->evbit, EV_SYN);
+ ASMBitSet(g_pInputDevice->evbit, EV_SYN);
# endif
- input_set_abs_params(g_pInputDevice, ABS_X, VMMDEV_MOUSE_RANGE_MIN, VMMDEV_MOUSE_RANGE_MAX, 0, 0);
- input_set_abs_params(g_pInputDevice, ABS_Y, VMMDEV_MOUSE_RANGE_MIN, VMMDEV_MOUSE_RANGE_MAX, 0, 0);
- ASMBitSet(g_pInputDevice->keybit, BTN_MOUSE);
- /** @todo this string should be in a header file somewhere. */
- g_pInputDevice->name = "VirtualBox mouse integration";
- return 0;
+ ASMBitSet(g_pInputDevice->absbit, ABS_X);
+ ASMBitSet(g_pInputDevice->absbit, ABS_Y);
+
+ input_set_abs_params(g_pInputDevice, ABS_X, VMMDEV_MOUSE_RANGE_MIN, VMMDEV_MOUSE_RANGE_MAX, 0, 0);
+ input_set_abs_params(g_pInputDevice, ABS_Y, VMMDEV_MOUSE_RANGE_MIN, VMMDEV_MOUSE_RANGE_MAX, 0, 0);
+
+ /* Report extra capabilities to input layer if extended mouse state protocol
+ * will be used in communication with host. */
+ if (vgdrvLinuxUsesMouseStatusEx())
+ {
+ ASMBitSet(g_pInputDevice->evbit, EV_REL);
+ ASMBitSet(g_pInputDevice->evbit, EV_KEY);
+
+ ASMBitSet(g_pInputDevice->relbit, REL_WHEEL);
+ ASMBitSet(g_pInputDevice->relbit, REL_HWHEEL);
+
+ ASMBitSet(g_pInputDevice->keybit, BTN_LEFT);
+ ASMBitSet(g_pInputDevice->keybit, BTN_RIGHT);
+ ASMBitSet(g_pInputDevice->keybit, BTN_MIDDLE);
+ ASMBitSet(g_pInputDevice->keybit, BTN_SIDE);
+ ASMBitSet(g_pInputDevice->keybit, BTN_EXTRA);
}
+ rc = input_register_device(g_pInputDevice);
+ if (rc == 0)
+ return 0;
+
input_free_device(g_pInputDevice);
}
else
rc = -ENOMEM;
- VbglR0GRFree(&g_pMouseStatusReq->header);
- g_pMouseStatusReq = NULL;
+
+ vgdrvLinuxFreeMouseStatusReq();
}
- else
- rc = -ENOMEM;
+
return rc;
}
@@ -526,8 +597,10 @@ static int __init vgdrvLinuxCreateInputDevice(void)
*/
static void vgdrvLinuxTermInputDevice(void)
{
- VbglR0GRFree(&g_pMouseStatusReq->header);
- g_pMouseStatusReq = NULL;
+ /* Notify host that mouse integration is no longer available. */
+ vgdrvLinuxSetMouseStatus(0);
+
+ vgdrvLinuxFreeMouseStatusReq();
/* See documentation of input_register_device(): input_free_device()
* should not be called after a device has been registered. */
@@ -1154,10 +1227,74 @@ static ssize_t vgdrvLinuxRead(struct file *pFile, char *pbBuf, size_t cbRead, lo
}
+#ifdef VBOXGUEST_WITH_INPUT_DRIVER
+/**
+ * Get host mouse state.
+ *
+ * @returns IPRT status code.
+ * @param pfMouseFeatures Where to store host mouse capabilities.
+ * @param pX Where to store X axis coordinate.
+ * @param pY Where to store Y axis coordinate.
+ * @param pDz Where to store vertical wheel movement offset (only set if in case of VMMDevReq_GetMouseStatusEx request).
+ * @param pDw Where to store horizontal wheel movement offset (only set if in case of VMMDevReq_GetMouseStatusEx request).
+ * @param pfButtons Where to store mouse buttons state (only set if in case of VMMDevReq_GetMouseStatusEx request).
+ */
+static int vgdrvLinuxGetHostMouseState(uint32_t *pfMouseFeatures, int32_t *pX, int32_t *pY, int32_t *pDz, int32_t *pDw, uint32_t *pfButtons)
+{
+ int rc = VERR_INVALID_PARAMETER;
+
+ Assert(pfMouseFeatures);
+ Assert(pX);
+ Assert(pY);
+ Assert(pDz);
+ Assert(pDw);
+ Assert(pfButtons);
+
+ /* Initialize legacy request data. */
+ g_pMouseStatusReqEx->Core.mouseFeatures = 0;
+ g_pMouseStatusReqEx->Core.pointerXPos = 0;
+ g_pMouseStatusReqEx->Core.pointerYPos = 0;
+
+ /* Initialize extended request data if VMMDevReq_GetMouseStatusEx is used. */
+ if (vgdrvLinuxUsesMouseStatusEx())
+ {
+ g_pMouseStatusReqEx->dz = 0;
+ g_pMouseStatusReqEx->dw = 0;
+ g_pMouseStatusReqEx->fButtons = 0;
+ }
+
+ /* Get host mouse state - either lagacy or extended version. */
+ rc = VbglR0GRPerform(&g_pMouseStatusReqEx->Core.header);
+ if (RT_SUCCESS(rc))
+ {
+ *pfMouseFeatures = g_pMouseStatusReqEx->Core.mouseFeatures;
+ *pX = g_pMouseStatusReqEx->Core.pointerXPos;
+ *pY = g_pMouseStatusReqEx->Core.pointerYPos;
+
+ /* Get extended mouse state data in case of VMMDevReq_GetMouseStatusEx. */
+ if (vgdrvLinuxUsesMouseStatusEx())
+ {
+ *pDz = g_pMouseStatusReqEx->dz;
+ *pDw = g_pMouseStatusReqEx->dw;
+ *pfButtons = g_pMouseStatusReqEx->fButtons;
+ }
+ }
+
+ return rc;
+}
+#endif /* VBOXGUEST_WITH_INPUT_DRIVER */
+
+
void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
{
#ifdef VBOXGUEST_WITH_INPUT_DRIVER
int rc;
+ uint32_t fMouseFeatures = 0;
+ int32_t x = 0;
+ int32_t y = 0;
+ int32_t dz = 0;
+ int32_t dw = 0;
+ uint32_t fButtons = 0;
#endif
NOREF(pDevExt);
@@ -1170,17 +1307,26 @@ void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
Log3(("VGDrvNativeISRMousePollEvent: kill_fasync\n"));
kill_fasync(&g_pFAsyncQueue, SIGIO, POLL_IN);
#ifdef VBOXGUEST_WITH_INPUT_DRIVER
- /* Report events to the kernel input device */
- g_pMouseStatusReq->mouseFeatures = 0;
- g_pMouseStatusReq->pointerXPos = 0;
- g_pMouseStatusReq->pointerYPos = 0;
- rc = VbglR0GRPerform(&g_pMouseStatusReq->header);
+ rc = vgdrvLinuxGetHostMouseState(&fMouseFeatures, &x, &y, &dz, &dw, &fButtons);
if (RT_SUCCESS(rc))
{
- input_report_abs(g_pInputDevice, ABS_X,
- g_pMouseStatusReq->pointerXPos);
- input_report_abs(g_pInputDevice, ABS_Y,
- g_pMouseStatusReq->pointerYPos);
+ input_report_abs(g_pInputDevice, ABS_X, x);
+ input_report_abs(g_pInputDevice, ABS_Y, y);
+
+ if ( vgdrvLinuxUsesMouseStatusEx()
+ && fMouseFeatures & VMMDEV_MOUSE_HOST_USES_FULL_STATE_PROTOCOL
+ && fMouseFeatures & VMMDEV_MOUSE_GUEST_USES_FULL_STATE_PROTOCOL)
+ {
+ input_report_rel(g_pInputDevice, REL_WHEEL, dz);
+ input_report_rel(g_pInputDevice, REL_HWHEEL, dw);
+
+ input_report_key(g_pInputDevice, BTN_LEFT, RT_BOOL(fButtons & VMMDEV_MOUSE_BUTTON_LEFT));
+ input_report_key(g_pInputDevice, BTN_RIGHT, RT_BOOL(fButtons & VMMDEV_MOUSE_BUTTON_RIGHT));
+ input_report_key(g_pInputDevice, BTN_MIDDLE, RT_BOOL(fButtons & VMMDEV_MOUSE_BUTTON_MIDDLE));
+ input_report_key(g_pInputDevice, BTN_SIDE, RT_BOOL(fButtons & VMMDEV_MOUSE_BUTTON_X1));
+ input_report_key(g_pInputDevice, BTN_EXTRA, RT_BOOL(fButtons & VMMDEV_MOUSE_BUTTON_X2));
+ }
+
# ifdef EV_SYN
input_sync(g_pInputDevice);
# endif
diff --git a/src/VBox/Devices/VMMDev/VMMDev.cpp b/src/VBox/Devices/VMMDev/VMMDev.cpp
index ca0f71357cd..7516b7b4fd3 100644
--- a/src/VBox/Devices/VMMDev/VMMDev.cpp
+++ b/src/VBox/Devices/VMMDev/VMMDev.cpp
@@ -1146,6 +1146,40 @@ static int vmmdevReqHandler_GetMouseStatus(PVMMDEV pThis, VMMDevRequestHeader *p
/**
+ * Handles VMMDevReq_GetMouseStatusEx.
+ *
+ * @returns VBox status code that the guest should see.
+ * @param pThis The VMMDev shared instance data.
+ * @param pReqHdr The header of the request to handle.
+ */
+static int vmmdevReqHandler_GetMouseStatusEx(PVMMDEV pThis, VMMDevRequestHeader *pReqHdr)
+{
+ VMMDevReqMouseStatusEx *pReq = (VMMDevReqMouseStatusEx *)pReqHdr;
+ AssertMsgReturn(pReq->Core.header.size == sizeof(*pReq), ("%u\n", pReq->Core.header.size), VERR_INVALID_PARAMETER);
+
+ /* Main will convert host mouse buttons state obtained from GUI
+ * into PDMIMOUSEPORT_BUTTON_XXX representation. Guest will expect it
+ * to VMMDEV_MOUSE_BUTTON_XXX representaion. Make sure both
+ * representations are identical. */
+ AssertCompile(VMMDEV_MOUSE_BUTTON_LEFT == PDMIMOUSEPORT_BUTTON_LEFT);
+ AssertCompile(VMMDEV_MOUSE_BUTTON_RIGHT == PDMIMOUSEPORT_BUTTON_RIGHT);
+ AssertCompile(VMMDEV_MOUSE_BUTTON_MIDDLE == PDMIMOUSEPORT_BUTTON_MIDDLE);
+ AssertCompile(VMMDEV_MOUSE_BUTTON_X1 == PDMIMOUSEPORT_BUTTON_X1);
+ AssertCompile(VMMDEV_MOUSE_BUTTON_X2 == PDMIMOUSEPORT_BUTTON_X2);
+
+ pReq->Core.mouseFeatures = pThis->fMouseCapabilities & VMMDEV_MOUSE_MASK;
+ pReq->Core.pointerXPos = pThis->xMouseAbs;
+ pReq->Core.pointerYPos = pThis->yMouseAbs;
+ pReq->dz = pThis->dzMouse;
+ pReq->dw = pThis->dwMouse;
+ pReq->fButtons = pThis->fMouseButtons;
+ LogRel2(("VMMDev: vmmdevReqHandler_GetMouseStatusEx: mouseFeatures=%#x, xAbs=%d, yAbs=%d, zAbs=%d, wMouseRel=%d, fButtons=0x%x\n",
+ pReq->Core.mouseFeatures, pReq->Core.pointerXPos, pReq->Core.pointerYPos, pReq->dz, pReq->dw, pReq->fButtons));
+ return VINF_SUCCESS;
+}
+
+
+/**
* Handles VMMDevReq_SetMouseStatus.
*
* @returns VBox status code that the guest should see.
@@ -2799,6 +2833,10 @@ static VBOXSTRICTRC vmmdevReqDispatcher(PPDMDEVINS pDevIns, PVMMDEV pThis, PVMMD
pReqHdr->rc = vmmdevReqHandler_GetMouseStatus(pThis, pReqHdr);
break;
+ case VMMDevReq_GetMouseStatusEx:
+ pReqHdr->rc = vmmdevReqHandler_GetMouseStatusEx(pThis, pReqHdr);
+ break;
+
case VMMDevReq_SetMouseStatus:
pReqHdr->rc = vmmdevReqHandler_SetMouseStatus(pThis, pThisCC, pReqHdr);
break;
@@ -3622,7 +3660,8 @@ static DECLCALLBACK(int) vmmdevIPort_QueryAbsoluteMouse(PPDMIVMMDEVPORT pInterfa
/**
* @interface_method_impl{PDMIVMMDEVPORT,pfnSetAbsoluteMouse}
*/
-static DECLCALLBACK(int) vmmdevIPort_SetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t xAbs, int32_t yAbs)
+static DECLCALLBACK(int) vmmdevIPort_SetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, int32_t xAbs, int32_t yAbs,
+ int32_t dz, int32_t dw, uint32_t fButtons)
{
PVMMDEVCC pThisCC = RT_FROM_MEMBER(pInterface, VMMDEVCC, IPort);
PPDMDEVINS pDevIns = pThisCC->pDevIns;
@@ -3631,11 +3670,20 @@ static DECLCALLBACK(int) vmmdevIPort_SetAbsoluteMouse(PPDMIVMMDEVPORT pInterface
AssertRCReturn(rcLock, rcLock);
if ( pThis->xMouseAbs != xAbs
- || pThis->yMouseAbs != yAbs)
+ || pThis->yMouseAbs != yAbs
+ || dz
+ || dw
+ || pThis->fMouseButtons != fButtons)
{
- Log2(("vmmdevIPort_SetAbsoluteMouse : settings absolute position to x = %d, y = %d\n", xAbs, yAbs));
+ Log2(("vmmdevIPort_SetAbsoluteMouse : settings absolute position to x = %d, y = %d, z = %d, w = %d, fButtons = 0x%x\n",
+ xAbs, yAbs, dz, dw, fButtons));
+
pThis->xMouseAbs = xAbs;
pThis->yMouseAbs = yAbs;
+ pThis->dzMouse = -dz; /* Inverted! */
+ pThis->dwMouse = -dw; /* Inverted! */
+ pThis->fMouseButtons = fButtons;
+
VMMDevNotifyGuest(pDevIns, pThis, pThisCC, VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
}
@@ -3671,7 +3719,8 @@ vmmdevIPort_UpdateMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t fCapsAd
uint32_t fOldCaps = pThis->fMouseCapabilities;
pThis->fMouseCapabilities &= ~(fCapsRemoved & VMMDEV_MOUSE_HOST_MASK);
pThis->fMouseCapabilities |= (fCapsAdded & VMMDEV_MOUSE_HOST_MASK)
- | VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
+ | VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR
+ | VMMDEV_MOUSE_HOST_USES_FULL_STATE_PROTOCOL;
bool fNotify = fOldCaps != pThis->fMouseCapabilities;
LogRelFlow(("VMMDev: vmmdevIPort_UpdateMouseCapabilities: fCapsAdded=0x%x, fCapsRemoved=0x%x, fNotify=%RTbool\n", fCapsAdded,
@@ -4063,6 +4112,9 @@ static DECLCALLBACK(int) vmmdevSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
pHlp->pfnSSMPutU32(pSSM, pThis->fMouseCapabilities);
pHlp->pfnSSMPutS32(pSSM, pThis->xMouseAbs);
pHlp->pfnSSMPutS32(pSSM, pThis->yMouseAbs);
+ pHlp->pfnSSMPutS32(pSSM, pThis->dzMouse);
+ pHlp->pfnSSMPutS32(pSSM, pThis->dwMouse);
+ pHlp->pfnSSMPutU32(pSSM, pThis->fMouseButtons);
pHlp->pfnSSMPutBool(pSSM, pThis->fNewGuestFilterMaskValid);
pHlp->pfnSSMPutU32(pSSM, pThis->fNewGuestFilterMask);
@@ -4155,6 +4207,12 @@ static DECLCALLBACK(int) vmmdevLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uin
pHlp->pfnSSMGetU32(pSSM, &pThis->fMouseCapabilities);
pHlp->pfnSSMGetS32(pSSM, &pThis->xMouseAbs);
pHlp->pfnSSMGetS32(pSSM, &pThis->yMouseAbs);
+ if (uVersion >= VMMDEV_SAVED_STATE_VERSION_VMM_MOUSE_EXTENDED_DATA)
+ {
+ pHlp->pfnSSMGetS32(pSSM, &pThis->dzMouse);
+ pHlp->pfnSSMGetS32(pSSM, &pThis->dwMouse);
+ pHlp->pfnSSMGetU32(pSSM, &pThis->fMouseButtons);
+ }
pHlp->pfnSSMGetBool(pSSM, &pThis->fNewGuestFilterMaskValid);
pHlp->pfnSSMGetU32(pSSM, &pThis->fNewGuestFilterMask);
@@ -5000,6 +5058,11 @@ static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
pThis->fMouseCapabilities |= VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
/*
+ * In this version of VirtualBox full mouse state can be provided to the guest over DevVMM.
+ */
+ pThis->fMouseCapabilities |= VMMDEV_MOUSE_HOST_USES_FULL_STATE_PROTOCOL;
+
+ /*
* Statistics.
*/
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMemBalloonChunks, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
diff --git a/src/VBox/Devices/VMMDev/VMMDevState.h b/src/VBox/Devices/VMMDev/VMMDevState.h
index 112852dbfba..c4a959f1996 100644
--- a/src/VBox/Devices/VMMDev/VMMDevState.h
+++ b/src/VBox/Devices/VMMDev/VMMDevState.h
@@ -144,10 +144,13 @@ typedef struct VMMDEV
/** mouse capabilities of host and guest */
uint32_t fMouseCapabilities;
- /** @name Absolute mouse position in pixels
+ /** @name Absolute mouse position in pixels, relative wheel movement and buttons state.
* @{ */
int32_t xMouseAbs;
int32_t yMouseAbs;
+ int32_t dzMouse;
+ int32_t dwMouse;
+ uint32_t fMouseButtons;
/** @} */
/** Does the guest currently want the host pointer to be shown? */
uint32_t fHostCursorRequested;
@@ -563,7 +566,9 @@ void VMMDevCtlSetGuestFilterMask(PPDMDEVINS pDevIns, PVMMDEV pThis, PVMMDEVCC pT
/** The saved state version. */
-#define VMMDEV_SAVED_STATE_VERSION VMMDEV_SAVED_STATE_VERSION_DISPLAY_CHANGE_DATA
+#define VMMDEV_SAVED_STATE_VERSION VMMDEV_SAVED_STATE_VERSION_VMM_MOUSE_EXTENDED_DATA
+/** The saved state version with VMMDev mouse buttons state and wheel movement data. */
+#define VMMDEV_SAVED_STATE_VERSION_VMM_MOUSE_EXTENDED_DATA 19
/** The saved state version with display change data state. */
#define VMMDEV_SAVED_STATE_VERSION_DISPLAY_CHANGE_DATA 18
/** Updated HGCM commands. */
diff --git a/src/VBox/Main/include/MouseImpl.h b/src/VBox/Main/include/MouseImpl.h
index 5058b452805..7aa0070e059 100644
--- a/src/VBox/Main/include/MouseImpl.h
+++ b/src/VBox/Main/include/MouseImpl.h
@@ -118,7 +118,7 @@ private:
HRESULT i_reportMTEventToMouseDev(int32_t x, int32_t z, uint32_t cContact,
uint32_t fContact);
HRESULT i_reportMultiTouchEventToDevice(uint8_t cContacts, const uint64_t *pau64Contacts, bool fTouchScreen, uint32_t u32ScanTime);
- HRESULT i_reportAbsEventToVMMDev(int32_t x, int32_t y);
+ HRESULT i_reportAbsEventToVMMDev(int32_t x, int32_t y, int32_t dz, int32_t dw, uint32_t fButtons);
HRESULT i_reportAbsEventToInputDevices(int32_t x, int32_t y, int32_t dz, int32_t dw, uint32_t fButtons,
bool fUsesVMMDevEvent);
HRESULT i_reportAbsEventToDisplayDevice(int32_t x, int32_t y);
diff --git a/src/VBox/Main/src-client/MouseImpl.cpp b/src/VBox/Main/src-client/MouseImpl.cpp
index 5747405a0dd..86a75b0ba48 100644
--- a/src/VBox/Main/src-client/MouseImpl.cpp
+++ b/src/VBox/Main/src-client/MouseImpl.cpp
@@ -630,17 +630,16 @@ HRESULT Mouse::i_reportMultiTouchEventToDevice(uint8_t cContacts,
*
* @returns COM status code
*/
-HRESULT Mouse::i_reportAbsEventToVMMDev(int32_t x, int32_t y)
+HRESULT Mouse::i_reportAbsEventToVMMDev(int32_t x, int32_t y, int32_t dz, int32_t dw, uint32_t fButtons)
{
VMMDevMouseInterface *pVMMDev = mParent->i_getVMMDevMouseInterface();
ComAssertRet(pVMMDev, E_FAIL);
PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
ComAssertRet(pVMMDevPort, E_FAIL);
- if (x != mcLastX || y != mcLastY)
+ if (x != mcLastX || y != mcLastY || dz || dw || fButtons != mfLastButtons)
{
- int vrc = pVMMDevPort->pfnSetAbsoluteMouse(pVMMDevPort,
- x, y);
+ int vrc = pVMMDevPort->pfnSetAbsoluteMouse(pVMMDevPort, x, y, dz, dw, fButtons);
if (RT_FAILURE(vrc))
return setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
@@ -670,18 +669,25 @@ HRESULT Mouse::i_reportAbsEventToInputDevices(int32_t x, int32_t y, int32_t dz,
/*
* Send the absolute mouse position to the VMM device.
*/
- if (x != mcLastX || y != mcLastY)
+ if (x != mcLastX || y != mcLastY || dz || dw || fButtons != mfLastButtons)
{
- hrc = i_reportAbsEventToVMMDev(x, y);
+ hrc = i_reportAbsEventToVMMDev(x, y, dz, dw, fButtons);
cJiggle = !fUsesVMMDevEvent;
}
- hrc = i_reportRelEventToMouseDev(cJiggle, 0, dz, dw, fButtons);
+
+ /* If guest cannot yet read full mouse state from DevVMM (i.e.,
+ * only 'x' and 'y' coordinates will be read) we need to pass buttons
+ * state as well as horizontal and vertical wheel movement over ever-present PS/2
+ * emulated mouse device. */
+ if (!(mfVMMDevGuestCaps & VMMDEV_MOUSE_GUEST_USES_FULL_STATE_PROTOCOL))
+ hrc = i_reportRelEventToMouseDev(cJiggle, 0, dz, dw, fButtons);
}
else
hrc = i_reportAbsEventToMouseDev(x, y, dz, dw, fButtons);
mcLastX = x;
mcLastY = y;
+ mfLastButtons = fButtons;
return hrc;
}