/** * Send an absolute position event to the display device. * @note all calls out of this object are made with no locks held! * @param x Cursor X position in pixels relative to the first screen, where * (1, 1) is the upper left corner. * @param y Cursor Y position in pixels relative to the first screen, where * (1, 1) is the upper left corner. */ HRESULT Mouse::i_reportAbsEventToDisplayDevice(int32_t x, int32_t y) { DisplayMouseInterface *pDisplay = mParent->getDisplayMouseInterface(); ComAssertRet(pDisplay, E_FAIL); if (x != mcLastX || y != mcLastY) { pDisplay->i_reportHostCursorPosition(x - 1, y - 1); } return S_OK; }
/** * Convert an (X, Y) value pair in screen co-ordinates (starting from 1) to a * value from VMMDEV_MOUSE_RANGE_MIN to VMMDEV_MOUSE_RANGE_MAX. Sets the * optional validity value to false if the pair is not on an active screen and * to true otherwise. * @note since guests with recent versions of X.Org use a different method * to everyone else to map the valuator value to a screen pixel (they * multiply by the screen dimension, do a floating point divide by * the valuator maximum and round the result, while everyone else * does truncating integer operations) we adjust the value we send * so that it maps to the right pixel both when the result is rounded * and when it is truncated. * * @returns COM status value */ HRESULT Mouse::convertDisplayRes(LONG x, LONG y, int32_t *pxAdj, int32_t *pyAdj, bool *pfValid) { AssertPtrReturn(pxAdj, E_POINTER); AssertPtrReturn(pyAdj, E_POINTER); AssertPtrNullReturn(pfValid, E_POINTER); 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 * pixels */ enum { ADJUST_RANGE = - 3 * VMMDEV_MOUSE_RANGE / 4 }; if (pfValid) *pfValid = true; if (!(mfVMMDevGuestCaps & VMMDEV_MOUSE_NEW_PROTOCOL)) { ULONG displayWidth, displayHeight; /* Takes the display lock */ HRESULT rc = pDisplay->getScreenResolution(0, &displayWidth, &displayHeight, NULL); if (FAILED(rc)) return rc; *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); *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; } return S_OK; }
/** Report the front-end's mouse handling capabilities to the VMM device and * thus to the guest. * @note all calls out of this object are made with no locks held! */ HRESULT Mouse::updateVMMDevMouseCaps(uint32_t fCapsAdded, uint32_t fCapsRemoved) { VMMDevMouseInterface *pVMMDev = mParent->getVMMDevMouseInterface(); if (!pVMMDev) return E_FAIL; /* No assertion, as the front-ends can send events * at all sorts of inconvenient times. */ DisplayMouseInterface *pDisplay = mParent->getDisplayMouseInterface(); if (pDisplay == NULL) return E_FAIL; PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort(); if (!pVMMDevPort) return E_FAIL; /* same here */ int rc = pVMMDevPort->pfnUpdateMouseCapabilities(pVMMDevPort, fCapsAdded, fCapsRemoved); if (RT_FAILURE(rc)) return E_FAIL; return pDisplay->i_reportHostCursorCapabilities(fCapsAdded, fCapsRemoved); }
/* 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); HRESULT rc = S_OK; 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, y1, x2, y2; /* Takes the display lock */ pDisplay->getFramebufferDimensions(&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)); /* Framebuffer dimensions are 0,0 width, height, that is x2,y2 are exclusive, * while coords are inclusive. */ 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 {
/* 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 {