/** * 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 *pcX, int32_t *pcY, bool *pfValid) { AssertPtrReturn(pcX, E_POINTER); AssertPtrReturn(pcY, E_POINTER); AssertPtrNullReturn(pfValid, E_POINTER); Display *pDisplay = mParent->getDisplay(); 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; *pcX = displayWidth ? (x * VMMDEV_MOUSE_RANGE + ADJUST_RANGE) / (LONG) displayWidth: 0; *pcY = 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) if (pfValid) *pfValid = false; } return S_OK; }