From 5ae282135f982505fab655d4f597e7329fb8b0d1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 16 May 2017 14:30:38 +0200 Subject: [PATCH] Basic support for QEMU Extended Key Events This adds the basic infrastructure and handshake for the QEMU Extended Key Events extension. No viewer or server makes use of the extra functionality yet though. --- common/rfb/CMsgHandler.cxx | 5 +++ common/rfb/CMsgHandler.h | 1 + common/rfb/CMsgReader.cxx | 2 + common/rfb/CMsgWriter.cxx | 27 +++++++++--- common/rfb/CMsgWriter.h | 2 +- common/rfb/ConnParams.cxx | 8 +++- common/rfb/ConnParams.h | 1 + common/rfb/InputHandler.h | 2 +- common/rfb/SConnection.cxx | 5 +++ common/rfb/SConnection.h | 1 + common/rfb/SMsgHandler.cxx | 10 ++++- common/rfb/SMsgHandler.h | 5 +++ common/rfb/SMsgReader.cxx | 29 ++++++++++++- common/rfb/SMsgReader.h | 3 ++ common/rfb/SMsgWriter.cxx | 35 ++++++++++++++- common/rfb/SMsgWriter.h | 5 +++ common/rfb/VNCSConnectionST.cxx | 61 ++++++++++++++------------- common/rfb/VNCSConnectionST.h | 2 +- common/rfb/encodings.h | 1 + common/rfb/msgTypes.h | 2 + common/rfb/qemuTypes.h | 25 +++++++++++ unix/x0vncserver/x0vncserver.cxx | 4 +- unix/xserver/hw/vnc/XserverDesktop.cc | 2 +- unix/xserver/hw/vnc/XserverDesktop.h | 2 +- vncviewer/Viewport.cxx | 12 +++--- win/rfb_win32/SDisplay.cxx | 4 +- win/rfb_win32/SDisplay.h | 2 +- win/rfb_win32/SInput.cxx | 2 +- win/rfb_win32/SInput.h | 2 +- 29 files changed, 203 insertions(+), 59 deletions(-) create mode 100644 common/rfb/qemuTypes.h diff --git a/common/rfb/CMsgHandler.cxx b/common/rfb/CMsgHandler.cxx index 74c7bf92..b89bc184 100644 --- a/common/rfb/CMsgHandler.cxx +++ b/common/rfb/CMsgHandler.cxx @@ -75,6 +75,11 @@ void CMsgHandler::endOfContinuousUpdates() cp.supportsContinuousUpdates = true; } +void CMsgHandler::supportsQEMUKeyEvent() +{ + cp.supportsQEMUKeyEvent = true; +} + void CMsgHandler::framebufferUpdateStart() { } diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h index ef2cda20..903ee156 100644 --- a/common/rfb/CMsgHandler.h +++ b/common/rfb/CMsgHandler.h @@ -55,6 +55,7 @@ namespace rfb { virtual void setName(const char* name); virtual void fence(rdr::U32 flags, unsigned len, const char data[]); virtual void endOfContinuousUpdates(); + virtual void supportsQEMUKeyEvent(); virtual void serverInit() = 0; virtual void readAndDecodeRect(const Rect& r, int encoding, diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx index 0aaf71fa..eee6d277 100644 --- a/common/rfb/CMsgReader.cxx +++ b/common/rfb/CMsgReader.cxx @@ -111,6 +111,8 @@ void CMsgReader::readMsg() break; case pseudoEncodingLEDState: readLEDState(); + case pseudoEncodingQEMUKeyEvent: + handler->supportsQEMUKeyEvent(); break; default: readRect(Rect(x, y, x+w, y+h), encoding); diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx index 7a89a934..57d1283a 100644 --- a/common/rfb/CMsgWriter.cxx +++ b/common/rfb/CMsgWriter.cxx @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +89,7 @@ void CMsgWriter::writeSetEncodings(int preferredEncoding, bool useCopyRect) encodings[nEncodings++] = pseudoEncodingLastRect; encodings[nEncodings++] = pseudoEncodingContinuousUpdates; encodings[nEncodings++] = pseudoEncodingFence; + encodings[nEncodings++] = pseudoEncodingQEMUKeyEvent; if (Decoder::supported(preferredEncoding)) { encodings[nEncodings++] = preferredEncoding; @@ -215,13 +217,26 @@ void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[]) endMsg(); } -void CMsgWriter::keyEvent(rdr::U32 key, bool down) +void CMsgWriter::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) { - startMsg(msgTypeKeyEvent); - os->writeU8(down); - os->pad(2); - os->writeU32(key); - endMsg(); + if (!cp->supportsQEMUKeyEvent || !keycode) { + /* This event isn't meaningful without a valid keysym */ + if (!keysym) + return; + + startMsg(msgTypeKeyEvent); + os->writeU8(down); + os->pad(2); + os->writeU32(keysym); + endMsg(); + } else { + startMsg(msgTypeQEMUClientMessage); + os->writeU8(qemuExtendedKeyEvent); + os->writeU16(down); + os->writeU32(keysym); + os->writeU32(keycode); + endMsg(); + } } diff --git a/common/rfb/CMsgWriter.h b/common/rfb/CMsgWriter.h index 06ecbe7d..56e0b7b9 100644 --- a/common/rfb/CMsgWriter.h +++ b/common/rfb/CMsgWriter.h @@ -55,7 +55,7 @@ namespace rfb { // InputHandler implementation - virtual void keyEvent(rdr::U32 key, bool down); + virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); virtual void pointerEvent(const Point& pos, int buttonMask); virtual void clientCutText(const char* str, rdr::U32 len); diff --git a/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx index f0b69327..23f02ed0 100644 --- a/common/rfb/ConnParams.cxx +++ b/common/rfb/ConnParams.cxx @@ -35,8 +35,9 @@ ConnParams::ConnParams() supportsLocalCursorWithAlpha(false), supportsDesktopResize(false), supportsExtendedDesktopSize(false), supportsDesktopRename(false), supportsLastRect(false), - supportsLEDState(false), supportsSetDesktopSize(false), - supportsFence(false), supportsContinuousUpdates(false), + supportsLEDState(false), supportsQEMUKeyEvent(false), + supportsSetDesktopSize(false), supportsFence(false), + supportsContinuousUpdates(false), compressLevel(2), qualityLevel(-1), fineQualityLevel(-1), subsampling(subsampleUndefined), name_(0), verStrPos(0), ledState_(ledUnknown) @@ -109,6 +110,7 @@ void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings) supportsExtendedDesktopSize = false; supportsLocalXCursor = false; supportsLastRect = false; + supportsQEMUKeyEvent = false; compressLevel = -1; qualityLevel = -1; fineQualityLevel = -1; @@ -145,6 +147,8 @@ void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings) break; case pseudoEncodingLEDState: supportsLEDState = true; + case pseudoEncodingQEMUKeyEvent: + supportsQEMUKeyEvent = true; break; case pseudoEncodingFence: supportsFence = true; diff --git a/common/rfb/ConnParams.h b/common/rfb/ConnParams.h index d99d142c..b3222936 100644 --- a/common/rfb/ConnParams.h +++ b/common/rfb/ConnParams.h @@ -97,6 +97,7 @@ namespace rfb { bool supportsDesktopRename; bool supportsLastRect; bool supportsLEDState; + bool supportsQEMUKeyEvent; bool supportsSetDesktopSize; bool supportsFence; diff --git a/common/rfb/InputHandler.h b/common/rfb/InputHandler.h index b5e5e879..0344bc3f 100644 --- a/common/rfb/InputHandler.h +++ b/common/rfb/InputHandler.h @@ -31,7 +31,7 @@ namespace rfb { class InputHandler { public: virtual ~InputHandler() {} - virtual void keyEvent(rdr::U32 key, bool down) {} + virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {} virtual void pointerEvent(const Point& pos, int buttonMask) {} virtual void clientCutText(const char* str, int len) {} }; diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx index 85cc6e82..c5c9038c 100644 --- a/common/rfb/SConnection.cxx +++ b/common/rfb/SConnection.cxx @@ -278,6 +278,11 @@ void SConnection::setEncodings(int nEncodings, const rdr::S32* encodings) SMsgHandler::setEncodings(nEncodings, encodings); } +void SConnection::supportsQEMUKeyEvent() +{ + writer()->writeQEMUKeyEvent(); +} + void SConnection::versionReceived() { } diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h index 63dc3146..bc435834 100644 --- a/common/rfb/SConnection.h +++ b/common/rfb/SConnection.h @@ -73,6 +73,7 @@ namespace rfb { virtual void setEncodings(int nEncodings, const rdr::S32* encodings); + virtual void supportsQEMUKeyEvent(); // Methods to be overridden in a derived class diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx index 8e48c673..c38458c3 100644 --- a/common/rfb/SMsgHandler.cxx +++ b/common/rfb/SMsgHandler.cxx @@ -41,11 +41,13 @@ void SMsgHandler::setPixelFormat(const PixelFormat& pf) void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings) { - bool firstFence, firstContinuousUpdates, firstLEDState; + bool firstFence, firstContinuousUpdates, firstLEDState, + firstQEMUKeyEvent; firstFence = !cp.supportsFence; firstContinuousUpdates = !cp.supportsContinuousUpdates; firstLEDState = !cp.supportsLEDState; + firstQEMUKeyEvent = !cp.supportsQEMUKeyEvent; cp.setEncodings(nEncodings, encodings); @@ -57,6 +59,8 @@ void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings) supportsContinuousUpdates(); if (cp.supportsLEDState && firstLEDState) supportsLEDState(); + if (cp.supportsQEMUKeyEvent && firstQEMUKeyEvent) + supportsQEMUKeyEvent(); } void SMsgHandler::supportsLocalCursor() @@ -75,6 +79,10 @@ void SMsgHandler::supportsLEDState() { } +void SMsgHandler::supportsQEMUKeyEvent() +{ +} + void SMsgHandler::setDesktopSize(int fb_width, int fb_height, const ScreenSet& layout) { diff --git a/common/rfb/SMsgHandler.h b/common/rfb/SMsgHandler.h index cf6b6b3b..749f0560 100644 --- a/common/rfb/SMsgHandler.h +++ b/common/rfb/SMsgHandler.h @@ -80,6 +80,11 @@ namespace rfb { // server state. virtual void supportsLEDState(); + // supportsQEMUKeyEvent() is called the first time we detect that the + // client wants the QEMU Extended Key Event extension. The default + // handler will send a pseudo-rect back, signalling server support. + virtual void supportsQEMUKeyEvent(); + ConnParams cp; }; } diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx index 3c08fd6f..cb71ac84 100644 --- a/common/rfb/SMsgReader.cxx +++ b/common/rfb/SMsgReader.cxx @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,9 @@ void SMsgReader::readMsg() case msgTypeClientCutText: readClientCutText(); break; + case msgTypeQEMUClientMessage: + readQEMUMessage(); + break; default: fprintf(stderr, "unknown message type %d\n", msgType); throw Exception("unknown message type"); @@ -184,7 +188,7 @@ void SMsgReader::readKeyEvent() bool down = is->readU8(); is->skip(2); rdr::U32 key = is->readU32(); - handler->keyEvent(key, down); + handler->keyEvent(key, 0, down); } void SMsgReader::readPointerEvent() @@ -214,3 +218,26 @@ void SMsgReader::readClientCutText() handler->clientCutText(ca.buf, len); } +void SMsgReader::readQEMUMessage() +{ + int subType = is->readU8(); + switch (subType) { + case qemuExtendedKeyEvent: + readQEMUKeyEvent(); + break; + default: + throw Exception("unknown QEMU submessage type %d", subType); + } +} + +void SMsgReader::readQEMUKeyEvent() +{ + bool down = is->readU16(); + rdr::U32 keysym = is->readU32(); + rdr::U32 keycode = is->readU32(); + if (!keycode) { + vlog.error("Key event without keycode - ignoring"); + return; + } + handler->keyEvent(keysym, keycode, down); +} diff --git a/common/rfb/SMsgReader.h b/common/rfb/SMsgReader.h index 00cb3031..146b29f8 100644 --- a/common/rfb/SMsgReader.h +++ b/common/rfb/SMsgReader.h @@ -55,6 +55,9 @@ namespace rfb { void readPointerEvent(); void readClientCutText(); + void readQEMUMessage(); + void readQEMUKeyEvent(); + SMsgHandler* handler; rdr::InStream* is; }; diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx index d8adfbc1..2d4998b3 100644 --- a/common/rfb/SMsgWriter.cxx +++ b/common/rfb/SMsgWriter.cxx @@ -39,7 +39,7 @@ SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_) needSetDesktopSize(false), needExtendedDesktopSize(false), needSetDesktopName(false), needSetCursor(false), needSetXCursor(false), needSetCursorWithAlpha(false), - needLEDState(false) + needLEDState(false), needQEMUKeyEvent(false) { } @@ -207,6 +207,16 @@ bool SMsgWriter::writeLEDState() return true; } +bool SMsgWriter::writeQEMUKeyEvent() +{ + if (!cp->supportsQEMUKeyEvent) + return false; + + needQEMUKeyEvent = true; + + return true; +} + bool SMsgWriter::needFakeUpdate() { if (needSetDesktopName) @@ -215,6 +225,8 @@ bool SMsgWriter::needFakeUpdate() return true; if (needLEDState) return true; + if (needQEMUKeyEvent) + return true; if (needNoDataUpdate()) return true; @@ -265,6 +277,8 @@ void SMsgWriter::writeFramebufferUpdateStart(int nRects) nRects++; if (needLEDState) nRects++; + if (needQEMUKeyEvent) + nRects++; } os->writeU16(nRects); @@ -385,6 +399,11 @@ void SMsgWriter::writePseudoRects() writeLEDStateRect(cp->ledState()); needLEDState = false; } + + if (needQEMUKeyEvent) { + writeQEMUKeyEventRect(); + needQEMUKeyEvent = false; + } } void SMsgWriter::writeNoDataRects() @@ -565,3 +584,17 @@ void SMsgWriter::writeLEDStateRect(rdr::U8 state) os->writeU32(pseudoEncodingLEDState); os->writeU8(state); } + +void SMsgWriter::writeQEMUKeyEventRect() +{ + if (!cp->supportsQEMUKeyEvent) + throw Exception("Client does not support QEMU extended key events"); + if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) + throw Exception("SMsgWriter::writeQEMUKeyEventRect: nRects out of sync"); + + os->writeS16(0); + os->writeS16(0); + os->writeU16(0); + os->writeU16(0); + os->writeU32(pseudoEncodingQEMUKeyEvent); +} diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h index 890b2b5b..f2adadca 100644 --- a/common/rfb/SMsgWriter.h +++ b/common/rfb/SMsgWriter.h @@ -85,6 +85,9 @@ namespace rfb { // Same for LED state message bool writeLEDState(); + // And QEMU keyboard event handshake + bool writeQEMUKeyEvent(); + // needFakeUpdate() returns true when an immediate update is needed in // order to flush out pseudo-rectangles to the client. bool needFakeUpdate(); @@ -135,6 +138,7 @@ namespace rfb { int hotspotX, int hotspotY, const rdr::U8* data); void writeLEDStateRect(rdr::U8 state); + void writeQEMUKeyEventRect(); ConnParams* cp; rdr::OutStream* os; @@ -150,6 +154,7 @@ namespace rfb { bool needSetXCursor; bool needSetCursorWithAlpha; bool needLEDState; + bool needQEMUKeyEvent; typedef struct { rdr::U16 reason, result; diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index 232776fc..be496e73 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -103,7 +103,7 @@ VNCSConnectionST::~VNCSConnectionST() std::set::iterator i; for (i=pressedKeys.begin(); i!=pressedKeys.end(); i++) { vlog.debug("Releasing key 0x%x on client disconnect", *i); - server->desktop->keyEvent(*i, false); + server->desktop->keyEvent(*i, 0, false); } if (server->pointerClient == this) server->pointerClient = 0; @@ -538,12 +538,12 @@ public: ~VNCSConnectionSTShiftPresser() { if (pressed) { vlog.debug("Releasing fake Shift_L"); - desktop->keyEvent(XK_Shift_L, false); + desktop->keyEvent(XK_Shift_L, 0, false); } } void press() { vlog.debug("Pressing fake Shift_L"); - desktop->keyEvent(XK_Shift_L, true); + desktop->keyEvent(XK_Shift_L, 0, true); pressed = true; } SDesktop* desktop; @@ -552,32 +552,32 @@ public: // keyEvent() - record in the pressedKeys which keys were pressed. Allow // multiple down events (for autorepeat), but only allow a single up event. -void VNCSConnectionST::keyEvent(rdr::U32 key, bool down) { +void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) { lastEventTime = time(0); server->lastUserInputTime = lastEventTime; if (!(accessRights & AccessKeyEvents)) return; if (!rfb::Server::acceptKeyEvents) return; if (down) - vlog.debug("Key pressed: 0x%x", key); + vlog.debug("Key pressed: 0x%x / 0x%x", keysym, keycode); else - vlog.debug("Key released: 0x%x", key); + vlog.debug("Key released: 0x%x / 0x%x", keysym, keycode); // Remap the key if required if (server->keyRemapper) { rdr::U32 newkey; - newkey = server->keyRemapper->remapKey(key); - if (newkey != key) { + newkey = server->keyRemapper->remapKey(keysym); + if (newkey != keysym) { vlog.debug("Key remapped to 0x%x", newkey); - key = newkey; + keysym = newkey; } } // Avoid lock keys if we don't know the server state if ((server->ledState == ledUnknown) && - ((key == XK_Caps_Lock) || - (key == XK_Num_Lock) || - (key == XK_Scroll_Lock))) { + ((keysym == XK_Caps_Lock) || + (keysym == XK_Num_Lock) || + (keysym == XK_Scroll_Lock))) { vlog.debug("Ignoring lock key (e.g. caps lock)"); return; } @@ -587,7 +587,7 @@ void VNCSConnectionST::keyEvent(rdr::U32 key, bool down) { if (!cp.supportsLEDState) { // Always ignore ScrollLock as we don't have a heuristic // for that - if (key == XK_Scroll_Lock) { + if (keysym == XK_Scroll_Lock) { vlog.debug("Ignoring lock key (e.g. caps lock)"); return; } @@ -596,32 +596,32 @@ void VNCSConnectionST::keyEvent(rdr::U32 key, bool down) { // CapsLock synchronisation heuristic // (this assumes standard interaction between CapsLock the Shift // keys and normal characters) - if (((key >= XK_A) && (key <= XK_Z)) || - ((key >= XK_a) && (key <= XK_z))) { + if (((keysym >= XK_A) && (keysym <= XK_Z)) || + ((keysym >= XK_a) && (keysym <= XK_z))) { bool uppercase, shift, lock; - uppercase = (key >= XK_A) && (key <= XK_Z); + uppercase = (keysym >= XK_A) && (keysym <= XK_Z); shift = pressedKeys.find(XK_Shift_L) != pressedKeys.end() || pressedKeys.find(XK_Shift_R) != pressedKeys.end(); lock = server->ledState & ledCapsLock; if (lock == (uppercase == shift)) { vlog.debug("Inserting fake CapsLock to get in sync with client"); - server->desktop->keyEvent(XK_Caps_Lock, true); - server->desktop->keyEvent(XK_Caps_Lock, false); + server->desktop->keyEvent(XK_Caps_Lock, 0, true); + server->desktop->keyEvent(XK_Caps_Lock, 0, false); } } // NumLock synchronisation heuristic // (this is more cautious because of the differences between Unix, // Windows and macOS) - if (((key >= XK_KP_Home) && (key <= XK_KP_Delete)) || - ((key >= XK_KP_0) && (key <= XK_KP_9)) || - (key == XK_KP_Separator) || (key == XK_KP_Decimal)) { + if (((keysym >= XK_KP_Home) && (keysym <= XK_KP_Delete)) || + ((keysym >= XK_KP_0) && (keysym <= XK_KP_9)) || + (keysym == XK_KP_Separator) || (keysym == XK_KP_Decimal)) { bool number, shift, lock; - number = ((key >= XK_KP_0) && (key <= XK_KP_9)) || - (key == XK_KP_Separator) || (key == XK_KP_Decimal); + number = ((keysym >= XK_KP_0) && (keysym <= XK_KP_9)) || + (keysym == XK_KP_Separator) || (keysym == XK_KP_Decimal); shift = pressedKeys.find(XK_Shift_L) != pressedKeys.end() || pressedKeys.find(XK_Shift_R) != pressedKeys.end(); lock = server->ledState & ledNumLock; @@ -638,8 +638,8 @@ void VNCSConnectionST::keyEvent(rdr::U32 key, bool down) { // } else if (lock == (number == shift)) { vlog.debug("Inserting fake NumLock to get in sync with client"); - server->desktop->keyEvent(XK_Num_Lock, true); - server->desktop->keyEvent(XK_Num_Lock, false); + server->desktop->keyEvent(XK_Num_Lock, 0, true); + server->desktop->keyEvent(XK_Num_Lock, 0, false); } } } @@ -647,19 +647,20 @@ void VNCSConnectionST::keyEvent(rdr::U32 key, bool down) { // Turn ISO_Left_Tab into shifted Tab. VNCSConnectionSTShiftPresser shiftPresser(server->desktop); - if (key == XK_ISO_Left_Tab) { + if (keysym == XK_ISO_Left_Tab) { if (pressedKeys.find(XK_Shift_L) == pressedKeys.end() && pressedKeys.find(XK_Shift_R) == pressedKeys.end()) shiftPresser.press(); - key = XK_Tab; + keysym = XK_Tab; } if (down) { - pressedKeys.insert(key); + pressedKeys.insert(keysym); } else { - if (!pressedKeys.erase(key)) return; + if (!pressedKeys.erase(keysym)) + return; } - server->desktop->keyEvent(key, down); + server->desktop->keyEvent(keysym, keycode, down); } void VNCSConnectionST::clientCutText(const char* str, int len) diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h index 8f33962d..9c58331e 100644 --- a/common/rfb/VNCSConnectionST.h +++ b/common/rfb/VNCSConnectionST.h @@ -136,7 +136,7 @@ namespace rfb { virtual void clientInit(bool shared); virtual void setPixelFormat(const PixelFormat& pf); virtual void pointerEvent(const Point& pos, int buttonMask); - virtual void keyEvent(rdr::U32 key, bool down); + virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); virtual void clientCutText(const char* str, int len); virtual void framebufferUpdateRequest(const Rect& r, bool incremental); virtual void setDesktopSize(int fb_width, int fb_height, diff --git a/common/rfb/encodings.h b/common/rfb/encodings.h index adeecaa9..122afe7f 100644 --- a/common/rfb/encodings.h +++ b/common/rfb/encodings.h @@ -40,6 +40,7 @@ namespace rfb { const int pseudoEncodingFence = -312; const int pseudoEncodingContinuousUpdates = -313; const int pseudoEncodingCursorWithAlpha = -314; + const int pseudoEncodingQEMUKeyEvent = -258; // TightVNC-specific const int pseudoEncodingLastRect = -224; diff --git a/common/rfb/msgTypes.h b/common/rfb/msgTypes.h index a55e1c50..a17493cd 100644 --- a/common/rfb/msgTypes.h +++ b/common/rfb/msgTypes.h @@ -45,5 +45,7 @@ namespace rfb { const int msgTypeClientFence = 248; const int msgTypeSetDesktopSize = 251; + + const int msgTypeQEMUClientMessage = 255; } #endif diff --git a/common/rfb/qemuTypes.h b/common/rfb/qemuTypes.h new file mode 100644 index 00000000..6a67f781 --- /dev/null +++ b/common/rfb/qemuTypes.h @@ -0,0 +1,25 @@ +/* Copyright 2017 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#ifndef __RFB_QEMUTYPES_H__ +#define __RFB_QEMUTYPES_H__ + +namespace rfb { + const int qemuExtendedKeyEvent = 0; + const int qemuAudio = 1; +} +#endif diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx index 9e5da4f9..7fb197aa 100644 --- a/unix/x0vncserver/x0vncserver.cxx +++ b/unix/x0vncserver/x0vncserver.cxx @@ -295,10 +295,10 @@ public: #endif } - virtual void keyEvent(rdr::U32 key, bool down) { + virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down) { #ifdef HAVE_XTEST if (!haveXtest) return; - int keycode = XKeysymToKeycode(dpy, key); + int keycode = XKeysymToKeycode(dpy, keysym); if (keycode) XTestFakeKeyEvent(dpy, keycode, down, CurrentTime); #endif diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc index 1c74bc66..031fb535 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.cc +++ b/unix/xserver/hw/vnc/XserverDesktop.cc @@ -771,7 +771,7 @@ void XserverDesktop::grabRegion(const rfb::Region& region) } } -void XserverDesktop::keyEvent(rdr::U32 keysym, bool down) +void XserverDesktop::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) { vncKeyboardEvent(keysym, down); } diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h index cd85e4b0..7f7823a7 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.h +++ b/unix/xserver/hw/vnc/XserverDesktop.h @@ -89,7 +89,7 @@ public: // rfb::SDesktop callbacks virtual void pointerEvent(const rfb::Point& pos, int buttonMask); - virtual void keyEvent(rdr::U32 key, bool down); + virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); virtual void clientCutText(const char* str, int len); virtual rfb::Point getFbSize() { return rfb::Point(width(), height()); } virtual unsigned int setScreenLayout(int fb_width, int fb_height, diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index bfadd4c0..1923f53a 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -709,8 +709,8 @@ void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym) if (ctrlPressed && altPressed) { vlog.debug("Faking release of AltGr (Ctrl_L+Alt_R)"); try { - cc->writer()->keyEvent(XK_Control_L, false); - cc->writer()->keyEvent(XK_Alt_R, false); + cc->writer()->keyEvent(XK_Control_L, 0, false); + cc->writer()->keyEvent(XK_Alt_R, 0, false); } catch (rdr::Exception& e) { vlog.error("%s", e.str()); exit_vncviewer(e.str()); @@ -732,7 +732,7 @@ void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym) #endif try { - cc->writer()->keyEvent(keySym, true); + cc->writer()->keyEvent(keySym, 0, true); } catch (rdr::Exception& e) { vlog.error("%s", e.str()); exit_vncviewer(e.str()); @@ -743,8 +743,8 @@ void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym) if (ctrlPressed && altPressed) { vlog.debug("Restoring AltGr state"); try { - cc->writer()->keyEvent(XK_Control_L, true); - cc->writer()->keyEvent(XK_Alt_R, true); + cc->writer()->keyEvent(XK_Control_L, 0, true); + cc->writer()->keyEvent(XK_Alt_R, 0, true); } catch (rdr::Exception& e) { vlog.error("%s", e.str()); exit_vncviewer(e.str()); @@ -777,7 +777,7 @@ void Viewport::handleKeyRelease(int keyCode) #endif try { - cc->writer()->keyEvent(iter->second, false); + cc->writer()->keyEvent(iter->second, 0, false); } catch (rdr::Exception& e) { vlog.error("%s", e.str()); exit_vncviewer(e.str()); diff --git a/win/rfb_win32/SDisplay.cxx b/win/rfb_win32/SDisplay.cxx index 2696f5dc..ad55d490 100644 --- a/win/rfb_win32/SDisplay.cxx +++ b/win/rfb_win32/SDisplay.cxx @@ -280,12 +280,12 @@ void SDisplay::pointerEvent(const Point& pos, int buttonmask) { } } -void SDisplay::keyEvent(rdr::U32 key, bool down) { +void SDisplay::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) { // - Check that the SDesktop doesn't need restarting if (isRestartRequired()) restartCore(); if (kbd) - kbd->keyEvent(key, down); + kbd->keyEvent(keysym, keycode, down); } bool SDisplay::checkLedState() { diff --git a/win/rfb_win32/SDisplay.h b/win/rfb_win32/SDisplay.h index e43e3021..9892ed99 100644 --- a/win/rfb_win32/SDisplay.h +++ b/win/rfb_win32/SDisplay.h @@ -66,7 +66,7 @@ namespace rfb { virtual void start(VNCServer* vs); virtual void stop(); virtual void pointerEvent(const Point& pos, int buttonmask); - virtual void keyEvent(rdr::U32 key, bool down); + virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); virtual void clientCutText(const char* str, int len); virtual Point getFbSize(); diff --git a/win/rfb_win32/SInput.cxx b/win/rfb_win32/SInput.cxx index 0923118a..15ef4b06 100644 --- a/win/rfb_win32/SInput.cxx +++ b/win/rfb_win32/SInput.cxx @@ -321,7 +321,7 @@ win32::SKeyboard::SKeyboard() } -void win32::SKeyboard::keyEvent(rdr::U32 keysym, bool down) +void win32::SKeyboard::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) { for (unsigned int i = 0; i < sizeof(keysymToAscii) / sizeof(keysymToAscii_t); i++) { if (keysymToAscii[i].keysym == keysym) { diff --git a/win/rfb_win32/SInput.h b/win/rfb_win32/SInput.h index 2a0b3e67..f7949ec4 100644 --- a/win/rfb_win32/SInput.h +++ b/win/rfb_win32/SInput.h @@ -53,7 +53,7 @@ namespace rfb { class SKeyboard { public: SKeyboard(); - void keyEvent(rdr::U32 key, bool down); + void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); static BoolParameter deadKeyAware; private: std::map vkMap; -- 2.39.5