aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Halim <adaha@cendio.se>2024-10-04 10:09:36 +0200
committerAdam Halim <adaha@cendio.se>2024-10-22 14:52:36 +0200
commitc40d8a4debbfbf98045ef25fcac91672f0cc1049 (patch)
treea83dcaf1dad87039047a8a45ec2a49a47646325e
parent66287bd933e1d5426b7b6108afcc42ac9b3440a5 (diff)
downloadtigervnc-c40d8a4debbfbf98045ef25fcac91672f0cc1049.tar.gz
tigervnc-c40d8a4debbfbf98045ef25fcac91672f0cc1049.zip
vncviewer: support for back/forward mouse buttons
This commit implements the pseudo-encoding ExtendedMouseButtons which makes it possible to use the back/forward mouse buttons. This commit contains work originally done by PixelSmith <manny33@frontbuffer.com>.
-rw-r--r--common/rfb/CConnection.cxx1
-rw-r--r--common/rfb/CMsgHandler.cxx5
-rw-r--r--common/rfb/CMsgHandler.h1
-rw-r--r--common/rfb/CMsgReader.cxx4
-rw-r--r--common/rfb/CMsgWriter.cxx38
-rw-r--r--common/rfb/CMsgWriter.h2
-rw-r--r--common/rfb/ServerParams.cxx2
-rw-r--r--common/rfb/ServerParams.h1
-rw-r--r--tests/unit/emulatemb.cxx6
-rw-r--r--vncviewer/EmulateMB.cxx8
-rw-r--r--vncviewer/EmulateMB.h12
-rw-r--r--vncviewer/Viewport.cxx20
-rw-r--r--vncviewer/Viewport.h6
13 files changed, 82 insertions, 24 deletions
diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx
index b4017dba..a6763c05 100644
--- a/common/rfb/CConnection.cxx
+++ b/common/rfb/CConnection.cxx
@@ -835,6 +835,7 @@ void CConnection::updateEncodings()
encodings.push_back(pseudoEncodingContinuousUpdates);
encodings.push_back(pseudoEncodingFence);
encodings.push_back(pseudoEncodingQEMUKeyEvent);
+ encodings.push_back(pseudoEncodingExtendedMouseButtons);
if (Decoder::supported(preferredEncoding)) {
encodings.push_back(preferredEncoding);
diff --git a/common/rfb/CMsgHandler.cxx b/common/rfb/CMsgHandler.cxx
index 4489dbd4..0f3f6cd5 100644
--- a/common/rfb/CMsgHandler.cxx
+++ b/common/rfb/CMsgHandler.cxx
@@ -75,6 +75,11 @@ void CMsgHandler::endOfContinuousUpdates()
server.supportsContinuousUpdates = true;
}
+void CMsgHandler::supportsExtendedMouseButtons()
+{
+ server.supportsExtendedMouseButtons = true;
+}
+
void CMsgHandler::supportsQEMUKeyEvent()
{
server.supportsQEMUKeyEvent = true;
diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h
index 9e5f7de2..b484b695 100644
--- a/common/rfb/CMsgHandler.h
+++ b/common/rfb/CMsgHandler.h
@@ -57,6 +57,7 @@ namespace rfb {
virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]);
virtual void endOfContinuousUpdates();
virtual void supportsQEMUKeyEvent();
+ virtual void supportsExtendedMouseButtons();
virtual void serverInit(int width, int height,
const PixelFormat& pf,
const char* name) = 0;
diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx
index 8bcdbfd0..d7cbc2fd 100644
--- a/common/rfb/CMsgReader.cxx
+++ b/common/rfb/CMsgReader.cxx
@@ -202,6 +202,10 @@ bool CMsgReader::readMsg()
handler->supportsQEMUKeyEvent();
ret = true;
break;
+ case pseudoEncodingExtendedMouseButtons:
+ handler->supportsExtendedMouseButtons();
+ ret = true;
+ break;
default:
ret = readRect(dataRect, rectEncoding);
break;
diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx
index 1bd8040f..8c379d66 100644
--- a/common/rfb/CMsgWriter.cxx
+++ b/common/rfb/CMsgWriter.cxx
@@ -22,6 +22,7 @@
#endif
#include <stdio.h>
+#include <assert.h>
#include <rdr/OutStream.h>
#include <rdr/MemOutStream.h>
@@ -173,18 +174,47 @@ void CMsgWriter::writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down)
}
-void CMsgWriter::writePointerEvent(const Point& pos, uint8_t buttonMask)
+void CMsgWriter::writePointerEvent(const Point& pos, uint16_t buttonMask)
{
Point p(pos);
+ bool extendedMouseButtons;
+
if (p.x < 0) p.x = 0;
if (p.y < 0) p.y = 0;
if (p.x >= server->width()) p.x = server->width() - 1;
if (p.y >= server->height()) p.y = server->height() - 1;
+ /* The highest bit in buttonMask is never sent to the server */
+ assert(!(buttonMask & 0x8000));
+
+ /* Only send extended pointerEvent message when needed */
+ extendedMouseButtons = buttonMask & 0x7f80;
+
startMsg(msgTypePointerEvent);
- os->writeU8(buttonMask);
- os->writeU16(p.x);
- os->writeU16(p.y);
+ if (server->supportsExtendedMouseButtons && extendedMouseButtons) {
+ int higherBits;
+ int lowerBits;
+
+ higherBits = (buttonMask >> 7) & 0xff;
+ assert(!(higherBits & 0xfc)); /* Bits 2-7 are reserved */
+
+ lowerBits = buttonMask & 0x7f;
+ lowerBits |= 0x80; /* Set marker bit to 1 */
+
+ os->writeU8(lowerBits);
+ os->writeU16(p.x);
+ os->writeU16(p.y);
+ os->writeU8(higherBits);
+ } else {
+ /* Marker bit must be set to 0, otherwise the server might confuse
+ * the marker bit with the highest bit in a normal PointerEvent
+ * message.
+ */
+ buttonMask &= 0x7f;
+ os->writeU8(buttonMask);
+ os->writeU16(p.x);
+ os->writeU16(p.y);
+ }
endMsg();
}
diff --git a/common/rfb/CMsgWriter.h b/common/rfb/CMsgWriter.h
index 61df567f..9cb4adec 100644
--- a/common/rfb/CMsgWriter.h
+++ b/common/rfb/CMsgWriter.h
@@ -54,7 +54,7 @@ namespace rfb {
void writeFence(uint32_t flags, unsigned len, const uint8_t data[]);
void writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down);
- void writePointerEvent(const Point& pos, uint8_t buttonMask);
+ void writePointerEvent(const Point& pos, uint16_t buttonMask);
void writeClientCutText(const char* str);
diff --git a/common/rfb/ServerParams.cxx b/common/rfb/ServerParams.cxx
index 9f6f5307..7c596036 100644
--- a/common/rfb/ServerParams.cxx
+++ b/common/rfb/ServerParams.cxx
@@ -32,7 +32,7 @@ ServerParams::ServerParams()
: majorVersion(0), minorVersion(0),
supportsQEMUKeyEvent(false),
supportsSetDesktopSize(false), supportsFence(false),
- supportsContinuousUpdates(false),
+ supportsContinuousUpdates(false), supportsExtendedMouseButtons(false),
width_(0), height_(0),
ledState_(ledUnknown)
{
diff --git a/common/rfb/ServerParams.h b/common/rfb/ServerParams.h
index 791e3e7f..d730b891 100644
--- a/common/rfb/ServerParams.h
+++ b/common/rfb/ServerParams.h
@@ -79,6 +79,7 @@ namespace rfb {
bool supportsSetDesktopSize;
bool supportsFence;
bool supportsContinuousUpdates;
+ bool supportsExtendedMouseButtons;
private:
diff --git a/tests/unit/emulatemb.cxx b/tests/unit/emulatemb.cxx
index ae022c06..6db8ea38 100644
--- a/tests/unit/emulatemb.cxx
+++ b/tests/unit/emulatemb.cxx
@@ -42,14 +42,14 @@ rfb::BoolParameter emulateMiddleButton("dummy_name", "dummy_desc", true);
class TestClass : public EmulateMB
{
public:
- void sendPointerEvent(const rfb::Point& pos, uint8_t buttonMask) override;
+ void sendPointerEvent(const rfb::Point& pos, uint16_t buttonMask) override;
- struct PointerEventParams {rfb::Point pos; uint8_t mask; };
+ struct PointerEventParams {rfb::Point pos; uint16_t mask; };
std::vector<PointerEventParams> results;
};
-void TestClass::sendPointerEvent(const rfb::Point& pos, uint8_t buttonMask)
+void TestClass::sendPointerEvent(const rfb::Point& pos, uint16_t buttonMask)
{
PointerEventParams params;
params.pos = pos;
diff --git a/vncviewer/EmulateMB.cxx b/vncviewer/EmulateMB.cxx
index fef8b3d9..ef19ace4 100644
--- a/vncviewer/EmulateMB.cxx
+++ b/vncviewer/EmulateMB.cxx
@@ -199,7 +199,7 @@ EmulateMB::EmulateMB()
{
}
-void EmulateMB::filterPointerEvent(const rfb::Point& pos, uint8_t buttonMask)
+void EmulateMB::filterPointerEvent(const rfb::Point& pos, uint16_t buttonMask)
{
int btstate;
int action1, action2;
@@ -280,7 +280,7 @@ void EmulateMB::filterPointerEvent(const rfb::Point& pos, uint8_t buttonMask)
void EmulateMB::handleTimeout(rfb::Timer *t)
{
int action1, action2;
- uint8_t buttonMask;
+ uint16_t buttonMask;
if (&timer != t)
return;
@@ -312,7 +312,7 @@ void EmulateMB::handleTimeout(rfb::Timer *t)
state = stateTab[state][4][2];
}
-void EmulateMB::sendAction(const rfb::Point& pos, uint8_t buttonMask, int action)
+void EmulateMB::sendAction(const rfb::Point& pos, uint16_t buttonMask, int action)
{
assert(action != 0);
@@ -325,7 +325,7 @@ void EmulateMB::sendAction(const rfb::Point& pos, uint8_t buttonMask, int action
sendPointerEvent(pos, buttonMask);
}
-int EmulateMB::createButtonMask(uint8_t buttonMask)
+int EmulateMB::createButtonMask(uint16_t buttonMask)
{
// Unset left and right buttons in the mask
buttonMask &= ~0x5;
diff --git a/vncviewer/EmulateMB.h b/vncviewer/EmulateMB.h
index 1afa4881..127c34a4 100644
--- a/vncviewer/EmulateMB.h
+++ b/vncviewer/EmulateMB.h
@@ -26,22 +26,22 @@ class EmulateMB : public rfb::Timer::Callback {
public:
EmulateMB();
- void filterPointerEvent(const rfb::Point& pos, uint8_t buttonMask);
+ void filterPointerEvent(const rfb::Point& pos, uint16_t buttonMask);
protected:
- virtual void sendPointerEvent(const rfb::Point& pos, uint8_t buttonMask)=0;
+ virtual void sendPointerEvent(const rfb::Point& pos, uint16_t buttonMask)=0;
void handleTimeout(rfb::Timer *t) override;
private:
- void sendAction(const rfb::Point& pos, uint8_t buttonMask, int action);
+ void sendAction(const rfb::Point& pos, uint16_t buttonMask, int action);
- int createButtonMask(uint8_t buttonMask);
+ int createButtonMask(uint16_t buttonMask);
private:
int state;
- uint8_t emulatedButtonMask;
- uint8_t lastButtonMask;
+ uint16_t emulatedButtonMask;
+ uint16_t lastButtonMask;
rfb::Point lastPos, origPos;
rfb::Timer timer;
};
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 9d71a859..6cda65e9 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -606,6 +606,20 @@ int Viewport::handle(int event)
if (Fl::event_button3())
buttonMask |= 1 << 2;
+ // The back/forward buttons are not supported by FTLK 1.3 and require
+ // a patch which adds these buttons to the FLTK API. These buttons
+ // will be part of the upcoming 1.4 API:
+ // * https://github.com/fltk/fltk/pull/1081
+ //
+ // A backport for branch-1.3 is available here:
+ // * https://github.com/fltk/fltk/pull/1083
+#if defined(FL_BUTTON4) && defined(FL_BUTTON5)
+ if (Fl::event_button4())
+ buttonMask |= 1 << 7;
+ if (Fl::event_button5())
+ buttonMask |= 1 << 8;
+#endif
+
if (event == FL_MOUSEWHEEL) {
wheelMask = 0;
if (Fl::event_dy() < 0)
@@ -660,7 +674,7 @@ int Viewport::handle(int event)
return Fl_Widget::handle(event);
}
-void Viewport::sendPointerEvent(const rfb::Point& pos, uint8_t buttonMask)
+void Viewport::sendPointerEvent(const rfb::Point& pos, uint16_t buttonMask)
{
if (viewOnly)
return;
@@ -790,7 +804,7 @@ void Viewport::flushPendingClipboard()
}
-void Viewport::handlePointerEvent(const rfb::Point& pos, uint8_t buttonMask)
+void Viewport::handlePointerEvent(const rfb::Point& pos, uint16_t buttonMask)
{
filterPointerEvent(pos, buttonMask);
}
@@ -937,6 +951,8 @@ int Viewport::handleSystemEvent(void *event, void *data)
(msg->message == WM_RBUTTONUP) ||
(msg->message == WM_MBUTTONDOWN) ||
(msg->message == WM_MBUTTONUP) ||
+ (msg->message == WM_XBUTTONDOWN) ||
+ (msg->message == WM_XBUTTONUP) ||
(msg->message == WM_MOUSEWHEEL) ||
(msg->message == WM_MOUSEHWHEEL)) {
// We can't get a mouse event in the middle of an AltGr sequence, so
diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h
index 5f4c1ca7..c5222a88 100644
--- a/vncviewer/Viewport.h
+++ b/vncviewer/Viewport.h
@@ -70,7 +70,7 @@ public:
int handle(int event) override;
protected:
- void sendPointerEvent(const rfb::Point& pos, uint8_t buttonMask) override;
+ void sendPointerEvent(const rfb::Point& pos, uint16_t buttonMask) override;
private:
bool hasFocus();
@@ -81,7 +81,7 @@ private:
void flushPendingClipboard();
- void handlePointerEvent(const rfb::Point& pos, uint8_t buttonMask);
+ void handlePointerEvent(const rfb::Point& pos, uint16_t buttonMask);
static void handlePointerTimeout(void *data);
void resetKeyboard();
@@ -111,7 +111,7 @@ private:
PlatformPixelBuffer* frameBuffer;
rfb::Point lastPointerPos;
- uint8_t lastButtonMask;
+ uint16_t lastButtonMask;
typedef std::map<int, uint32_t> DownMap;
DownMap downKeySym;