summaryrefslogtreecommitdiff
path: root/src/VBox/Main/src-client/MouseImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/src-client/MouseImpl.cpp')
-rw-r--r--src/VBox/Main/src-client/MouseImpl.cpp467
1 files changed, 367 insertions, 100 deletions
diff --git a/src/VBox/Main/src-client/MouseImpl.cpp b/src/VBox/Main/src-client/MouseImpl.cpp
index 641f1ad8..652f2df3 100644
--- a/src/VBox/Main/src-client/MouseImpl.cpp
+++ b/src/VBox/Main/src-client/MouseImpl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2008 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -36,7 +36,9 @@ enum
/** The mouse device can do relative reporting */
MOUSE_DEVCAP_RELATIVE = 1,
/** The mouse device can do absolute reporting */
- MOUSE_DEVCAP_ABSOLUTE = 2
+ MOUSE_DEVCAP_ABSOLUTE = 2,
+ /** The mouse device can do absolute reporting */
+ MOUSE_DEVCAP_MULTI_TOUCH = 4
};
/** @} */
@@ -75,8 +77,8 @@ Mouse::~Mouse()
HRESULT Mouse::FinalConstruct()
{
RT_ZERO(mpDrv);
- mcLastAbsX = 0x8000;
- mcLastAbsY = 0x8000;
+ mcLastX = 0x8000;
+ mcLastY = 0x8000;
mfLastButtons = 0;
mfVMMDevGuestCaps = 0;
return BaseFinalConstruct();
@@ -97,7 +99,7 @@ void Mouse::FinalRelease()
* @returns COM result indicator
* @param parent handle of our parent object
*/
-HRESULT Mouse::init (Console *parent)
+HRESULT Mouse::init (ConsoleMouseInterface *parent)
{
LogFlowThisFunc(("\n"));
@@ -109,13 +111,11 @@ HRESULT Mouse::init (Console *parent)
unconst(mParent) = parent;
-#ifndef VBOXBFE_WITHOUT_COM
unconst(mEventSource).createObject();
- HRESULT rc = mEventSource->init(static_cast<IMouse*>(this));
+ HRESULT rc = mEventSource->init();
AssertComRCReturnRC(rc);
mMouseEvent.init(mEventSource, VBoxEventType_OnGuestMouse,
- 0, 0, 0, 0, 0);
-#endif
+ 0, 0, 0, 0, 0, 0);
/* Confirm a successful initialization */
autoInitSpan.setSucceeded();
@@ -143,13 +143,9 @@ void Mouse::uninit()
mpDrv[i] = NULL;
}
-#ifdef VBOXBFE_WITHOUT_COM
- mParent = NULL;
-#else
mMouseEvent.uninit();
unconst(mEventSource).setNull();
unconst(mParent) = NULL;
-#endif
}
@@ -162,7 +158,7 @@ void Mouse::uninit()
HRESULT Mouse::updateVMMDevMouseCaps(uint32_t fCapsAdded,
uint32_t fCapsRemoved)
{
- VMMDev *pVMMDev = mParent->getVMMDev();
+ VMMDevMouseInterface *pVMMDev = mParent->getVMMDevMouseInterface();
if (!pVMMDev)
return E_FAIL; /* No assertion, as the front-ends can send events
* at all sorts of inconvenient times. */
@@ -176,9 +172,8 @@ HRESULT Mouse::updateVMMDevMouseCaps(uint32_t fCapsAdded,
}
/**
- * Returns whether the current setup can accept absolute mouse events, either
- * because an emulated absolute pointing device is active or because the Guest
- * Additions are.
+ * Returns whether the currently active device portfolio can accept absolute
+ * mouse events.
*
* @returns COM status code
* @param absoluteSupported address of result variable
@@ -196,8 +191,8 @@ STDMETHODIMP Mouse::COMGETTER(AbsoluteSupported) (BOOL *absoluteSupported)
}
/**
- * Returns whether the current setup can accept relative mouse events, that is,
- * whether an emulated relative pointing device is active.
+ * Returns whether the currently active device portfolio can accept relative
+ * mouse events.
*
* @returns COM status code
* @param relativeSupported address of result variable
@@ -215,6 +210,25 @@ STDMETHODIMP Mouse::COMGETTER(RelativeSupported) (BOOL *relativeSupported)
}
/**
+ * Returns whether the currently active device portfolio can accept multi-touch
+ * mouse events.
+ *
+ * @returns COM status code
+ * @param multiTouchSupported address of result variable
+ */
+STDMETHODIMP Mouse::COMGETTER(MultiTouchSupported) (BOOL *multiTouchSupported)
+{
+ if (!multiTouchSupported)
+ return E_POINTER;
+
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ *multiTouchSupported = supportsMT();
+ return S_OK;
+}
+
+/**
* Returns whether the guest can currently switch to drawing the mouse cursor
* itself if it is asked to by the front-end.
*
@@ -255,7 +269,6 @@ static uint32_t mouseButtonsToPDM(LONG buttonState)
return fButtons;
}
-#ifndef VBOXBFE_WITHOUT_COM
STDMETHODIMP Mouse::COMGETTER(EventSource)(IEventSource ** aEventSource)
{
CheckComArgOutPointerValid(aEventSource);
@@ -268,7 +281,6 @@ STDMETHODIMP Mouse::COMGETTER(EventSource)(IEventSource ** aEventSource)
return S_OK;
}
-#endif
/**
* Send a relative pointer event to the relative device we deem most
@@ -312,16 +324,16 @@ HRESULT Mouse::reportRelEventToMouseDev(int32_t dx, int32_t dy, int32_t dz,
*
* @returns COM status code
*/
-HRESULT Mouse::reportAbsEventToMouseDev(int32_t mouseXAbs, int32_t mouseYAbs,
+HRESULT Mouse::reportAbsEventToMouseDev(int32_t x, int32_t y,
int32_t dz, int32_t dw, uint32_t fButtons)
{
- if ( mouseXAbs < VMMDEV_MOUSE_RANGE_MIN
- || mouseXAbs > VMMDEV_MOUSE_RANGE_MAX)
+ if ( x < VMMDEV_MOUSE_RANGE_MIN
+ || x > VMMDEV_MOUSE_RANGE_MAX)
return S_OK;
- if ( mouseYAbs < VMMDEV_MOUSE_RANGE_MIN
- || mouseYAbs > VMMDEV_MOUSE_RANGE_MAX)
+ if ( y < VMMDEV_MOUSE_RANGE_MIN
+ || y > VMMDEV_MOUSE_RANGE_MAX)
return S_OK;
- if ( mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY
+ if ( x != mcLastX || y != mcLastY
|| dz || dw || fButtons != mfLastButtons)
{
PPDMIMOUSEPORT pUpPort = NULL;
@@ -337,7 +349,7 @@ HRESULT Mouse::reportAbsEventToMouseDev(int32_t mouseXAbs, int32_t mouseYAbs,
if (!pUpPort)
return S_OK;
- int vrc = pUpPort->pfnPutEventAbs(pUpPort, mouseXAbs, mouseYAbs, dz,
+ int vrc = pUpPort->pfnPutEventAbs(pUpPort, x, y, dz,
dw, fButtons);
if (RT_FAILURE(vrc))
return setError(VBOX_E_IPRT_ERROR,
@@ -349,6 +361,44 @@ HRESULT Mouse::reportAbsEventToMouseDev(int32_t mouseXAbs, int32_t mouseYAbs,
return S_OK;
}
+HRESULT Mouse::reportMultiTouchEventToDevice(uint8_t cContacts,
+ const uint64_t *pau64Contacts,
+ uint32_t u32ScanTime)
+{
+ HRESULT hrc = S_OK;
+
+ PPDMIMOUSEPORT pUpPort = NULL;
+ {
+ AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
+
+ unsigned i;
+ for (i = 0; i < MOUSE_MAX_DEVICES; ++i)
+ {
+ if ( mpDrv[i]
+ && (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_MULTI_TOUCH))
+ {
+ pUpPort = mpDrv[i]->pUpPort;
+ break;
+ }
+ }
+ }
+
+ if (pUpPort)
+ {
+ int vrc = pUpPort->pfnPutEventMultiTouch(pUpPort, cContacts, pau64Contacts, u32ScanTime);
+ if (RT_FAILURE(vrc))
+ hrc = setError(VBOX_E_IPRT_ERROR,
+ tr("Could not send the multi-touch event to the virtual device (%Rrc)"),
+ vrc);
+ }
+ else
+ {
+ hrc = E_UNEXPECTED;
+ }
+
+ return hrc;
+}
+
/**
* Send an absolute position event to the VMM device.
@@ -356,17 +406,17 @@ HRESULT Mouse::reportAbsEventToMouseDev(int32_t mouseXAbs, int32_t mouseYAbs,
*
* @returns COM status code
*/
-HRESULT Mouse::reportAbsEventToVMMDev(int32_t mouseXAbs, int32_t mouseYAbs)
+HRESULT Mouse::reportAbsEventToVMMDev(int32_t x, int32_t y)
{
- VMMDev *pVMMDev = mParent->getVMMDev();
+ VMMDevMouseInterface *pVMMDev = mParent->getVMMDevMouseInterface();
ComAssertRet(pVMMDev, E_FAIL);
PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
ComAssertRet(pVMMDevPort, E_FAIL);
- if (mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY)
+ if (x != mcLastX || y != mcLastY)
{
int vrc = pVMMDevPort->pfnSetAbsoluteMouse(pVMMDevPort,
- mouseXAbs, mouseYAbs);
+ x, y);
if (RT_FAILURE(vrc))
return setError(VBOX_E_IPRT_ERROR,
tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
@@ -382,7 +432,7 @@ HRESULT Mouse::reportAbsEventToVMMDev(int32_t mouseXAbs, int32_t mouseYAbs)
*
* @returns COM status code
*/
-HRESULT Mouse::reportAbsEvent(int32_t mouseXAbs, int32_t mouseYAbs,
+HRESULT Mouse::reportAbsEvent(int32_t x, int32_t y,
int32_t dz, int32_t dw, uint32_t fButtons,
bool fUsesVMMDevEvent)
{
@@ -397,40 +447,73 @@ HRESULT Mouse::reportAbsEvent(int32_t mouseXAbs, int32_t mouseYAbs,
/*
* Send the absolute mouse position to the VMM device.
*/
- if (mouseXAbs != mcLastAbsX || mouseYAbs != mcLastAbsY)
+ if (x != mcLastX || y != mcLastY)
{
- rc = reportAbsEventToVMMDev(mouseXAbs, mouseYAbs);
+ rc = reportAbsEventToVMMDev(x, y);
cJiggle = !fUsesVMMDevEvent;
}
rc = reportRelEventToMouseDev(cJiggle, 0, dz, dw, fButtons);
}
else
- rc = reportAbsEventToMouseDev(mouseXAbs, mouseYAbs, dz, dw, fButtons);
+ rc = reportAbsEventToMouseDev(x, y, dz, dw, fButtons);
- mcLastAbsX = mouseXAbs;
- mcLastAbsY = mouseYAbs;
+ mcLastX = x;
+ mcLastY = y;
return rc;
}
-#ifndef VBOXBFE_WITHOUT_COM
-void Mouse::fireMouseEvent(bool fAbsolute, LONG x, LONG y, LONG dz, LONG dw, LONG Buttons)
+void Mouse::fireMouseEvent(bool fAbsolute, LONG x, LONG y, LONG dz, LONG dw,
+ LONG fButtons)
{
/* If mouse button is pressed, we generate new event, to avoid reusable events coalescing and thus
dropping key press events */
- if (Buttons != 0)
+ GuestMouseEventMode_T mode;
+ if (fAbsolute)
+ mode = GuestMouseEventMode_Absolute;
+ else
+ mode = GuestMouseEventMode_Relative;
+
+ if (fButtons != 0)
{
VBoxEventDesc evDesc;
- evDesc.init(mEventSource, VBoxEventType_OnGuestMouse, fAbsolute, x, y, dz, dw, Buttons);
+ evDesc.init(mEventSource, VBoxEventType_OnGuestMouse, mode, x, y,
+ dz, dw, fButtons);
evDesc.fire(0);
}
else
{
- mMouseEvent.reinit(VBoxEventType_OnGuestMouse, fAbsolute, x, y, dz, dw, Buttons);
+ mMouseEvent.reinit(VBoxEventType_OnGuestMouse, mode, x, y, dz, dw,
+ fButtons);
mMouseEvent.fire(0);
}
}
-#endif
+void Mouse::fireMultiTouchEvent(uint8_t cContacts,
+ const LONG64 *paContacts,
+ uint32_t u32ScanTime)
+{
+ com::SafeArray<SHORT> xPositions(cContacts);
+ com::SafeArray<SHORT> yPositions(cContacts);
+ com::SafeArray<USHORT> contactIds(cContacts);
+ com::SafeArray<USHORT> contactFlags(cContacts);
+
+ uint8_t i;
+ for (i = 0; i < cContacts; i++)
+ {
+ uint32_t u32Lo = RT_LO_U32(paContacts[i]);
+ uint32_t u32Hi = RT_HI_U32(paContacts[i]);
+ xPositions[i] = (int16_t)u32Lo;
+ yPositions[i] = (int16_t)(u32Lo >> 16);
+ contactIds[i] = RT_BYTE1(u32Hi);
+ contactFlags[i] = RT_BYTE2(u32Hi);
+ }
+
+ VBoxEventDesc evDesc;
+ evDesc.init(mEventSource, VBoxEventType_OnGuestMultiTouch,
+ cContacts, ComSafeArrayAsInParam(xPositions), ComSafeArrayAsInParam(yPositions),
+ ComSafeArrayAsInParam(contactIds), ComSafeArrayAsInParam(contactFlags), u32ScanTime);
+ evDesc.fire(0);
+}
/**
* Send a relative mouse event to the guest.
@@ -442,25 +525,26 @@ void Mouse::fireMouseEvent(bool fAbsolute, LONG x, LONG y, LONG dz, LONG dw, LON
* @param dx X movement
* @param dy Y movement
* @param dz Z movement
- * @param buttonState The mouse button state
+ * @param fButtons The mouse button state
*/
-STDMETHODIMP Mouse::PutMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw, LONG buttonState)
+STDMETHODIMP Mouse::PutMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw,
+ LONG fButtons)
{
HRESULT rc;
- uint32_t fButtons;
+ uint32_t fButtonsAdj;
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__,
dx, dy, dz, dw));
- fButtons = mouseButtonsToPDM(buttonState);
+ fButtonsAdj = mouseButtonsToPDM(fButtons);
/* Make sure that the guest knows that we are sending real movement
* events to the PS/2 device and not just dummy wake-up ones. */
updateVMMDevMouseCaps(0, VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE);
- rc = reportRelEventToMouseDev(dx, dy, dz, dw, fButtons);
+ rc = reportRelEventToMouseDev(dx, dy, dz, dw, fButtonsAdj);
- fireMouseEvent(false, dx, dy, dz, dw, buttonState);
+ fireMouseEvent(false, dx, dy, dz, dw, fButtons);
return rc;
}
@@ -480,13 +564,13 @@ STDMETHODIMP Mouse::PutMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw, LONG butto
*
* @returns COM status value
*/
-HRESULT Mouse::convertDisplayRes(LONG x, LONG y, int32_t *pcX, int32_t *pcY,
+HRESULT Mouse::convertDisplayRes(LONG x, LONG y, int32_t *pxAdj, int32_t *pyAdj,
bool *pfValid)
{
- AssertPtrReturn(pcX, E_POINTER);
- AssertPtrReturn(pcY, E_POINTER);
+ AssertPtrReturn(pxAdj, E_POINTER);
+ AssertPtrReturn(pyAdj, E_POINTER);
AssertPtrNullReturn(pfValid, E_POINTER);
- Display *pDisplay = mParent->getDisplay();
+ DisplayMouseInterface *pDisplay = mParent->getDisplayMouseInterface();
ComAssertRet(pDisplay, E_FAIL);
/** The amount to add to the result (multiplied by the screen width/height)
* to compensate for differences in guest methods for mapping back to
@@ -499,27 +583,29 @@ HRESULT Mouse::convertDisplayRes(LONG x, LONG y, int32_t *pcX, int32_t *pcY,
{
ULONG displayWidth, displayHeight;
/* Takes the display lock */
- HRESULT rc = pDisplay->GetScreenResolution(0, &displayWidth,
- &displayHeight, NULL);
+ HRESULT rc = pDisplay->getScreenResolution(0, &displayWidth,
+ &displayHeight, NULL, NULL, NULL);
if (FAILED(rc))
return rc;
- *pcX = displayWidth ? (x * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
- / (LONG) displayWidth: 0;
- *pcY = displayHeight ? (y * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
- / (LONG) displayHeight: 0;
+ *pxAdj = displayWidth ? (x * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
+ / (LONG) displayWidth: 0;
+ *pyAdj = displayHeight ? (y * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
+ / (LONG) displayHeight: 0;
}
else
{
int32_t x1, y1, x2, y2;
/* Takes the display lock */
pDisplay->getFramebufferDimensions(&x1, &y1, &x2, &y2);
- *pcX = x1 < x2 ? ((x - x1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
- / (x2 - x1) : 0;
- *pcY = y1 < y2 ? ((y - y1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
- / (y2 - y1) : 0;
- if ( *pcX < VMMDEV_MOUSE_RANGE_MIN || *pcX > VMMDEV_MOUSE_RANGE_MAX
- || *pcY < VMMDEV_MOUSE_RANGE_MIN || *pcY > VMMDEV_MOUSE_RANGE_MAX)
+ *pxAdj = x1 < x2 ? ((x - x1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
+ / (x2 - x1) : 0;
+ *pyAdj = y1 < y2 ? ((y - y1) * VMMDEV_MOUSE_RANGE + ADJUST_RANGE)
+ / (y2 - y1) : 0;
+ if ( *pxAdj < VMMDEV_MOUSE_RANGE_MIN
+ || *pxAdj > VMMDEV_MOUSE_RANGE_MAX
+ || *pyAdj < VMMDEV_MOUSE_RANGE_MIN
+ || *pyAdj > VMMDEV_MOUSE_RANGE_MAX)
if (pfValid)
*pfValid = false;
}
@@ -540,47 +626,209 @@ HRESULT Mouse::convertDisplayRes(LONG x, LONG y, int32_t *pcX, int32_t *pcY,
* @param x X position (pixel), starting from 1
* @param y Y position (pixel), starting from 1
* @param dz Z movement
- * @param buttonState The mouse button state
+ * @param fButtons The mouse button state
*/
STDMETHODIMP Mouse::PutMouseEventAbsolute(LONG x, LONG y, LONG dz, LONG dw,
- LONG buttonState)
+ LONG fButtons)
{
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
- LogRel3(("%s: x=%d, y=%d, dz=%d, dw=%d, buttonState=0x%x\n",
- __PRETTY_FUNCTION__, x, y, dz, dw, buttonState));
+ LogRel3(("%s: x=%d, y=%d, dz=%d, dw=%d, fButtons=0x%x\n",
+ __PRETTY_FUNCTION__, x, y, dz, dw, fButtons));
- int32_t mouseXAbs, mouseYAbs;
- uint32_t fButtons;
+ int32_t xAdj, yAdj;
+ uint32_t fButtonsAdj;
bool fValid;
/** @todo the front end should do this conversion to avoid races */
/** @note Or maybe not... races are pretty inherent in everything done in
* this object and not really bad as far as I can see. */
- HRESULT rc = convertDisplayRes(x, y, &mouseXAbs, &mouseYAbs, &fValid);
+ HRESULT rc = convertDisplayRes(x, y, &xAdj, &yAdj, &fValid);
if (FAILED(rc)) return rc;
- fButtons = mouseButtonsToPDM(buttonState);
+ fButtonsAdj = mouseButtonsToPDM(fButtons);
/* If we are doing old-style (IRQ-less) absolute reporting to the VMM
* device then make sure the guest is aware of it, so that it knows to
* ignore relative movement on the PS/2 device. */
updateVMMDevMouseCaps(VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE, 0);
if (fValid)
{
- rc = reportAbsEvent(mouseXAbs, mouseYAbs, dz, dw, fButtons,
+ rc = reportAbsEvent(xAdj, yAdj, dz, dw, fButtonsAdj,
RT_BOOL( mfVMMDevGuestCaps
& VMMDEV_MOUSE_NEW_PROTOCOL));
- fireMouseEvent(true, x, y, dz, dw, buttonState);
+ fireMouseEvent(true, x, y, dz, dw, fButtons);
}
return rc;
}
+/**
+ * Send a multi-touch event. This requires multi-touch pointing device emulation.
+ * @note all calls out of this object are made with no locks held!
+ *
+ * @returns COM status code.
+ * @param aCount Number of contacts.
+ * @param aContacts Information about each contact.
+ * @param aScanTime Timestamp.
+ */
+STDMETHODIMP Mouse::PutEventMultiTouch(LONG aCount,
+ ComSafeArrayIn(LONG64, aContacts),
+ ULONG aScanTime)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+ com::SafeArray <LONG64> arrayContacts(ComSafeArrayInArg(aContacts));
+
+ LogRel3(("%s: aCount %d(actual %d), aScanTime %u\n",
+ __FUNCTION__, aCount, arrayContacts.size(), aScanTime));
+
+ HRESULT rc = S_OK;
+
+ if ((LONG)arrayContacts.size() >= aCount)
+ {
+ LONG64* paContacts = arrayContacts.raw();
+
+ rc = putEventMultiTouch(aCount, paContacts, aScanTime);
+ }
+ else
+ {
+ rc = E_INVALIDARG;
+ }
+
+ return rc;
+}
+
+/**
+ * Send a multi-touch event. Version for scripting languages.
+ *
+ * @returns COM status code.
+ * @param aCount Number of contacts.
+ * @param aContacts Information about each contact.
+ * @param aScanTime Timestamp.
+ */
+STDMETHODIMP Mouse::PutEventMultiTouchString(LONG aCount,
+ IN_BSTR aContacts,
+ ULONG aScanTime)
+{
+ /** @todo implement: convert the string to LONG64 array and call putEventMultiTouch. */
+ NOREF(aCount);
+ NOREF(aContacts);
+ NOREF(aScanTime);
+ return E_NOTIMPL;
+}
+
+
// private methods
/////////////////////////////////////////////////////////////////////////////
+/* Used by PutEventMultiTouch and PutEventMultiTouchString. */
+HRESULT Mouse::putEventMultiTouch(LONG aCount,
+ LONG64 *paContacts,
+ ULONG aScanTime)
+{
+ if (aCount >= 256)
+ {
+ return E_INVALIDARG;
+ }
+
+ DisplayMouseInterface *pDisplay = mParent->getDisplayMouseInterface();
+ ComAssertRet(pDisplay, E_FAIL);
+
+ /* Touch events are mapped to the primary monitor, because the emulated USB
+ * touchscreen device is associated with one (normally the primary) screen in the guest.
+ */
+ ULONG uScreenId = 0;
+
+ ULONG cWidth = 0;
+ ULONG cHeight = 0;
+ LONG xOrigin = 0;
+ LONG yOrigin = 0;
+ HRESULT rc = pDisplay->getScreenResolution(uScreenId, &cWidth, &cHeight, NULL, &xOrigin, &yOrigin);
+ ComAssertComRCRetRC(rc);
+
+ uint64_t* pau64Contacts = NULL;
+ uint8_t cContacts = 0;
+
+ /* Deliver 0 contacts too, touch device may use this to reset the state. */
+ if (aCount > 0)
+ {
+ /* Create a copy with converted coords. */
+ pau64Contacts = (uint64_t *)RTMemTmpAlloc(aCount * sizeof(uint64_t));
+ if (pau64Contacts)
+ {
+ int32_t x1 = xOrigin;
+ int32_t y1 = yOrigin;
+ int32_t x2 = x1 + cWidth;
+ int32_t y2 = y1 + cHeight;
+
+ LogRel3(("%s: screen [%d] %d,%d %d,%d\n",
+ __FUNCTION__, uScreenId, x1, y1, x2, y2));
+
+ LONG i;
+ for (i = 0; i < aCount; i++)
+ {
+ uint32_t u32Lo = RT_LO_U32(paContacts[i]);
+ uint32_t u32Hi = RT_HI_U32(paContacts[i]);
+ int32_t x = (int16_t)u32Lo;
+ int32_t y = (int16_t)(u32Lo >> 16);
+ uint8_t contactId = RT_BYTE1(u32Hi);
+ bool fInContact = (RT_BYTE2(u32Hi) & 0x1) != 0;
+ bool fInRange = (RT_BYTE2(u32Hi) & 0x2) != 0;
+
+ LogRel3(("%s: [%d] %d,%d id %d, inContact %d, inRange %d\n",
+ __FUNCTION__, i, x, y, contactId, fInContact, fInRange));
+
+ /* x1,y1 are inclusive and x2,y2 are exclusive,
+ * while x,y start from 1 and are inclusive.
+ */
+ if (x <= x1 || x > x2 || y <= y1 || y > y2)
+ {
+ /* Out of range. Skip the contact. */
+ continue;
+ }
+
+ int32_t xAdj = x1 < x2? ((x - 1 - x1) * VMMDEV_MOUSE_RANGE) / (x2 - x1) : 0;
+ int32_t yAdj = y1 < y2? ((y - 1 - y1) * VMMDEV_MOUSE_RANGE) / (y2 - y1) : 0;
+
+ bool fValid = ( xAdj >= VMMDEV_MOUSE_RANGE_MIN
+ && xAdj <= VMMDEV_MOUSE_RANGE_MAX
+ && yAdj >= VMMDEV_MOUSE_RANGE_MIN
+ && yAdj <= VMMDEV_MOUSE_RANGE_MAX);
+
+ if (fValid)
+ {
+ uint8_t fu8 = (fInContact? 0x01: 0x00)
+ | (fInRange? 0x02: 0x00);
+ pau64Contacts[cContacts] = RT_MAKE_U64_FROM_U16((uint16_t)xAdj,
+ (uint16_t)yAdj,
+ RT_MAKE_U16(contactId, fu8),
+ 0);
+ cContacts++;
+ }
+ }
+ }
+ else
+ {
+ rc = E_OUTOFMEMORY;
+ }
+ }
+
+ if (SUCCEEDED(rc))
+ {
+ rc = reportMultiTouchEventToDevice(cContacts, cContacts? pau64Contacts: NULL, (uint32_t)aScanTime);
+
+ /* Send the original contact information. */
+ fireMultiTouchEvent(cContacts, cContacts? paContacts: NULL, (uint32_t)aScanTime);
+ }
+
+ RTMemTmpFree(pau64Contacts);
+
+ return rc;
+}
+
/** Does the guest currently rely on the host to draw the mouse cursor or
* can it switch to doing it itself in software? */
@@ -592,10 +840,11 @@ bool Mouse::guestNeedsHostCursor(void)
/** Check what sort of reporting can be done using the devices currently
* enabled. Does not consider the VMM device. */
-void Mouse::getDeviceCaps(bool *pfAbs, bool *pfRel)
+void Mouse::getDeviceCaps(bool *pfAbs, bool *pfRel, bool *pfMT)
{
bool fAbsDev = false;
bool fRelDev = false;
+ bool fMTDev = false;
AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
@@ -606,11 +855,15 @@ void Mouse::getDeviceCaps(bool *pfAbs, bool *pfRel)
fAbsDev = true;
if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_RELATIVE)
fRelDev = true;
+ if (mpDrv[i]->u32DevCaps & MOUSE_DEVCAP_MULTI_TOUCH)
+ fMTDev = true;
}
if (pfAbs)
*pfAbs = fAbsDev;
if (pfRel)
*pfRel = fRelDev;
+ if (pfMT)
+ *pfMT = fMTDev;
}
@@ -619,7 +872,7 @@ bool Mouse::vmmdevCanAbs(void)
{
bool fRelDev;
- getDeviceCaps(NULL, &fRelDev);
+ getDeviceCaps(NULL, &fRelDev, NULL);
return (mfVMMDevGuestCaps & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE)
&& fRelDev;
}
@@ -630,7 +883,7 @@ bool Mouse::deviceCanAbs(void)
{
bool fAbsDev;
- getDeviceCaps(&fAbsDev, NULL);
+ getDeviceCaps(&fAbsDev, NULL, NULL);
return fAbsDev;
}
@@ -640,7 +893,7 @@ bool Mouse::supportsRel(void)
{
bool fRelDev;
- getDeviceCaps(NULL, &fRelDev);
+ getDeviceCaps(NULL, &fRelDev, NULL);
return fRelDev;
}
@@ -650,22 +903,32 @@ bool Mouse::supportsAbs(void)
{
bool fAbsDev;
- getDeviceCaps(&fAbsDev, NULL);
+ getDeviceCaps(&fAbsDev, NULL, NULL);
return fAbsDev || vmmdevCanAbs();
}
+/** Can we currently send absolute events to the guest? */
+bool Mouse::supportsMT(void)
+{
+ bool fMTDev;
+
+ getDeviceCaps(NULL, NULL, &fMTDev);
+ return fMTDev;
+}
+
+
/** Check what sort of reporting can be done using the devices currently
* enabled (including the VMM device) and notify the guest and the front-end.
*/
void Mouse::sendMouseCapsNotifications(void)
{
- bool fAbsDev, fRelDev, fCanAbs, fNeedsHostCursor;
+ bool fAbsDev, fRelDev, fMTDev, fCanAbs, fNeedsHostCursor;
{
AutoReadLock aLock(this COMMA_LOCKVAL_SRC_POS);
- getDeviceCaps(&fAbsDev, &fRelDev);
+ getDeviceCaps(&fAbsDev, &fRelDev, &fMTDev);
fCanAbs = supportsAbs();
fNeedsHostCursor = guestNeedsHostCursor();
}
@@ -676,7 +939,7 @@ void Mouse::sendMouseCapsNotifications(void)
/** @todo this call takes the Console lock in order to update the cached
* callback data atomically. However I can't see any sign that the cached
* data is ever used again. */
- mParent->onMouseCapabilityChange(fCanAbs, fRelDev, fNeedsHostCursor);
+ mParent->onMouseCapabilityChange(fCanAbs, fRelDev, fMTDev, fNeedsHostCursor);
}
@@ -684,7 +947,7 @@ void Mouse::sendMouseCapsNotifications(void)
* @interface_method_impl{PDMIMOUSECONNECTOR,pfnReportModes}
* A virtual device is notifying us about its current state and capabilities
*/
-DECLCALLBACK(void) Mouse::mouseReportModes(PPDMIMOUSECONNECTOR pInterface, bool fRel, bool fAbs)
+DECLCALLBACK(void) Mouse::mouseReportModes(PPDMIMOUSECONNECTOR pInterface, bool fRel, bool fAbs, bool fMT)
{
PDRVMAINMOUSE pDrv = RT_FROM_MEMBER(pInterface, DRVMAINMOUSE, IConnector);
if (fRel)
@@ -695,6 +958,10 @@ DECLCALLBACK(void) Mouse::mouseReportModes(PPDMIMOUSECONNECTOR pInterface, bool
pDrv->u32DevCaps |= MOUSE_DEVCAP_ABSOLUTE;
else
pDrv->u32DevCaps &= ~MOUSE_DEVCAP_ABSOLUTE;
+ if (fMT)
+ pDrv->u32DevCaps |= MOUSE_DEVCAP_MULTI_TOUCH;
+ else
+ pDrv->u32DevCaps &= ~MOUSE_DEVCAP_MULTI_TOUCH;
pDrv->pMouse->sendMouseCapsNotifications();
}
@@ -722,17 +989,17 @@ DECLCALLBACK(void *) Mouse::drvQueryInterface(PPDMIBASE pInterface, const char
*/
DECLCALLBACK(void) Mouse::drvDestruct(PPDMDRVINS pDrvIns)
{
- PDRVMAINMOUSE pData = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
- LogFlow(("Mouse::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+ PDRVMAINMOUSE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
+ LogFlow(("Mouse::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
- if (pData->pMouse)
+ if (pThis->pMouse)
{
- AutoWriteLock mouseLock(pData->pMouse COMMA_LOCKVAL_SRC_POS);
+ AutoWriteLock mouseLock(pThis->pMouse COMMA_LOCKVAL_SRC_POS);
for (unsigned cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev)
- if (pData->pMouse->mpDrv[cDev] == pData)
+ if (pThis->pMouse->mpDrv[cDev] == pThis)
{
- pData->pMouse->mpDrv[cDev] = NULL;
+ pThis->pMouse->mpDrv[cDev] = NULL;
break;
}
}
@@ -746,9 +1013,9 @@ DECLCALLBACK(void) Mouse::drvDestruct(PPDMDRVINS pDrvIns)
*/
DECLCALLBACK(int) Mouse::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
- PDRVMAINMOUSE pData = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
- LogFlow(("drvMainMouse_Construct: iInstance=%d\n", pDrvIns->iInstance));
PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+ PDRVMAINMOUSE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINMOUSE);
+ LogFlow(("drvMainMouse_Construct: iInstance=%d\n", pDrvIns->iInstance));
/*
* Validate configuration.
@@ -764,13 +1031,13 @@ DECLCALLBACK(int) Mouse::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32
*/
pDrvIns->IBase.pfnQueryInterface = Mouse::drvQueryInterface;
- pData->IConnector.pfnReportModes = Mouse::mouseReportModes;
+ pThis->IConnector.pfnReportModes = Mouse::mouseReportModes;
/*
* Get the IMousePort interface of the above driver/device.
*/
- pData->pUpPort = (PPDMIMOUSEPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMIMOUSEPORT_IID);
- if (!pData->pUpPort)
+ pThis->pUpPort = (PPDMIMOUSEPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMIMOUSEPORT_IID);
+ if (!pThis->pUpPort)
{
AssertMsgFailed(("Configuration error: No mouse port interface above!\n"));
return VERR_PDM_MISSING_INTERFACE_ABOVE;
@@ -786,15 +1053,15 @@ DECLCALLBACK(int) Mouse::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32
AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
return rc;
}
- pData->pMouse = (Mouse *)pv; /** @todo Check this cast! */
+ pThis->pMouse = (Mouse *)pv; /** @todo Check this cast! */
unsigned cDev;
{
- AutoReadLock mouseLock(pData->pMouse COMMA_LOCKVAL_SRC_POS);
+ AutoReadLock mouseLock(pThis->pMouse COMMA_LOCKVAL_SRC_POS);
for (cDev = 0; cDev < MOUSE_MAX_DEVICES; ++cDev)
- if (!pData->pMouse->mpDrv[cDev])
+ if (!pThis->pMouse->mpDrv[cDev])
{
- pData->pMouse->mpDrv[cDev] = pData;
+ pThis->pMouse->mpDrv[cDev] = pThis;
break;
}
}