From 63ea8b2461381d779dfacb3d919f60279daf95dc Mon Sep 17 00:00:00 2001 From: PixelSmith Date: Thu, 28 Dec 2023 14:24:15 -0600 Subject: [PATCH 1/3] Added the abillity for vnc to use 9 mouse buttons instead of 7. This adds the Xinput device buttons back and forward for the mouse. Both Client and server message reader and writters as well as connections signal their support for the extra mouse buttons. The client signals the server through support of a psuedo encoding "pseudoEncodingExtendedMouseButtons". The server responds with a server message "msgTypeExtendedMouseSupport". Not sure if this is the best way to do this. After confirming both both client and server support the extended mouse button msg, the client starts sending new message with a u16 write instead of a u8. The button layout doesn't change to maintain support for clients that don't support more mouse buttons. --- common/rfb/CConnection.cxx | 2 ++ common/rfb/CMsgHandler.cxx | 5 +++++ common/rfb/CMsgHandler.h | 1 + common/rfb/CMsgReader.cxx | 9 +++++++++ common/rfb/CMsgReader.h | 1 + common/rfb/CMsgWriter.cxx | 15 +++++++++++++++ common/rfb/CMsgWriter.h | 1 + common/rfb/ClientParams.cxx | 7 +++++++ common/rfb/ClientParams.h | 1 + common/rfb/SConnection.cxx | 5 +++++ common/rfb/SConnection.h | 2 ++ common/rfb/SMsgHandler.cxx | 6 ++++++ common/rfb/SMsgHandler.h | 5 +++++ common/rfb/SMsgReader.cxx | 13 +++++++++++++ common/rfb/SMsgReader.h | 1 + common/rfb/SMsgWriter.cxx | 9 +++++++++ common/rfb/SMsgWriter.h | 3 +++ common/rfb/ServerParams.cxx | 2 +- common/rfb/ServerParams.h | 1 + common/rfb/encodings.h | 1 + common/rfb/msgTypes.h | 4 ++++ java/com/tigervnc/rfb/CConnection.java | 8 ++++++++ java/com/tigervnc/rfb/CMsgHandler.java | 5 +++++ java/com/tigervnc/rfb/CMsgReader.java | 8 ++++++++ java/com/tigervnc/rfb/CMsgWriter.java | 15 +++++++++++++++ java/com/tigervnc/rfb/Encodings.java | 1 + java/com/tigervnc/rfb/MsgTypes.java | 3 +++ java/com/tigervnc/rfb/ServerParams.java | 7 ++++++- java/com/tigervnc/vncviewer/Viewport.java | 10 ++++++++++ unix/xserver/hw/vnc/vncInput.c | 5 ++++- vncviewer/Viewport.cxx | 5 +++++ 31 files changed, 158 insertions(+), 3 deletions(-) diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx index 0f4fc4f887..3d7da3f705 100644 --- a/common/rfb/CConnection.cxx +++ b/common/rfb/CConnection.cxx @@ -860,5 +860,7 @@ void CConnection::updateEncodings() if (qualityLevel >= 0 && qualityLevel <= 9) encodings.push_back(pseudoEncodingQualityLevel0 + qualityLevel); + encodings.push_back(pseudoEncodingExtendedMouseButtons); + writer()->writeSetEncodings(encodings); } diff --git a/common/rfb/CMsgHandler.cxx b/common/rfb/CMsgHandler.cxx index c3594af9ed..db928d47fc 100644 --- a/common/rfb/CMsgHandler.cxx +++ b/common/rfb/CMsgHandler.cxx @@ -80,6 +80,11 @@ void CMsgHandler::endOfContinuousUpdates() server.supportsContinuousUpdates = true; } +void CMsgHandler::supportExtendedMouseButtons() +{ + server.supportsExtendedMouseButtons = true; +} + void CMsgHandler::supportsQEMUKeyEvent() { server.supportsQEMUKeyEvent = true; diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h index 16a53c6a60..ce7e005751 100644 --- a/common/rfb/CMsgHandler.h +++ b/common/rfb/CMsgHandler.h @@ -58,6 +58,7 @@ namespace rfb { virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]); virtual void endOfContinuousUpdates(); virtual void supportsQEMUKeyEvent(); + virtual void supportExtendedMouseButtons(); 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 006645df42..c1c6ad17c3 100644 --- a/common/rfb/CMsgReader.cxx +++ b/common/rfb/CMsgReader.cxx @@ -118,6 +118,9 @@ bool CMsgReader::readMsg() case msgTypeEndOfContinuousUpdates: ret = readEndOfContinuousUpdates(); break; + case msgTypeExtendedMouseSupport: + ret = readSupportExtendedMouseButton(); + break; default: throw Exception("Unknown message type %d", currentMsgType); } @@ -454,6 +457,12 @@ bool CMsgReader::readEndOfContinuousUpdates() return true; } +bool CMsgReader::readSupportExtendedMouseButton() +{ + handler->supportExtendedMouseButtons(); + return true; +} + bool CMsgReader::readFramebufferUpdate() { if (!is->hasData(1 + 2)) diff --git a/common/rfb/CMsgReader.h b/common/rfb/CMsgReader.h index 3b1c0ddbd6..8000762bc4 100644 --- a/common/rfb/CMsgReader.h +++ b/common/rfb/CMsgReader.h @@ -56,6 +56,7 @@ namespace rfb { bool readExtendedClipboard(int32_t len); bool readFence(); bool readEndOfContinuousUpdates(); + bool readSupportExtendedMouseButton(); bool readFramebufferUpdate(); diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx index e941aaa7eb..8ba87e801f 100644 --- a/common/rfb/CMsgWriter.cxx +++ b/common/rfb/CMsgWriter.cxx @@ -182,6 +182,12 @@ void CMsgWriter::writePointerEvent(const Point& pos, int buttonMask) if (p.x >= server->width()) p.x = server->width() - 1; if (p.y >= server->height()) p.y = server->height() - 1; + if (server->supportsExtendedMouseButtons) + { + writePointerEventExt(pos,buttonMask); + return; + } + startMsg(msgTypePointerEvent); os->writeU8(buttonMask); os->writeU16(p.x); @@ -189,6 +195,15 @@ void CMsgWriter::writePointerEvent(const Point& pos, int buttonMask) endMsg(); } +void CMsgWriter::writePointerEventExt(const Point& p, int buttonMask) +{ + startMsg(msgTypePointerEventExt); + os->writeU16(buttonMask); + os->writeU16(p.x); + os->writeU16(p.y); + endMsg(); +} + void CMsgWriter::writeClientCutText(const char* str) { diff --git a/common/rfb/CMsgWriter.h b/common/rfb/CMsgWriter.h index 1b70a1d011..1b76c1da65 100644 --- a/common/rfb/CMsgWriter.h +++ b/common/rfb/CMsgWriter.h @@ -55,6 +55,7 @@ namespace rfb { void writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down); void writePointerEvent(const Point& pos, int buttonMask); + void writePointerEventExt(const Point& pos, int buttonMask); void writeClientCutText(const char* str); diff --git a/common/rfb/ClientParams.cxx b/common/rfb/ClientParams.cxx index ade990181c..14524ac415 100644 --- a/common/rfb/ClientParams.cxx +++ b/common/rfb/ClientParams.cxx @@ -228,3 +228,10 @@ bool ClientParams::supportsContinuousUpdates() const return true; return false; } + +bool ClientParams::supportExtendedMouseButtons() const +{ + if (supportsEncoding(pseudoEncodingExtendedMouseButtons)) + return true; + return false; +} \ No newline at end of file diff --git a/common/rfb/ClientParams.h b/common/rfb/ClientParams.h index ea86ea785d..156c69bce3 100644 --- a/common/rfb/ClientParams.h +++ b/common/rfb/ClientParams.h @@ -101,6 +101,7 @@ namespace rfb { bool supportsLEDState() const; bool supportsFence() const; bool supportsContinuousUpdates() const; + bool supportExtendedMouseButtons() const; int compressLevel; int qualityLevel; diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx index 33b2d850e6..a2d8e9d5be 100644 --- a/common/rfb/SConnection.cxx +++ b/common/rfb/SConnection.cxx @@ -446,6 +446,11 @@ void SConnection::supportsQEMUKeyEvent() writer()->writeQEMUKeyEvent(); } +void SConnection::supportsExtendedMouseButtons() +{ + writer()->writeExtendedMouseButtonSupport(); +} + void SConnection::versionReceived() { } diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h index b163d6273e..445e0707b8 100644 --- a/common/rfb/SConnection.h +++ b/common/rfb/SConnection.h @@ -95,6 +95,8 @@ namespace rfb { virtual void supportsQEMUKeyEvent(); + virtual void supportsExtendedMouseButtons() override; + // Methods to be overridden in a derived class diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx index 4ecfc2b2fc..972620707b 100644 --- a/common/rfb/SMsgHandler.cxx +++ b/common/rfb/SMsgHandler.cxx @@ -72,6 +72,8 @@ void SMsgHandler::setEncodings(int nEncodings, const int32_t* encodings) supportsLEDState(); if (client.supportsEncoding(pseudoEncodingQEMUKeyEvent) && firstQEMUKeyEvent) supportsQEMUKeyEvent(); + if (client.supportsEncoding(pseudoEncodingExtendedMouseButtons)) + supportsExtendedMouseButtons(); } void SMsgHandler::handleClipboardCaps(uint32_t flags, const uint32_t* lengths) @@ -153,3 +155,7 @@ void SMsgHandler::supportsLEDState() void SMsgHandler::supportsQEMUKeyEvent() { } + +void SMsgHandler::supportsExtendedMouseButtons() +{ +} \ No newline at end of file diff --git a/common/rfb/SMsgHandler.h b/common/rfb/SMsgHandler.h index 20dc066f28..26f1bc9c9c 100644 --- a/common/rfb/SMsgHandler.h +++ b/common/rfb/SMsgHandler.h @@ -95,6 +95,11 @@ namespace rfb { // handler will send a pseudo-rect back, signalling server support. virtual void supportsQEMUKeyEvent(); + // supportsExtendedMouseButtons() is called the first time we detect that the + // client supports sending 16 bit mouse button state. This lets us pass more button + // states between server and client. + virtual void supportsExtendedMouseButtons(); + ClientParams client; }; } diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx index 0792639a2e..cdb284d242 100644 --- a/common/rfb/SMsgReader.cxx +++ b/common/rfb/SMsgReader.cxx @@ -99,6 +99,9 @@ bool SMsgReader::readMsg() case msgTypePointerEvent: ret = readPointerEvent(); break; + case msgTypePointerEventExt: + ret = readPointerEvenExt(); + break; case msgTypeClientCutText: ret = readClientCutText(); break; @@ -281,6 +284,16 @@ bool SMsgReader::readPointerEvent() return true; } +bool SMsgReader::readPointerEvenExt() +{ + if (!is->hasData(2 + 2 + 2)) + return false; + int mask = is->readU16(); + int x = is->readU16(); + int y = is->readU16(); + handler->pointerEvent(Point(x, y), mask); + return true; +} bool SMsgReader::readClientCutText() { diff --git a/common/rfb/SMsgReader.h b/common/rfb/SMsgReader.h index f99b6627d5..0a5b287d9d 100644 --- a/common/rfb/SMsgReader.h +++ b/common/rfb/SMsgReader.h @@ -53,6 +53,7 @@ namespace rfb { bool readKeyEvent(); bool readPointerEvent(); + bool readPointerEvenExt(); bool readClientCutText(); bool readExtendedClipboard(int32_t len); diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx index 8592e6f4b8..39ce3699e8 100644 --- a/common/rfb/SMsgWriter.cxx +++ b/common/rfb/SMsgWriter.cxx @@ -303,6 +303,15 @@ void SMsgWriter::writeQEMUKeyEvent() needQEMUKeyEvent = true; } +void SMsgWriter::writeExtendedMouseButtonSupport() +{ + if (!client->supportsEncoding(pseudoEncodingExtendedMouseButtons)) + throw Exception("Client does not support Extended Mouse Buttons"); + + startMsg(msgTypeExtendedMouseSupport); + endMsg(); +} + bool SMsgWriter::needFakeUpdate() { if (needSetDesktopName) diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h index c46551e9a8..71cf2bbe45 100644 --- a/common/rfb/SMsgWriter.h +++ b/common/rfb/SMsgWriter.h @@ -93,6 +93,9 @@ namespace rfb { // And QEMU keyboard event handshake void writeQEMUKeyEvent(); + // let the client know we support extended mouse button support + void writeExtendedMouseButtonSupport(); + // needFakeUpdate() returns true when an immediate update is needed in // order to flush out pseudo-rectangles to the client. bool needFakeUpdate(); diff --git a/common/rfb/ServerParams.cxx b/common/rfb/ServerParams.cxx index 6af446c212..82fd73b911 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 791e3e7f33..d730b89139 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/common/rfb/encodings.h b/common/rfb/encodings.h index e427572f6f..fca4e59bf3 100644 --- a/common/rfb/encodings.h +++ b/common/rfb/encodings.h @@ -36,6 +36,7 @@ namespace rfb { const int pseudoEncodingXCursor = -240; const int pseudoEncodingCursor = -239; + const int pseudoEncodingExtendedMouseButtons = -241; const int pseudoEncodingDesktopSize = -223; const int pseudoEncodingLEDState = -261; const int pseudoEncodingExtendedDesktopSize = -308; diff --git a/common/rfb/msgTypes.h b/common/rfb/msgTypes.h index a17493cd80..e2bc3423f0 100644 --- a/common/rfb/msgTypes.h +++ b/common/rfb/msgTypes.h @@ -28,6 +28,8 @@ namespace rfb { const int msgTypeEndOfContinuousUpdates = 150; + const int msgTypeExtendedMouseSupport = 151; + const int msgTypeServerFence = 248; // client to server @@ -39,6 +41,8 @@ namespace rfb { const int msgTypeKeyEvent = 4; const int msgTypePointerEvent = 5; const int msgTypeClientCutText = 6; + const int msgTypePointerEventExt = 7; + const int msgTypeEnableContinuousUpdates = 150; diff --git a/java/com/tigervnc/rfb/CConnection.java b/java/com/tigervnc/rfb/CConnection.java index e0e669d886..dbca561aa6 100644 --- a/java/com/tigervnc/rfb/CConnection.java +++ b/java/com/tigervnc/rfb/CConnection.java @@ -403,6 +403,12 @@ public void endOfContinuousUpdates() requestNewUpdate(); } } + + public void SupportExtendedMouseButton() + { + super.SupportExtendedMouseButton(); + } + // serverInit() is called when the ServerInit message is received. The // derived class must call on to CConnection::serverInit(). public void serverInit(int width, int height, @@ -683,6 +689,8 @@ private void updateEncodings() encodings.add(Encodings.pseudoEncodingLastRect); encodings.add(Encodings.pseudoEncodingContinuousUpdates); encodings.add(Encodings.pseudoEncodingFence); + encodings.add(Encodings.pseudoEncodingExtendedMouseButtons); + if (Decoder.supported(preferredEncoding)) { encodings.add(preferredEncoding); diff --git a/java/com/tigervnc/rfb/CMsgHandler.java b/java/com/tigervnc/rfb/CMsgHandler.java index 5b62f961ba..d29f25dab1 100644 --- a/java/com/tigervnc/rfb/CMsgHandler.java +++ b/java/com/tigervnc/rfb/CMsgHandler.java @@ -73,6 +73,11 @@ public void endOfContinuousUpdates() server.supportsContinuousUpdates = true; } + public void SupportExtendedMouseButton() + { + server.supportsExtendedMouseButtons = true; + } + abstract public void clientRedirect(int port, String host, String x509subject); diff --git a/java/com/tigervnc/rfb/CMsgReader.java b/java/com/tigervnc/rfb/CMsgReader.java index c71a1e02f6..2289535d89 100644 --- a/java/com/tigervnc/rfb/CMsgReader.java +++ b/java/com/tigervnc/rfb/CMsgReader.java @@ -80,6 +80,9 @@ public void readMsg() case MsgTypes.msgTypeEndOfContinuousUpdates: readEndOfContinuousUpdates(); break; + case MsgTypes.msgTypeExtendedMouseSupport: + readSupportExtendedMouseButton(); + break; default: vlog.error("unknown message type "+type); throw new Exception("unknown message type"); @@ -192,6 +195,11 @@ protected void readEndOfContinuousUpdates() handler.endOfContinuousUpdates(); } + protected void readSupportExtendedMouseButton() + { + handler.SupportExtendedMouseButton(); + } + protected void readFramebufferUpdate() { is.skip(1); diff --git a/java/com/tigervnc/rfb/CMsgWriter.java b/java/com/tigervnc/rfb/CMsgWriter.java index f89e40d4b0..27a24ee2c0 100644 --- a/java/com/tigervnc/rfb/CMsgWriter.java +++ b/java/com/tigervnc/rfb/CMsgWriter.java @@ -150,6 +150,12 @@ synchronized public void writePointerEvent(Point pos, int buttonMask) if (p.x >= server.width()) p.x = server.width() - 1; if (p.y >= server.height()) p.y = server.height() - 1; + if(server.supportsExtendedMouseButtons) + { + writePointerEventExt(pos,buttonMask); + return; + } + startMsg(MsgTypes.msgTypePointerEvent); os.writeU8(buttonMask); os.writeU16(p.x); @@ -157,6 +163,15 @@ synchronized public void writePointerEvent(Point pos, int buttonMask) endMsg(); } + synchronized public void writePointerEventExt(Point p, int buttonMask) + { + startMsg(MsgTypes.msgTypePointerEventExt); + os.writeU16(buttonMask); + os.writeU16(p.x); + os.writeU16(p.y); + endMsg(); + } + synchronized public void writeClientCutText(String str, int len) { startMsg(MsgTypes.msgTypeClientCutText); diff --git a/java/com/tigervnc/rfb/Encodings.java b/java/com/tigervnc/rfb/Encodings.java index d9b713bc2a..e869b18684 100644 --- a/java/com/tigervnc/rfb/Encodings.java +++ b/java/com/tigervnc/rfb/Encodings.java @@ -34,6 +34,7 @@ public class Encodings { public static final int pseudoEncodingXCursor = -240; public static final int pseudoEncodingCursor = -239; + public static final int pseudoEncodingExtendedMouseButtons = -241; public static final int pseudoEncodingDesktopSize = -223; public static final int pseudoEncodingExtendedDesktopSize = -308; public static final int pseudoEncodingDesktopName = -307; diff --git a/java/com/tigervnc/rfb/MsgTypes.java b/java/com/tigervnc/rfb/MsgTypes.java index c12f38deb0..332be38ebf 100644 --- a/java/com/tigervnc/rfb/MsgTypes.java +++ b/java/com/tigervnc/rfb/MsgTypes.java @@ -29,6 +29,8 @@ public class MsgTypes { public static final int msgTypeEndOfContinuousUpdates = 150; + public static final int msgTypeExtendedMouseSupport = 151; + public static final int msgTypeServerFence = 248; // client to server @@ -40,6 +42,7 @@ public class MsgTypes { public static final int msgTypeKeyEvent = 4; public static final int msgTypePointerEvent = 5; public static final int msgTypeClientCutText = 6; + public static final int msgTypePointerEventExt = 7; public static final int msgTypeEnableContinuousUpdates = 150; diff --git a/java/com/tigervnc/rfb/ServerParams.java b/java/com/tigervnc/rfb/ServerParams.java index 1ed64186db..8b445069e1 100644 --- a/java/com/tigervnc/rfb/ServerParams.java +++ b/java/com/tigervnc/rfb/ServerParams.java @@ -38,7 +38,7 @@ public ServerParams() { majorVersion = 0; minorVersion = 0; width_ = 0; height_ = 0; useCopyRect = false; - supportsLocalCursor = false; supportsLocalXCursor = false; + supportsLocalCursor = false; supportsLocalXCursor = false; supportsExtendedMouseButtons = false; supportsLocalCursorWithAlpha = false; supportsDesktopResize = false; supportsExtendedDesktopSize = false; supportsDesktopRename = false; supportsLastRect = false; @@ -120,6 +120,7 @@ public void setEncodings(int nEncodings, int[] encodings) supportsDesktopResize = false; supportsExtendedDesktopSize = false; supportsLocalXCursor = false; + supportsExtendedMouseButtons = false; supportsLastRect = false; compressLevel = -1; qualityLevel = -1; @@ -140,6 +141,9 @@ public void setEncodings(int nEncodings, int[] encodings) case Encodings.pseudoEncodingXCursor: supportsLocalXCursor = true; break; + case Encodings.pseudoEncodingExtendedMouseButtons: + supportsExtendedMouseButtons = true; + break; case Encodings.pseudoEncodingCursorWithAlpha: supportsLocalCursorWithAlpha = true; break; @@ -205,6 +209,7 @@ public void setEncodings(int nEncodings, int[] encodings) public boolean supportsLocalCursor; public boolean supportsLocalXCursor; + public boolean supportsExtendedMouseButtons; public boolean supportsLocalCursorWithAlpha; public boolean supportsDesktopResize; public boolean supportsExtendedDesktopSize; diff --git a/java/com/tigervnc/vncviewer/Viewport.java b/java/com/tigervnc/vncviewer/Viewport.java index 2e5e42d605..4bbf39a146 100644 --- a/java/com/tigervnc/vncviewer/Viewport.java +++ b/java/com/tigervnc/vncviewer/Viewport.java @@ -256,6 +256,16 @@ public int handle(MouseEvent e) buttonMask |= 2; if ((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) != 0) buttonMask |= 4; + + //there are no masks for buttons 4 and 5 so we need to check for them only when pressed. + if (tk.areExtraMouseButtonsEnabled() && e.getID() == MouseEvent.MOUSE_PRESSED) { + //Back + if (MouseInfo.getNumberOfButtons() >= 4 && e.getButton() == 6) + buttonMask |= 128; + //Forward + if (MouseInfo.getNumberOfButtons() >= 5 && e.getButton() == 7) + buttonMask |= 256; + } if (e.getID() == MouseEvent.MOUSE_WHEEL) { wheelMask = 0; diff --git a/unix/xserver/hw/vnc/vncInput.c b/unix/xserver/hw/vnc/vncInput.c index b3d0926dd0..0e1038658f 100644 --- a/unix/xserver/hw/vnc/vncInput.c +++ b/unix/xserver/hw/vnc/vncInput.c @@ -50,7 +50,7 @@ extern const unsigned int code_map_qnum_to_xorgevdev_len; extern const unsigned short code_map_qnum_to_xorgkbd[]; extern const unsigned int code_map_qnum_to_xorgkbd_len; -#define BUTTONS 7 +#define BUTTONS 9 DeviceIntPtr vncKeyboardDev; DeviceIntPtr vncPointerDev; @@ -206,6 +206,9 @@ static int vncPointerProc(DeviceIntPtr pDevice, int onoff) btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); + btn_labels[7] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_BACK); + btn_labels[8] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_FORWARD); + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 5dd5f7efc5..818cea679c 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -606,6 +606,11 @@ int Viewport::handle(int event) if (Fl::event_button3()) buttonMask |= 4; + if(Fl::event_buttons()&FL_BUTTON(4)) + buttonMask |= 128; + if(Fl::event_buttons()&FL_BUTTON(5)) + buttonMask |= 256; + if (event == FL_MOUSEWHEEL) { wheelMask = 0; if (Fl::event_dy() < 0) From 1105449a26f073aaca303d0120a1af52c5f6a573 Mon Sep 17 00:00:00 2001 From: PixelSmith Date: Fri, 5 Jan 2024 08:09:44 -0600 Subject: [PATCH 2/3] Fixed recommended issues. Added support on native FLTK for mouse buttons 8 and 9. Removed the use of the Client message for the psuedo encoding. --- common/rfb/CMsgReader.cxx | 13 +++------ common/rfb/CMsgReader.h | 1 - common/rfb/CMsgWriter.cxx | 33 +++++++++-------------- common/rfb/CMsgWriter.h | 1 - common/rfb/SMsgHandler.cxx | 5 ++-- common/rfb/SMsgReader.cxx | 4 +-- common/rfb/SMsgReader.h | 2 +- common/rfb/SMsgWriter.cxx | 29 +++++++++++++++++--- common/rfb/SMsgWriter.h | 2 ++ common/rfb/msgTypes.h | 2 -- java/com/tigervnc/rfb/CMsgReader.java | 11 +++----- java/com/tigervnc/rfb/CMsgWriter.java | 32 +++++++++------------- java/com/tigervnc/vncviewer/Viewport.java | 12 ++++----- unix/xserver/hw/vnc/vncInput.c | 9 ++++--- vncviewer/Viewport.cxx | 11 +++++--- 15 files changed, 86 insertions(+), 81 deletions(-) diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx index c1c6ad17c3..1a84807a95 100644 --- a/common/rfb/CMsgReader.cxx +++ b/common/rfb/CMsgReader.cxx @@ -118,9 +118,6 @@ bool CMsgReader::readMsg() case msgTypeEndOfContinuousUpdates: ret = readEndOfContinuousUpdates(); break; - case msgTypeExtendedMouseSupport: - ret = readSupportExtendedMouseButton(); - break; default: throw Exception("Unknown message type %d", currentMsgType); } @@ -205,6 +202,10 @@ bool CMsgReader::readMsg() handler->supportsQEMUKeyEvent(); ret = true; break; + case pseudoEncodingExtendedMouseButtons: + handler->supportExtendedMouseButtons(); + ret = true; + break; default: ret = readRect(dataRect, rectEncoding); break; @@ -457,12 +458,6 @@ bool CMsgReader::readEndOfContinuousUpdates() return true; } -bool CMsgReader::readSupportExtendedMouseButton() -{ - handler->supportExtendedMouseButtons(); - return true; -} - bool CMsgReader::readFramebufferUpdate() { if (!is->hasData(1 + 2)) diff --git a/common/rfb/CMsgReader.h b/common/rfb/CMsgReader.h index 8000762bc4..3b1c0ddbd6 100644 --- a/common/rfb/CMsgReader.h +++ b/common/rfb/CMsgReader.h @@ -56,7 +56,6 @@ namespace rfb { bool readExtendedClipboard(int32_t len); bool readFence(); bool readEndOfContinuousUpdates(); - bool readSupportExtendedMouseButton(); bool readFramebufferUpdate(); diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx index 8ba87e801f..99ed493574 100644 --- a/common/rfb/CMsgWriter.cxx +++ b/common/rfb/CMsgWriter.cxx @@ -182,29 +182,22 @@ void CMsgWriter::writePointerEvent(const Point& pos, int buttonMask) if (p.x >= server->width()) p.x = server->width() - 1; if (p.y >= server->height()) p.y = server->height() - 1; - if (server->supportsExtendedMouseButtons) - { - writePointerEventExt(pos,buttonMask); - return; + if (server->supportsExtendedMouseButtons) { + startMsg(msgTypePointerEventExt); + os->writeU16(buttonMask); + os->writeU16(p.x); + os->writeU16(p.y); + endMsg(); + } + else { + startMsg(msgTypePointerEvent); + os->writeU8(buttonMask); + os->writeU16(p.x); + os->writeU16(p.y); + endMsg(); } - - startMsg(msgTypePointerEvent); - os->writeU8(buttonMask); - os->writeU16(p.x); - os->writeU16(p.y); - endMsg(); -} - -void CMsgWriter::writePointerEventExt(const Point& p, int buttonMask) -{ - startMsg(msgTypePointerEventExt); - os->writeU16(buttonMask); - os->writeU16(p.x); - os->writeU16(p.y); - endMsg(); } - void CMsgWriter::writeClientCutText(const char* str) { if (strchr(str, '\r') != NULL) diff --git a/common/rfb/CMsgWriter.h b/common/rfb/CMsgWriter.h index 1b76c1da65..1b70a1d011 100644 --- a/common/rfb/CMsgWriter.h +++ b/common/rfb/CMsgWriter.h @@ -55,7 +55,6 @@ namespace rfb { void writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down); void writePointerEvent(const Point& pos, int buttonMask); - void writePointerEventExt(const Point& pos, int buttonMask); void writeClientCutText(const char* str); diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx index 972620707b..bee4530f81 100644 --- a/common/rfb/SMsgHandler.cxx +++ b/common/rfb/SMsgHandler.cxx @@ -53,12 +53,13 @@ void SMsgHandler::setPixelFormat(const PixelFormat& pf) void SMsgHandler::setEncodings(int nEncodings, const int32_t* encodings) { bool firstFence, firstContinuousUpdates, firstLEDState, - firstQEMUKeyEvent; + firstQEMUKeyEvent, firstExtMouseButtonEvent; firstFence = !client.supportsFence(); firstContinuousUpdates = !client.supportsContinuousUpdates(); firstLEDState = !client.supportsLEDState(); firstQEMUKeyEvent = !client.supportsEncoding(pseudoEncodingQEMUKeyEvent); + firstExtMouseButtonEvent = !client.supportsEncoding(pseudoEncodingExtendedMouseButtons); client.setEncodings(nEncodings, encodings); @@ -72,7 +73,7 @@ void SMsgHandler::setEncodings(int nEncodings, const int32_t* encodings) supportsLEDState(); if (client.supportsEncoding(pseudoEncodingQEMUKeyEvent) && firstQEMUKeyEvent) supportsQEMUKeyEvent(); - if (client.supportsEncoding(pseudoEncodingExtendedMouseButtons)) + if (client.supportsEncoding(pseudoEncodingExtendedMouseButtons) && firstExtMouseButtonEvent) supportsExtendedMouseButtons(); } diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx index cdb284d242..6cdb9e2be6 100644 --- a/common/rfb/SMsgReader.cxx +++ b/common/rfb/SMsgReader.cxx @@ -100,7 +100,7 @@ bool SMsgReader::readMsg() ret = readPointerEvent(); break; case msgTypePointerEventExt: - ret = readPointerEvenExt(); + ret = readPointerEventExt(); break; case msgTypeClientCutText: ret = readClientCutText(); @@ -284,7 +284,7 @@ bool SMsgReader::readPointerEvent() return true; } -bool SMsgReader::readPointerEvenExt() +bool SMsgReader::readPointerEventExt() { if (!is->hasData(2 + 2 + 2)) return false; diff --git a/common/rfb/SMsgReader.h b/common/rfb/SMsgReader.h index 0a5b287d9d..6b64e5df5c 100644 --- a/common/rfb/SMsgReader.h +++ b/common/rfb/SMsgReader.h @@ -53,7 +53,7 @@ namespace rfb { bool readKeyEvent(); bool readPointerEvent(); - bool readPointerEvenExt(); + bool readPointerEventExt(); bool readClientCutText(); bool readExtendedClipboard(int32_t len); diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx index 39ce3699e8..a25c558abf 100644 --- a/common/rfb/SMsgWriter.cxx +++ b/common/rfb/SMsgWriter.cxx @@ -50,6 +50,7 @@ SMsgWriter::SMsgWriter(ClientParams* client_, rdr::OutStream* os_) needSetDesktopName(false), needCursor(false), needCursorPos(false), needLEDState(false), needQEMUKeyEvent(false) + ,needExtMouseButtonEvent(false) { } @@ -307,9 +308,8 @@ void SMsgWriter::writeExtendedMouseButtonSupport() { if (!client->supportsEncoding(pseudoEncodingExtendedMouseButtons)) throw Exception("Client does not support Extended Mouse Buttons"); - - startMsg(msgTypeExtendedMouseSupport); - endMsg(); + + needExtMouseButtonEvent = true; } bool SMsgWriter::needFakeUpdate() @@ -324,6 +324,8 @@ bool SMsgWriter::needFakeUpdate() return true; if (needQEMUKeyEvent) return true; + if (needExtMouseButtonEvent) + return true; if (needNoDataUpdate()) return true; @@ -372,6 +374,8 @@ void SMsgWriter::writeFramebufferUpdateStart(int nRects) nRects++; if (needQEMUKeyEvent) nRects++; + if (needExtMouseButtonEvent) + nRects++; } os->writeU16(nRects); @@ -511,6 +515,11 @@ void SMsgWriter::writePseudoRects() writeQEMUKeyEventRect(); needQEMUKeyEvent = false; } + + if (needExtMouseButtonEvent) { + writeExtendedMouseButtonRect(); + needExtMouseButtonEvent = false; + } } void SMsgWriter::writeNoDataRects() @@ -744,3 +753,17 @@ void SMsgWriter::writeQEMUKeyEventRect() os->writeU16(0); os->writeU32(pseudoEncodingQEMUKeyEvent); } + +void SMsgWriter::writeExtendedMouseButtonRect() +{ + if (!client->supportsEncoding(pseudoEncodingExtendedMouseButtons)) + throw Exception("Client does not support extended mouse button events"); + if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) + throw Exception("SMsgWriter::writeExtendedMouseButtonRect: nRects out of sync"); + + os->writeS16(0); + os->writeS16(0); + os->writeU16(0); + os->writeU16(0); + os->writeU32(pseudoEncodingExtendedMouseButtons); +} diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h index 71cf2bbe45..e96257ea6b 100644 --- a/common/rfb/SMsgWriter.h +++ b/common/rfb/SMsgWriter.h @@ -151,6 +151,7 @@ namespace rfb { void writeSetVMwareCursorPositionRect(int hotspotX, int hotspotY); void writeLEDStateRect(uint8_t state); void writeQEMUKeyEventRect(); + void writeExtendedMouseButtonRect(); ClientParams* client; rdr::OutStream* os; @@ -163,6 +164,7 @@ namespace rfb { bool needCursorPos; bool needLEDState; bool needQEMUKeyEvent; + bool needExtMouseButtonEvent; typedef struct { uint16_t reason, result; diff --git a/common/rfb/msgTypes.h b/common/rfb/msgTypes.h index e2bc3423f0..14fb6037fe 100644 --- a/common/rfb/msgTypes.h +++ b/common/rfb/msgTypes.h @@ -28,8 +28,6 @@ namespace rfb { const int msgTypeEndOfContinuousUpdates = 150; - const int msgTypeExtendedMouseSupport = 151; - const int msgTypeServerFence = 248; // client to server diff --git a/java/com/tigervnc/rfb/CMsgReader.java b/java/com/tigervnc/rfb/CMsgReader.java index 2289535d89..5dd9402e1e 100644 --- a/java/com/tigervnc/rfb/CMsgReader.java +++ b/java/com/tigervnc/rfb/CMsgReader.java @@ -80,9 +80,6 @@ public void readMsg() case MsgTypes.msgTypeEndOfContinuousUpdates: readEndOfContinuousUpdates(); break; - case MsgTypes.msgTypeExtendedMouseSupport: - readSupportExtendedMouseButton(); - break; default: vlog.error("unknown message type "+type); throw new Exception("unknown message type"); @@ -119,6 +116,9 @@ public void readMsg() case Encodings.pseudoEncodingExtendedDesktopSize: readExtendedDesktopSize(x, y, w, h); break; + case Encodings.pseudoEncodingExtendedMouseButtons: + handler.SupportExtendedMouseButton(); + break; case Encodings.pseudoEncodingClientRedirect: nUpdateRectsLeft = 0; readClientRedirect(x, y, w, h); @@ -195,11 +195,6 @@ protected void readEndOfContinuousUpdates() handler.endOfContinuousUpdates(); } - protected void readSupportExtendedMouseButton() - { - handler.SupportExtendedMouseButton(); - } - protected void readFramebufferUpdate() { is.skip(1); diff --git a/java/com/tigervnc/rfb/CMsgWriter.java b/java/com/tigervnc/rfb/CMsgWriter.java index 27a24ee2c0..b92c181ea3 100644 --- a/java/com/tigervnc/rfb/CMsgWriter.java +++ b/java/com/tigervnc/rfb/CMsgWriter.java @@ -150,26 +150,20 @@ synchronized public void writePointerEvent(Point pos, int buttonMask) if (p.x >= server.width()) p.x = server.width() - 1; if (p.y >= server.height()) p.y = server.height() - 1; - if(server.supportsExtendedMouseButtons) - { - writePointerEventExt(pos,buttonMask); - return; + if(server.supportsExtendedMouseButtons) { + startMsg(MsgTypes.msgTypePointerEventExt); + os.writeU16(buttonMask); + os.writeU16(p.x); + os.writeU16(p.y); + endMsg(); + } + else { + startMsg(MsgTypes.msgTypePointerEvent); + os.writeU8(buttonMask); + os.writeU16(p.x); + os.writeU16(p.y); + endMsg(); } - - startMsg(MsgTypes.msgTypePointerEvent); - os.writeU8(buttonMask); - os.writeU16(p.x); - os.writeU16(p.y); - endMsg(); - } - - synchronized public void writePointerEventExt(Point p, int buttonMask) - { - startMsg(MsgTypes.msgTypePointerEventExt); - os.writeU16(buttonMask); - os.writeU16(p.x); - os.writeU16(p.y); - endMsg(); } synchronized public void writeClientCutText(String str, int len) diff --git a/java/com/tigervnc/vncviewer/Viewport.java b/java/com/tigervnc/vncviewer/Viewport.java index 4bbf39a146..654e4dbb88 100644 --- a/java/com/tigervnc/vncviewer/Viewport.java +++ b/java/com/tigervnc/vncviewer/Viewport.java @@ -257,14 +257,14 @@ public int handle(MouseEvent e) if ((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) != 0) buttonMask |= 4; - //there are no masks for buttons 4 and 5 so we need to check for them only when pressed. - if (tk.areExtraMouseButtonsEnabled() && e.getID() == MouseEvent.MOUSE_PRESSED) { + //there are no masks for buttons 6 and 7 so we need to check for them only when pressed. + if (tk.areExtraMouseButtonsEnabled()){ //Back - if (MouseInfo.getNumberOfButtons() >= 4 && e.getButton() == 6) - buttonMask |= 128; + if (MouseInfo.getNumberOfButtons() >= 6 && ((e.getModifiersEx() & e.getMaskForButton(6)) != 0)) + buttonMask |= 1024; //Forward - if (MouseInfo.getNumberOfButtons() >= 5 && e.getButton() == 7) - buttonMask |= 256; + if (MouseInfo.getNumberOfButtons() >= 7 && ((e.getModifiersEx() & e.getMaskForButton(7)) != 0)) + buttonMask |= 512; } if (e.getID() == MouseEvent.MOUSE_WHEEL) { diff --git a/unix/xserver/hw/vnc/vncInput.c b/unix/xserver/hw/vnc/vncInput.c index 0e1038658f..1dbe4a3c0a 100644 --- a/unix/xserver/hw/vnc/vncInput.c +++ b/unix/xserver/hw/vnc/vncInput.c @@ -50,7 +50,7 @@ extern const unsigned int code_map_qnum_to_xorgevdev_len; extern const unsigned short code_map_qnum_to_xorgkbd[]; extern const unsigned int code_map_qnum_to_xorgkbd_len; -#define BUTTONS 9 +#define BUTTONS 11 DeviceIntPtr vncKeyboardDev; DeviceIntPtr vncPointerDev; @@ -206,8 +206,11 @@ static int vncPointerProc(DeviceIntPtr pDevice, int onoff) btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); - btn_labels[7] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_BACK); - btn_labels[8] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_FORWARD); + btn_labels[7] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_SIDE); + btn_labels[8] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_EXTRA); + btn_labels[9] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_FORWARD); + btn_labels[10] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_BACK); + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 818cea679c..94cde1b509 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -606,10 +606,13 @@ int Viewport::handle(int event) if (Fl::event_button3()) buttonMask |= 4; - if(Fl::event_buttons()&FL_BUTTON(4)) - buttonMask |= 128; - if(Fl::event_buttons()&FL_BUTTON(5)) - buttonMask |= 256; + //Fl::event_button is only good for FL_PUSH and FL_RELEASE + if(event == FL_PUSH) { + if (Fl::event_button() == 8) //Mouse Back + buttonMask |= 1024; + if (Fl::event_button() == 9) //Mouse Forward + buttonMask |= 512; + } if (event == FL_MOUSEWHEEL) { wheelMask = 0; From 14a6d254f756b3b777b1e360fc5c767ff227f40d Mon Sep 17 00:00:00 2001 From: PixelSmith Date: Fri, 5 Jan 2024 08:35:27 -0600 Subject: [PATCH 3/3] Fixed Some indentation that was off in vncinput.c --- unix/xserver/hw/vnc/vncInput.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/unix/xserver/hw/vnc/vncInput.c b/unix/xserver/hw/vnc/vncInput.c index 1dbe4a3c0a..ab60930b6a 100644 --- a/unix/xserver/hw/vnc/vncInput.c +++ b/unix/xserver/hw/vnc/vncInput.c @@ -207,11 +207,9 @@ static int vncPointerProc(DeviceIntPtr pDevice, int onoff) btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); btn_labels[7] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_SIDE); - btn_labels[8] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_EXTRA); - btn_labels[9] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_FORWARD); - btn_labels[10] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_BACK); - - + btn_labels[8] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_EXTRA); + btn_labels[9] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_FORWARD); + btn_labels[10] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_BACK); axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);