diff options
Diffstat (limited to 'src/VBox/Main/src-client/MouseImpl.cpp')
-rw-r--r-- | src/VBox/Main/src-client/MouseImpl.cpp | 467 |
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; } } |