From 0029a49a8d3cd17cf15dd2c71cb59d64d7291492 Mon Sep 17 00:00:00 2001 From: lhchavez Date: Mon, 8 Feb 2021 07:09:10 -0800 Subject: [PATCH] Support the VMware Cursor Position extension on vncviewer This change makes it possible for re-synchronizing the remote cursor on the vncviewer when in fullscreen mode. This is done by locally moving the cursor position to what the server thinks it should be. Now SDL games should work! --- common/rfb/CConnection.cxx | 7 +++++-- common/rfb/CConnection.h | 1 + common/rfb/CMsgHandler.h | 1 + common/rfb/CMsgReader.cxx | 4 ++++ tests/perf/decperf.cxx | 5 +++++ tests/perf/encperf.cxx | 5 +++++ vncviewer/CConn.cxx | 6 ++++++ vncviewer/CConn.h | 1 + vncviewer/DesktopWindow.cxx | 22 ++++++++++++++++++++++ vncviewer/DesktopWindow.h | 3 +++ 10 files changed, 53 insertions(+), 2 deletions(-) diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx index 9a9593e289..1c9490095c 100644 --- a/common/rfb/CConnection.cxx +++ b/common/rfb/CConnection.cxx @@ -43,8 +43,8 @@ static LogWriter vlog("CConnection"); CConnection::CConnection() : csecurity(0), - supportsLocalCursor(false), supportsDesktopResize(false), - supportsLEDState(false), + supportsLocalCursor(false), supportsCursorPosition(false), + supportsDesktopResize(false), supportsLEDState(false), is(0), os(0), reader_(0), writer_(0), shared(false), state_(RFBSTATE_UNINITIALISED), @@ -805,6 +805,9 @@ void CConnection::updateEncodings() encodings.push_back(pseudoEncodingCursor); encodings.push_back(pseudoEncodingXCursor); } + if (supportsCursorPosition) { + encodings.push_back(pseudoEncodingVMwareCursorPosition); + } if (supportsDesktopResize) { encodings.push_back(pseudoEncodingDesktopSize); encodings.push_back(pseudoEncodingExtendedDesktopSize); diff --git a/common/rfb/CConnection.h b/common/rfb/CConnection.h index deab50ae52..d5d07ca0b0 100644 --- a/common/rfb/CConnection.h +++ b/common/rfb/CConnection.h @@ -239,6 +239,7 @@ namespace rfb { // Optional capabilities that a subclass is expected to set to true // if supported bool supportsLocalCursor; + bool supportsCursorPosition; bool supportsDesktopResize; bool supportsLEDState; diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h index 5b14806ad1..43d8df246a 100644 --- a/common/rfb/CMsgHandler.h +++ b/common/rfb/CMsgHandler.h @@ -52,6 +52,7 @@ namespace rfb { const ScreenSet& layout); virtual void setCursor(int width, int height, const Point& hotspot, const rdr::U8* data) = 0; + virtual void setCursorPos(const Point& pos) = 0; virtual void setPixelFormat(const PixelFormat& pf); virtual void setName(const char* name); virtual void fence(rdr::U32 flags, unsigned len, const char data[]); diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx index 40fb5912a1..3620d76c80 100644 --- a/common/rfb/CMsgReader.cxx +++ b/common/rfb/CMsgReader.cxx @@ -165,6 +165,10 @@ bool CMsgReader::readMsg() case pseudoEncodingVMwareCursor: ret = readSetVMwareCursor(dataRect.width(), dataRect.height(), dataRect.tl); break; + case pseudoEncodingVMwareCursorPosition: + handler->setCursorPos(dataRect.tl); + ret = true; + break; case pseudoEncodingDesktopName: ret = readSetDesktopName(dataRect.tl.x, dataRect.tl.y, dataRect.width(), dataRect.height()); diff --git a/tests/perf/decperf.cxx b/tests/perf/decperf.cxx index a6c65a221d..23f3fe24a3 100644 --- a/tests/perf/decperf.cxx +++ b/tests/perf/decperf.cxx @@ -66,6 +66,7 @@ class CConn : public rfb::CConnection { virtual void initDone(); virtual void setPixelFormat(const rfb::PixelFormat& pf); virtual void setCursor(int, int, const rfb::Point&, const rdr::U8*); + virtual void setCursorPos(const rfb::Point&); virtual void framebufferUpdateStart(); virtual void framebufferUpdateEnd(); virtual void setColourMapEntries(int, int, rdr::U16*); @@ -144,6 +145,10 @@ void CConn::setCursor(int, int, const rfb::Point&, const rdr::U8*) { } +void CConn::setCursorPos(const rfb::Point&) +{ +} + void CConn::framebufferUpdateStart() { CConnection::framebufferUpdateStart(); diff --git a/tests/perf/encperf.cxx b/tests/perf/encperf.cxx index 9f30cab7ab..69121ffa4d 100644 --- a/tests/perf/encperf.cxx +++ b/tests/perf/encperf.cxx @@ -95,6 +95,7 @@ class CConn : public rfb::CConnection { virtual void initDone() {}; virtual void resizeFramebuffer(); virtual void setCursor(int, int, const rfb::Point&, const rdr::U8*); + virtual void setCursorPos(const rfb::Point&); virtual void framebufferUpdateStart(); virtual void framebufferUpdateEnd(); virtual bool dataRect(const rfb::Rect&, int); @@ -216,6 +217,10 @@ void CConn::setCursor(int, int, const rfb::Point&, const rdr::U8*) { } +void CConn::setCursorPos(const rfb::Point&) +{ +} + void CConn::framebufferUpdateStart() { CConnection::framebufferUpdateStart(); diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx index 4894ddf78e..e1f5f70a27 100644 --- a/vncviewer/CConn.cxx +++ b/vncviewer/CConn.cxx @@ -84,6 +84,7 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=NULL) sock = socket; supportsLocalCursor = true; + supportsCursorPosition = true; supportsDesktopResize = true; supportsLEDState = false; @@ -430,6 +431,11 @@ void CConn::setCursor(int width, int height, const Point& hotspot, desktop->setCursor(width, height, hotspot, data); } +void CConn::setCursorPos(const Point& pos) +{ + desktop->setCursorPos(pos); +} + void CConn::fence(rdr::U32 flags, unsigned len, const char data[]) { CMsgHandler::fence(flags, len, data); diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h index ad3fb797bb..e662ec8726 100644 --- a/vncviewer/CConn.h +++ b/vncviewer/CConn.h @@ -63,6 +63,7 @@ class CConn : public rfb::CConnection void setCursor(int width, int height, const rfb::Point& hotspot, const rdr::U8* data); + void setCursorPos(const rfb::Point& pos); void fence(rdr::U32 flags, unsigned len, const char data[]); diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx index 6dc85f4a9e..2866946ae4 100644 --- a/vncviewer/DesktopWindow.cxx +++ b/vncviewer/DesktopWindow.cxx @@ -51,6 +51,7 @@ #ifdef __APPLE__ #include "cocoa.h" +#include #endif #define EDGE_SCROLL_SIZE 32 @@ -322,6 +323,27 @@ void DesktopWindow::setCursor(int width, int height, } +void DesktopWindow::setCursorPos(const rfb::Point& pos) +{ + if (!mouseGrabbed) { + // Do nothing if we do not have the mouse captured. + return; + } +#if defined(WIN32) + SetCursorPos(pos.x, pos.y); +#elif defined(__APPLE__) + CGPoint new_pos; + new_pos.x = pos.x; + new_pos.y = pos.y; + CGWarpMouseCursorPosition(new_pos); +#else // Assume this is Xlib + Window rootwindow = DefaultRootWindow(fl_display); + XWarpPointer(fl_display, rootwindow, rootwindow, 0, 0, 0, 0, + pos.x, pos.y); +#endif +} + + void DesktopWindow::show() { Fl_Window::show(); diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h index ef3dbb08ec..67be6c6a88 100644 --- a/vncviewer/DesktopWindow.h +++ b/vncviewer/DesktopWindow.h @@ -66,6 +66,9 @@ class DesktopWindow : public Fl_Window { void setCursor(int width, int height, const rfb::Point& hotspot, const rdr::U8* data); + // Server-provided cursor position + void setCursorPos(const rfb::Point& pos); + // Change client LED state void setLEDState(unsigned int state);