Add support for notifying clients about pointer movements

This change adds support for the VMware Mouse Position
pseudo-encoding[1], which is used to notify VNC clients when X11 clients
call `XWarpPointer()`[2]. This function is called by SDL (and other
similar libraries)  when they detect that the server does not support
native relative motion, like some RFB clients.

With this, RFB clients can choose to adjust the local cursor position
under certain circumstances to match what the server has set. For
instance, if pointer lock has been enabled on the client's machine and
the cursor is not being drawn locally, the local position of the cursor
is irrelevant, so the RFB client can use what the server sends as the
canonical absolute position of the cursor. This ultimately enables the
possibility of games (especially FPS games) to behave how users expect
(if the clients implement the corresponding change).

Part of: #619

1: https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#vmware-cursor-position-pseudo-encoding
2: https://tronche.com/gui/x/xlib/input/XWarpPointer.html
3: https://hg.libsdl.org/SDL/file/28e3b60e2131/src/events/SDL_mouse.c#l804
This commit is contained in:
lhchavez
2021-02-07 16:36:47 -08:00
committed by Lauri Kasanen
parent d8caab699d
commit 25b8e64adb
16 changed files with 146 additions and 8 deletions

View File

@@ -39,6 +39,7 @@ SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
needSetDesktopSize(false), needExtendedDesktopSize(false),
needSetDesktopName(false), needSetCursor(false),
needSetXCursor(false), needSetCursorWithAlpha(false),
needCursorPos(false),
needLEDState(false), needQEMUKeyEvent(false)
{
}
@@ -204,6 +205,14 @@ bool SMsgWriter::writeSetCursorWithAlpha()
return true;
}
void SMsgWriter::writeCursorPos()
{
if (!cp->supportsEncoding(pseudoEncodingVMwareCursorPosition))
throw Exception("Client does not support cursor position");
needCursorPos = true;
}
bool SMsgWriter::writeLEDState()
{
if (!cp->supportsLEDState)
@@ -232,6 +241,8 @@ bool SMsgWriter::needFakeUpdate()
return true;
if (needSetCursor || needSetXCursor || needSetCursorWithAlpha)
return true;
if (needCursorPos)
return true;
if (needLEDState)
return true;
if (needQEMUKeyEvent)
@@ -284,6 +295,8 @@ void SMsgWriter::writeFramebufferUpdateStart(int nRects)
nRects++;
if (needSetCursorWithAlpha)
nRects++;
if (needCursorPos)
nRects++;
if (needLEDState)
nRects++;
if (needQEMUKeyEvent)
@@ -399,6 +412,18 @@ void SMsgWriter::writePseudoRects()
needSetCursorWithAlpha = false;
}
if (needCursorPos) {
const Point& cursorPos = cp->cursorPos();
if (cp->supportsEncoding(pseudoEncodingVMwareCursorPosition)) {
writeSetVMwareCursorPositionRect(cursorPos.x, cursorPos.y);
} else {
throw Exception("Client does not support cursor position");
}
needCursorPos = false;
}
if (needSetDesktopName) {
writeSetDesktopNameRect(cp->name());
needSetDesktopName = false;
@@ -577,6 +602,20 @@ void SMsgWriter::writeSetCursorWithAlphaRect(int width, int height,
}
}
void SMsgWriter::writeSetVMwareCursorPositionRect(int hotspotX, int hotspotY)
{
if (!cp->supportsEncoding(pseudoEncodingVMwareCursorPosition))
throw Exception("Client does not support cursor position");
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw Exception("SMsgWriter::writeSetVMwareCursorRect: nRects out of sync");
os->writeS16(hotspotX);
os->writeS16(hotspotY);
os->writeU16(0);
os->writeU16(0);
os->writeU32(pseudoEncodingVMwareCursorPosition);
}
void SMsgWriter::writeLEDStateRect(rdr::U8 state)
{
if (!cp->supportsLEDState)