Exemplo n.º 1
0
/**
 * 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;
}