encodings.push_back(pseudoEncodingContinuousUpdates);
encodings.push_back(pseudoEncodingFence);
encodings.push_back(pseudoEncodingQEMUKeyEvent);
+ encodings.push_back(pseudoEncodingExtendedMouseButtons);
if (Decoder::supported(preferredEncoding)) {
encodings.push_back(preferredEncoding);
server.supportsContinuousUpdates = true;
}
+void CMsgHandler::supportsExtendedMouseButtons()
+{
+ server.supportsExtendedMouseButtons = true;
+}
+
void CMsgHandler::supportsQEMUKeyEvent()
{
server.supportsQEMUKeyEvent = true;
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;
handler->supportsQEMUKeyEvent();
ret = true;
break;
+ case pseudoEncodingExtendedMouseButtons:
+ handler->supportsExtendedMouseButtons();
+ ret = true;
+ break;
default:
ret = readRect(dataRect, rectEncoding);
break;
#endif
#include <stdio.h>
+#include <assert.h>
#include <rdr/OutStream.h>
#include <rdr/MemOutStream.h>
}
-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();
}
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);
: majorVersion(0), minorVersion(0),
supportsQEMUKeyEvent(false),
supportsSetDesktopSize(false), supportsFence(false),
- supportsContinuousUpdates(false),
+ supportsContinuousUpdates(false), supportsExtendedMouseButtons(false),
width_(0), height_(0),
ledState_(ledUnknown)
{
bool supportsSetDesktopSize;
bool supportsFence;
bool supportsContinuousUpdates;
+ bool supportsExtendedMouseButtons;
private:
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;
{
}
-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;
void EmulateMB::handleTimeout(rfb::Timer *t)
{
int action1, action2;
- uint8_t buttonMask;
+ uint16_t buttonMask;
if (&timer != t)
return;
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);
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;
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;
};
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)
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;
}
-void Viewport::handlePointerEvent(const rfb::Point& pos, uint8_t buttonMask)
+void Viewport::handlePointerEvent(const rfb::Point& pos, uint16_t buttonMask)
{
filterPointerEvent(pos, buttonMask);
}
(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
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();
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();
PlatformPixelBuffer* frameBuffer;
rfb::Point lastPointerPos;
- uint8_t lastButtonMask;
+ uint16_t lastButtonMask;
typedef std::map<int, uint32_t> DownMap;
DownMap downKeySym;