[PATCH 00/10] Support QEMU extended keys and led state notification

286 views
Skip to first unread message

Peter Korsgaard

unread,
Jul 12, 2017, 6:36:12 PM7/12/17
to tigervn...@googlegroups.com, Peter Korsgaard
For thin client use cases, the key symbol based keyboard handling in
classical RFB cause problems, as a mapping may not always exist
between the client and server keymap or the indicator led state may
get out of sync.

Similar issues exists for VNC connections to virtual machines, so QEMU
has defined two RFB extensions:

- Extended key events, which transmits a layout independent scancode
together with the keysym

- Keyboard indicator led state notifications from the server to the
client

These extensions are documented in rfbproto:
https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#qemu-extended-key-event-pseudo-encoding

And are supported by gtk-vnc and noVNC on the client side, and QEMU on
the server side.

This patch series implements the server side handling of these two
extensions for x0vncserver and the windows server.

Feedback is very welcome!

Peter Korsgaard (8):
Extend keyEvent callback with a keycode argument
ConnParams: Add QEMU extendend key event pseudo encoding
VNCSConnectionST: negotiate QEMU extended key support
VNCSConnectionST: keyEvent(): skip key tracking for events without a
valid key sym
x0vncserver: keyEvent(): use scancodes if available
ConnParams: Add QEMU led state pseudo encoding
common/rfb: Add led state handling support
x0vncserver: add support for led state notifications

Rahul Kale (2):
rfb_win32: Use scan codes if available
rfb_win32: Add support for LED state notifications

common/rfb/CMsgWriter.cxx | 2 +-
common/rfb/CMsgWriter.h | 2 +-
common/rfb/ConnParams.cxx | 11 +-
common/rfb/ConnParams.h | 3 +
common/rfb/InputHandler.h | 2 +-
common/rfb/SMsgHandler.cxx | 18 ++-
common/rfb/SMsgHandler.h | 8 ++
common/rfb/SMsgReader.cxx | 14 +-
common/rfb/SMsgReader.h | 1 +
common/rfb/SMsgWriter.cxx | 54 ++++++-
common/rfb/SMsgWriter.h | 6 +
common/rfb/ServerCore.cxx | 4 +
common/rfb/ServerCore.h | 1 +
common/rfb/VNCSConnectionST.cxx | 47 +++++-
common/rfb/VNCSConnectionST.h | 5 +-
common/rfb/VNCServer.h | 4 +
common/rfb/VNCServerST.cxx | 13 +-
common/rfb/VNCServerST.h | 3 +
common/rfb/encodings.h | 4 +
common/rfb/msgTypes.h | 2 +
unix/x0vncserver/rfb_to_xorgevdev.h | 262 ++++++++++++++++++++++++++++++++++
unix/x0vncserver/rfb_to_xorgkbd.h | 262 ++++++++++++++++++++++++++++++++++
unix/x0vncserver/x0vncserver.cxx | 110 +++++++++++++-
unix/xserver/hw/vnc/XserverDesktop.cc | 2 +-
unix/xserver/hw/vnc/XserverDesktop.h | 2 +-
vncviewer/Viewport.cxx | 12 +-
win/rfb_win32/SDisplay.cxx | 32 ++++-
win/rfb_win32/SDisplay.h | 5 +-
win/rfb_win32/SInput.cxx | 34 ++++-
win/rfb_win32/SInput.h | 2 +-
30 files changed, 893 insertions(+), 34 deletions(-)
create mode 100644 unix/x0vncserver/rfb_to_xorgevdev.h
create mode 100644 unix/x0vncserver/rfb_to_xorgkbd.h

--
2.11.0

Peter Korsgaard

unread,
Jul 12, 2017, 6:36:16 PM7/12/17
to tigervn...@googlegroups.com, Peter Korsgaard
Signed-off-by: Peter Korsgaard <peter.k...@barco.com>
---
common/rfb/ConnParams.cxx | 5 ++++-
common/rfb/ConnParams.h | 1 +
common/rfb/encodings.h | 3 +++
3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx
index 9ee1d9c0..4d4ca658 100644
--- a/common/rfb/ConnParams.cxx
+++ b/common/rfb/ConnParams.cxx
@@ -35,7 +35,7 @@ ConnParams::ConnParams()
supportsDesktopResize(false), supportsExtendedDesktopSize(false),
supportsDesktopRename(false), supportsLastRect(false),
supportsSetDesktopSize(false), supportsFence(false),
- supportsContinuousUpdates(false),
+ supportsContinuousUpdates(false), supportsExtendedKey(false),
compressLevel(2), qualityLevel(-1), fineQualityLevel(-1),
subsampling(subsampleUndefined), name_(0), verStrPos(0)
{
@@ -147,6 +147,9 @@ void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings)
case pseudoEncodingContinuousUpdates:
supportsContinuousUpdates = true;
break;
+ case pseudoEncodingExtendedKey:
+ supportsExtendedKey = true;
+ break;
case pseudoEncodingSubsamp1X:
subsampling = subsampleNone;
break;
diff --git a/common/rfb/ConnParams.h b/common/rfb/ConnParams.h
index 5e538933..f6b87db3 100644
--- a/common/rfb/ConnParams.h
+++ b/common/rfb/ConnParams.h
@@ -97,6 +97,7 @@ namespace rfb {
bool supportsSetDesktopSize;
bool supportsFence;
bool supportsContinuousUpdates;
+ bool supportsExtendedKey;

int compressLevel;
int qualityLevel;
diff --git a/common/rfb/encodings.h b/common/rfb/encodings.h
index a65d863b..6026bb71 100644
--- a/common/rfb/encodings.h
+++ b/common/rfb/encodings.h
@@ -57,6 +57,9 @@ namespace rfb {
const int pseudoEncodingSubsamp8X = -764;
const int pseudoEncodingSubsamp16X = -763;

+ // QEMU-specific
+ const int pseudoEncodingExtendedKey = -258;
+
int encodingNum(const char* name);
const char* encodingName(int num);
}
--
2.11.0

Peter Korsgaard

unread,
Jul 12, 2017, 6:36:17 PM7/12/17
to tigervn...@googlegroups.com, Peter Korsgaard
Key events from clients supporting the QEMU extended key event message with
keycodes may not contain a valid key symbol. From rfbproto.rst:

"An unknown keycode or keysym should have the value 0."

This causes problems with the pressedKeys tracking as it doesn't take the
keycode into consideration and ignores everything but the first release
event when multiple keys without a keysym are pressed.

As a workaround, don't update pressedKeys if a valid keysym isn't provided.

Signed-off-by: Peter Korsgaard <peter.k...@barco.com>
---
common/rfb/VNCSConnectionST.cxx | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index b044cee6..fd67302b 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -568,10 +568,12 @@ void VNCSConnectionST::keyEvent(rdr::U32 key, rdr::U32 code, bool down) {
key = XK_Tab;
}

+ // events with scancodes may not have a valid key sym
if (down) {
- pressedKeys.insert(key);
+ if (key)
+ pressedKeys.insert(key);
} else {
- if (!pressedKeys.erase(key)) return;
+ if (key && !pressedKeys.erase(key)) return;
}
server->desktop->keyEvent(key, code, down);
}
--
2.11.0

Peter Korsgaard

unread,
Jul 12, 2017, 6:36:18 PM7/12/17
to tigervn...@googlegroups.com, Peter Korsgaard
And interprete the extended key event messages if received by a client.

Hide the logic behind a "AcceptExtendedKeyEvents" option (disabled by
default).

Signed-off-by: Peter Korsgaard <peter.k...@barco.com>
---
common/rfb/SMsgHandler.cxx | 10 +++++++++-
common/rfb/SMsgHandler.h | 4 ++++
common/rfb/SMsgReader.cxx | 12 ++++++++++++
common/rfb/SMsgReader.h | 1 +
common/rfb/SMsgWriter.cxx | 28 +++++++++++++++++++++++++++-
common/rfb/SMsgWriter.h | 3 +++
common/rfb/ServerCore.cxx | 4 ++++
common/rfb/ServerCore.h | 1 +
common/rfb/VNCSConnectionST.cxx | 5 +++++
common/rfb/VNCSConnectionST.h | 1 +
common/rfb/msgTypes.h | 2 ++
11 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx
index 388b21f8..8cb8992b 100644
--- a/common/rfb/SMsgHandler.cxx
+++ b/common/rfb/SMsgHandler.cxx
@@ -41,10 +41,11 @@ void SMsgHandler::setPixelFormat(const PixelFormat& pf)

void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings)
{
- bool firstFence, firstContinuousUpdates;
+ bool firstFence, firstContinuousUpdates, firstExtendedKey;

firstFence = !cp.supportsFence;
firstContinuousUpdates = !cp.supportsContinuousUpdates;
+ firstExtendedKey = !cp.supportsExtendedKey;

cp.setEncodings(nEncodings, encodings);

@@ -54,6 +55,9 @@ void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings)
supportsFence();
if (cp.supportsContinuousUpdates && firstContinuousUpdates)
supportsContinuousUpdates();
+
+ if (cp.supportsExtendedKey && firstExtendedKey)
+ supportsExtendedKey();
}

void SMsgHandler::supportsLocalCursor()
@@ -68,6 +72,10 @@ void SMsgHandler::supportsContinuousUpdates()
{
}

+void SMsgHandler::supportsExtendedKey()
+{
+}
+
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 74509e0b..2a949fcd 100644
--- a/common/rfb/SMsgHandler.h
+++ b/common/rfb/SMsgHandler.h
@@ -74,6 +74,10 @@ namespace rfb {
// this point if it is supported.
virtual void supportsContinuousUpdates();

+ // supportsExtendedKey() is called the first time we detect that the
+ // client supports the extended key message.
+ virtual void supportsExtendedKey();
+
ConnParams cp;
};
}
diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx
index 786200c2..b85fa7ae 100644
--- a/common/rfb/SMsgReader.cxx
+++ b/common/rfb/SMsgReader.cxx
@@ -72,6 +72,9 @@ void SMsgReader::readMsg()
case msgTypeKeyEvent:
readKeyEvent();
break;
+ case msgTypeExtendedKeyEvent:
+ readExtendedKeyEvent();
+ break;
case msgTypePointerEvent:
readPointerEvent();
break;
@@ -187,6 +190,15 @@ void SMsgReader::readKeyEvent()
handler->keyEvent(key, 0, down);
}

+void SMsgReader::readExtendedKeyEvent()
+{
+ is->skip(1);
+ bool down = is->readU16();
+ rdr::U32 key = is->readU32();
+ rdr::U32 code = is->readU32();
+ handler->keyEvent(key, code, down);
+}
+
void SMsgReader::readPointerEvent()
{
int mask = is->readU8();
diff --git a/common/rfb/SMsgReader.h b/common/rfb/SMsgReader.h
index 00cb3031..0a33da09 100644
--- a/common/rfb/SMsgReader.h
+++ b/common/rfb/SMsgReader.h
@@ -52,6 +52,7 @@ namespace rfb {
void readFence();

void readKeyEvent();
+ void readExtendedKeyEvent();
void readPointerEvent();
void readClientCutText();

diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx
index bc3f4398..97306b1a 100644
--- a/common/rfb/SMsgWriter.cxx
+++ b/common/rfb/SMsgWriter.cxx
@@ -37,7 +37,8 @@ SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
nRectsInUpdate(0), nRectsInHeader(0),
needSetDesktopSize(false), needExtendedDesktopSize(false),
needSetDesktopName(false), needSetCursor(false),
- needSetXCursor(false), needSetCursorWithAlpha(false)
+ needSetXCursor(false), needSetCursorWithAlpha(false),
+ needExtendedKey(false)
{
}

@@ -163,6 +164,15 @@ bool SMsgWriter::writeSetDesktopName() {
return true;
}

+bool SMsgWriter::writeExtendedKey() {
+ if (!cp->supportsExtendedKey)
+ return false;
+
+ needExtendedKey = true;
+
+ return true;
+}
+
bool SMsgWriter::writeSetCursor()
{
if (!cp->supportsLocalCursor)
@@ -211,6 +221,8 @@ bool SMsgWriter::needNoDataUpdate()
return true;
if (needExtendedDesktopSize || !extendedDesktopSizeMsgs.empty())
return true;
+ if (needExtendedKey)
+ return true;

return false;
}
@@ -227,6 +239,8 @@ void SMsgWriter::writeNoDataUpdate()
nRects++;
if (!extendedDesktopSizeMsgs.empty())
nRects += extendedDesktopSizeMsgs.size();
+ if (needExtendedKey)
+ nRects++;

writeFramebufferUpdateStart(nRects);
writeNoDataRects();
@@ -385,6 +399,18 @@ void SMsgWriter::writeNoDataRects()
needExtendedDesktopSize = false;
}

+ if (needExtendedKey) {
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriter::writeNoDataRects: nRects out of sync");
+
+ os->writeS16(0);
+ os->writeS16(0);
+ os->writeU16(0);
+ os->writeU16(0);
+ os->writeU32(pseudoEncodingExtendedKey);
+ needExtendedKey = false;
+ }
+
// Some clients assume this is the last rectangle so don't send anything
// more after this
if (needSetDesktopSize) {
diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h
index 548b8e8e..98617231 100644
--- a/common/rfb/SMsgWriter.h
+++ b/common/rfb/SMsgWriter.h
@@ -76,6 +76,8 @@ namespace rfb {

bool writeSetDesktopName();

+ bool writeExtendedKey();
+
// Like setDesktopSize, we can't just write out a cursor message
// immediately.
bool writeSetCursor();
@@ -145,6 +147,7 @@ namespace rfb {
bool needSetCursor;
bool needSetXCursor;
bool needSetCursorWithAlpha;
+ bool needExtendedKey;

typedef struct {
rdr::U16 reason, result;
diff --git a/common/rfb/ServerCore.cxx b/common/rfb/ServerCore.cxx
index 59a7cff3..b21336df 100644
--- a/common/rfb/ServerCore.cxx
+++ b/common/rfb/ServerCore.cxx
@@ -85,6 +85,10 @@ rfb::BoolParameter rfb::Server::acceptPointerEvents
("AcceptPointerEvents",
"Accept pointer press and release events from clients.",
true);
+rfb::BoolParameter rfb::Server::acceptExtendedKeyEvents
+("AcceptExtendedKeyEvents",
+ "Accept extended key press and release events from clients.",
+ false);
rfb::BoolParameter rfb::Server::acceptCutText
("AcceptCutText",
"Accept clipboard updates from clients.",
diff --git a/common/rfb/ServerCore.h b/common/rfb/ServerCore.h
index 37923cc1..d7cdcb06 100644
--- a/common/rfb/ServerCore.h
+++ b/common/rfb/ServerCore.h
@@ -45,6 +45,7 @@ namespace rfb {
static BoolParameter disconnectClients;
static BoolParameter acceptKeyEvents;
static BoolParameter acceptPointerEvents;
+ static BoolParameter acceptExtendedKeyEvents;
static BoolParameter acceptCutText;
static BoolParameter sendCutText;
static BoolParameter acceptSetDesktopSize;
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index 3f8ce8d6..b044cee6 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -747,6 +747,11 @@ void VNCSConnectionST::supportsContinuousUpdates()
writer()->writeEndOfContinuousUpdates();
}

+void VNCSConnectionST::supportsExtendedKey()
+{
+ if (!rfb::Server::acceptExtendedKeyEvents) return;
+ writer()->writeExtendedKey();
+}

bool VNCSConnectionST::handleTimeout(Timer* t)
{
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index 7fcca7fd..9f7ab8e1 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -146,6 +146,7 @@ namespace rfb {
virtual void supportsLocalCursor();
virtual void supportsFence();
virtual void supportsContinuousUpdates();
+ virtual void supportsExtendedKey();

// setAccessRights() allows a security package to limit the access rights
// of a VNCSConnectioST to the server. These access rights are applied
diff --git a/common/rfb/msgTypes.h b/common/rfb/msgTypes.h
index a55e1c50..fa5745d1 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 msgTypeExtendedKeyEvent = 255;
}
#endif
--
2.11.0

Peter Korsgaard

unread,
Jul 12, 2017, 6:36:20 PM7/12/17
to tigervn...@googlegroups.com, Peter Korsgaard
Use the client provided (using QEMU extendend key event) scancodes if
available instead of reverse mapping the keysym.

X11 unfortunately uses keyboard driver specific keycodes and provides
no direct way to query this, so guess based on the keyboard mapping.

Handle the two most likely keyboard drivers, the old xorgkbd and evdev.

RFB->evdev and RFB->xorgkbd scancode mapping is from keycodemap:

https://gitlab.com/keycodemap/keycodemapdb

A keycodemapdb patch is needed to generate tables suitable for C++. A pull
request has been sent, but has so far not been integrated:

https://gitlab.com/keycodemap/keycodemapdb/merge_requests/2

Signed-off-by: Peter Korsgaard <peter.k...@barco.com>
---
unix/x0vncserver/rfb_to_xorgevdev.h | 262 ++++++++++++++++++++++++++++++++++++
unix/x0vncserver/rfb_to_xorgkbd.h | 262 ++++++++++++++++++++++++++++++++++++
unix/x0vncserver/x0vncserver.cxx | 46 ++++++-
3 files changed, 568 insertions(+), 2 deletions(-)
create mode 100644 unix/x0vncserver/rfb_to_xorgevdev.h
create mode 100644 unix/x0vncserver/rfb_to_xorgkbd.h

diff --git a/unix/x0vncserver/rfb_to_xorgevdev.h b/unix/x0vncserver/rfb_to_xorgevdev.h
new file mode 100644
index 00000000..026ae727
--- /dev/null
+++ b/unix/x0vncserver/rfb_to_xorgevdev.h
@@ -0,0 +1,262 @@
+/*
+ * This file is auto-generated from keymaps.csv on 2017-05-22 16:43
+ * Database checksum sha256(f45720dc09778503dea402d7b4c742d746b01d4c74155c4633a69f40d938a363)
+ * To re-generate, run:
+ * keymap-gen --lang=stdc++ code-map keymaps.csv rfb xorgevdev
+*/
+const unsigned short code_map_rfb_to_xorgevdev[254] = {
+ 0, /* rfb:0 -> linux:None (unnamed) -> xorgevdev:None */
+ 0x9, /* rfb:1 -> linux:1 (KEY_ESC) -> xorgevdev:9 */
+ 0xa, /* rfb:2 -> linux:2 (KEY_1) -> xorgevdev:10 */
+ 0xb, /* rfb:3 -> linux:3 (KEY_2) -> xorgevdev:11 */
+ 0xc, /* rfb:4 -> linux:4 (KEY_3) -> xorgevdev:12 */
+ 0xd, /* rfb:5 -> linux:5 (KEY_4) -> xorgevdev:13 */
+ 0xe, /* rfb:6 -> linux:6 (KEY_5) -> xorgevdev:14 */
+ 0xf, /* rfb:7 -> linux:7 (KEY_6) -> xorgevdev:15 */
+ 0x10, /* rfb:8 -> linux:8 (KEY_7) -> xorgevdev:16 */
+ 0x11, /* rfb:9 -> linux:9 (KEY_8) -> xorgevdev:17 */
+ 0x12, /* rfb:10 -> linux:10 (KEY_9) -> xorgevdev:18 */
+ 0x13, /* rfb:11 -> linux:11 (KEY_0) -> xorgevdev:19 */
+ 0x14, /* rfb:12 -> linux:12 (KEY_MINUS) -> xorgevdev:20 */
+ 0x15, /* rfb:13 -> linux:13 (KEY_EQUAL) -> xorgevdev:21 */
+ 0x16, /* rfb:14 -> linux:14 (KEY_BACKSPACE) -> xorgevdev:22 */
+ 0x17, /* rfb:15 -> linux:15 (KEY_TAB) -> xorgevdev:23 */
+ 0x18, /* rfb:16 -> linux:16 (KEY_Q) -> xorgevdev:24 */
+ 0x19, /* rfb:17 -> linux:17 (KEY_W) -> xorgevdev:25 */
+ 0x1a, /* rfb:18 -> linux:18 (KEY_E) -> xorgevdev:26 */
+ 0x1b, /* rfb:19 -> linux:19 (KEY_R) -> xorgevdev:27 */
+ 0x1c, /* rfb:20 -> linux:20 (KEY_T) -> xorgevdev:28 */
+ 0x1d, /* rfb:21 -> linux:21 (KEY_Y) -> xorgevdev:29 */
+ 0x1e, /* rfb:22 -> linux:22 (KEY_U) -> xorgevdev:30 */
+ 0x1f, /* rfb:23 -> linux:23 (KEY_I) -> xorgevdev:31 */
+ 0x20, /* rfb:24 -> linux:24 (KEY_O) -> xorgevdev:32 */
+ 0x21, /* rfb:25 -> linux:25 (KEY_P) -> xorgevdev:33 */
+ 0x22, /* rfb:26 -> linux:26 (KEY_LEFTBRACE) -> xorgevdev:34 */
+ 0x23, /* rfb:27 -> linux:27 (KEY_RIGHTBRACE) -> xorgevdev:35 */
+ 0x24, /* rfb:28 -> linux:28 (KEY_ENTER) -> xorgevdev:36 */
+ 0x25, /* rfb:29 -> linux:29 (KEY_LEFTCTRL) -> xorgevdev:37 */
+ 0x26, /* rfb:30 -> linux:30 (KEY_A) -> xorgevdev:38 */
+ 0x27, /* rfb:31 -> linux:31 (KEY_S) -> xorgevdev:39 */
+ 0x28, /* rfb:32 -> linux:32 (KEY_D) -> xorgevdev:40 */
+ 0x29, /* rfb:33 -> linux:33 (KEY_F) -> xorgevdev:41 */
+ 0x2a, /* rfb:34 -> linux:34 (KEY_G) -> xorgevdev:42 */
+ 0x2b, /* rfb:35 -> linux:35 (KEY_H) -> xorgevdev:43 */
+ 0x2c, /* rfb:36 -> linux:36 (KEY_J) -> xorgevdev:44 */
+ 0x2d, /* rfb:37 -> linux:37 (KEY_K) -> xorgevdev:45 */
+ 0x2e, /* rfb:38 -> linux:38 (KEY_L) -> xorgevdev:46 */
+ 0x2f, /* rfb:39 -> linux:39 (KEY_SEMICOLON) -> xorgevdev:47 */
+ 0x30, /* rfb:40 -> linux:40 (KEY_APOSTROPHE) -> xorgevdev:48 */
+ 0x31, /* rfb:41 -> linux:41 (KEY_GRAVE) -> xorgevdev:49 */
+ 0x32, /* rfb:42 -> linux:42 (KEY_LEFTSHIFT) -> xorgevdev:50 */
+ 0x33, /* rfb:43 -> linux:43 (KEY_BACKSLASH) -> xorgevdev:51 */
+ 0x34, /* rfb:44 -> linux:44 (KEY_Z) -> xorgevdev:52 */
+ 0x35, /* rfb:45 -> linux:45 (KEY_X) -> xorgevdev:53 */
+ 0x36, /* rfb:46 -> linux:46 (KEY_C) -> xorgevdev:54 */
+ 0x37, /* rfb:47 -> linux:47 (KEY_V) -> xorgevdev:55 */
+ 0x38, /* rfb:48 -> linux:48 (KEY_B) -> xorgevdev:56 */
+ 0x39, /* rfb:49 -> linux:49 (KEY_N) -> xorgevdev:57 */
+ 0x3a, /* rfb:50 -> linux:50 (KEY_M) -> xorgevdev:58 */
+ 0x3b, /* rfb:51 -> linux:51 (KEY_COMMA) -> xorgevdev:59 */
+ 0x3c, /* rfb:52 -> linux:52 (KEY_DOT) -> xorgevdev:60 */
+ 0x3d, /* rfb:53 -> linux:53 (KEY_SLASH) -> xorgevdev:61 */
+ 0x3e, /* rfb:54 -> linux:54 (KEY_RIGHTSHIFT) -> xorgevdev:62 */
+ 0x3f, /* rfb:55 -> linux:55 (KEY_KPASTERISK) -> xorgevdev:63 */
+ 0x40, /* rfb:56 -> linux:56 (KEY_LEFTALT) -> xorgevdev:64 */
+ 0x41, /* rfb:57 -> linux:57 (KEY_SPACE) -> xorgevdev:65 */
+ 0x42, /* rfb:58 -> linux:58 (KEY_CAPSLOCK) -> xorgevdev:66 */
+ 0x43, /* rfb:59 -> linux:59 (KEY_F1) -> xorgevdev:67 */
+ 0x44, /* rfb:60 -> linux:60 (KEY_F2) -> xorgevdev:68 */
+ 0x45, /* rfb:61 -> linux:61 (KEY_F3) -> xorgevdev:69 */
+ 0x46, /* rfb:62 -> linux:62 (KEY_F4) -> xorgevdev:70 */
+ 0x47, /* rfb:63 -> linux:63 (KEY_F5) -> xorgevdev:71 */
+ 0x48, /* rfb:64 -> linux:64 (KEY_F6) -> xorgevdev:72 */
+ 0x49, /* rfb:65 -> linux:65 (KEY_F7) -> xorgevdev:73 */
+ 0x4a, /* rfb:66 -> linux:66 (KEY_F8) -> xorgevdev:74 */
+ 0x4b, /* rfb:67 -> linux:67 (KEY_F9) -> xorgevdev:75 */
+ 0x4c, /* rfb:68 -> linux:68 (KEY_F10) -> xorgevdev:76 */
+ 0x4d, /* rfb:69 -> linux:69 (KEY_NUMLOCK) -> xorgevdev:77 */
+ 0x4e, /* rfb:70 -> linux:70 (KEY_SCROLLLOCK) -> xorgevdev:78 */
+ 0x4f, /* rfb:71 -> linux:71 (KEY_KP7) -> xorgevdev:79 */
+ 0x50, /* rfb:72 -> linux:72 (KEY_KP8) -> xorgevdev:80 */
+ 0x51, /* rfb:73 -> linux:73 (KEY_KP9) -> xorgevdev:81 */
+ 0x52, /* rfb:74 -> linux:74 (KEY_KPMINUS) -> xorgevdev:82 */
+ 0x53, /* rfb:75 -> linux:75 (KEY_KP4) -> xorgevdev:83 */
+ 0x54, /* rfb:76 -> linux:76 (KEY_KP5) -> xorgevdev:84 */
+ 0x55, /* rfb:77 -> linux:77 (KEY_KP6) -> xorgevdev:85 */
+ 0x56, /* rfb:78 -> linux:78 (KEY_KPPLUS) -> xorgevdev:86 */
+ 0x57, /* rfb:79 -> linux:79 (KEY_KP1) -> xorgevdev:87 */
+ 0x58, /* rfb:80 -> linux:80 (KEY_KP2) -> xorgevdev:88 */
+ 0x59, /* rfb:81 -> linux:81 (KEY_KP3) -> xorgevdev:89 */
+ 0x5a, /* rfb:82 -> linux:82 (KEY_KP0) -> xorgevdev:90 */
+ 0x5b, /* rfb:83 -> linux:83 (KEY_KPDOT) -> xorgevdev:91 */
+ 0x6b, /* rfb:84 -> linux:99 (KEY_SYSRQ) -> xorgevdev:107 */
+ 0xc2, /* rfb:85 -> linux:186 (KEY_F16) -> xorgevdev:194 */
+ 0x5e, /* rfb:86 -> linux:86 (KEY_102ND) -> xorgevdev:94 */
+ 0x5f, /* rfb:87 -> linux:87 (KEY_F11) -> xorgevdev:95 */
+ 0x60, /* rfb:88 -> linux:88 (KEY_F12) -> xorgevdev:96 */
+ 0x7d, /* rfb:89 -> linux:117 (KEY_KPEQUAL) -> xorgevdev:125 */
+ 0xc6, /* rfb:90 -> linux:190 (KEY_F20) -> xorgevdev:198 */
+ 0x6d, /* rfb:91 -> linux:101 (KEY_LINEFEED) -> xorgevdev:109 */
+ 0x67, /* rfb:92 -> linux:95 (KEY_KPJPCOMMA) -> xorgevdev:103 */
+ 0xbf, /* rfb:93 -> linux:183 (KEY_F13) -> xorgevdev:191 */
+ 0xc0, /* rfb:94 -> linux:184 (KEY_F14) -> xorgevdev:192 */
+ 0xc1, /* rfb:95 -> linux:185 (KEY_F15) -> xorgevdev:193 */
+ 0, /* rfb:96 -> linux:None (unnamed) -> xorgevdev:None */
+ 0, /* rfb:97 -> linux:None (unnamed) -> xorgevdev:None */
+ 0, /* rfb:98 -> linux:None (unnamed) -> xorgevdev:None */
+ 0xb1, /* rfb:99 -> linux:169 (KEY_PHONE) -> xorgevdev:177 */
+ 0x8e, /* rfb:100 -> linux:134 (KEY_OPEN) -> xorgevdev:142 */
+ 0x8f, /* rfb:101 -> linux:135 (KEY_PASTE) -> xorgevdev:143 */
+ 0x95, /* rfb:102 -> linux:141 (KEY_SETUP) -> xorgevdev:149 */
+ 0x98, /* rfb:103 -> linux:144 (KEY_FILE) -> xorgevdev:152 */
+ 0x99, /* rfb:104 -> linux:145 (KEY_SENDFILE) -> xorgevdev:153 */
+ 0x9a, /* rfb:105 -> linux:146 (KEY_DELETEFILE) -> xorgevdev:154 */
+ 0x9f, /* rfb:106 -> linux:151 (KEY_MSDOS) -> xorgevdev:159 */
+ 0xa1, /* rfb:107 -> linux:153 (KEY_DIRECTION) -> xorgevdev:161 */
+ 0xa9, /* rfb:108 -> linux:161 (KEY_EJECTCD) -> xorgevdev:169 */
+ 0xc9, /* rfb:109 -> linux:193 (KEY_F23) -> xorgevdev:201 */
+ 0, /* rfb:110 -> linux:None (unnamed) -> xorgevdev:None */
+ 0xca, /* rfb:111 -> linux:194 (KEY_F24) -> xorgevdev:202 */
+ 0xb2, /* rfb:112 -> linux:170 (KEY_ISO) -> xorgevdev:178 */
+ 0xb6, /* rfb:113 -> linux:174 (KEY_EXIT) -> xorgevdev:182 */
+ 0xb7, /* rfb:114 -> linux:175 (KEY_MOVE) -> xorgevdev:183 */
+ 0x61, /* rfb:115 -> linux:89 (KEY_RO) -> xorgevdev:97 */
+ 0xc7, /* rfb:116 -> linux:191 (KEY_F21) -> xorgevdev:199 */
+ 0xb9, /* rfb:117 -> linux:177 (KEY_SCROLLUP) -> xorgevdev:185 */
+ 0x5d, /* rfb:118 -> linux:85 (KEY_ZENKAKUHANKAKU) -> xorgevdev:93 */
+ 0x63, /* rfb:119 -> linux:91 (KEY_HIRAGANA) -> xorgevdev:99 */
+ 0x62, /* rfb:120 -> linux:90 (KEY_KATAKANA) -> xorgevdev:98 */
+ 0x64, /* rfb:121 -> linux:92 (KEY_HENKAN) -> xorgevdev:100 */
+ 0, /* rfb:122 -> linux:None (unnamed) -> xorgevdev:None */
+ 0x66, /* rfb:123 -> linux:94 (KEY_MUHENKAN) -> xorgevdev:102 */
+ 0, /* rfb:124 -> linux:None (unnamed) -> xorgevdev:None */
+ 0x84, /* rfb:125 -> linux:124 (KEY_YEN) -> xorgevdev:132 */
+ 0x81, /* rfb:126 -> linux:121 (KEY_KPCOMMA) -> xorgevdev:129 */
+ 0, /* rfb:127 -> linux:None (unnamed) -> xorgevdev:None */
+ 0, /* rfb:128 -> linux:None (unnamed) -> xorgevdev:None */
+ 0xb3, /* rfb:129 -> linux:171 (KEY_CONFIG) -> xorgevdev:179 */
+ 0x9e, /* rfb:130 -> linux:150 (KEY_WWW) -> xorgevdev:158 */
+ 0xc3, /* rfb:131 -> linux:187 (KEY_F17) -> xorgevdev:195 */
+ 0xc5, /* rfb:132 -> linux:189 (KEY_F19) -> xorgevdev:197 */
+ 0x89, /* rfb:133 -> linux:129 (KEY_AGAIN) -> xorgevdev:137 */
+ 0x8a, /* rfb:134 -> linux:130 (KEY_PROPS) -> xorgevdev:138 */
+ 0x8b, /* rfb:135 -> linux:131 (KEY_UNDO) -> xorgevdev:139 */
+ 0xb8, /* rfb:136 -> linux:176 (KEY_EDIT) -> xorgevdev:184 */
+ 0xbd, /* rfb:137 -> linux:181 (KEY_NEW) -> xorgevdev:189 */
+ 0xbe, /* rfb:138 -> linux:182 (KEY_REDO) -> xorgevdev:190 */
+ 0x80, /* rfb:139 -> linux:120 (KEY_SCALE) -> xorgevdev:128 */
+ 0x8c, /* rfb:140 -> linux:132 (KEY_FRONT) -> xorgevdev:140 */
+ 0x83, /* rfb:141 -> linux:123 (KEY_HANJA) -> xorgevdev:131 */
+ 0xf1, /* rfb:142 -> linux:233 (KEY_FORWARDMAIL) -> xorgevdev:241 */
+ 0xba, /* rfb:143 -> linux:178 (KEY_SCROLLDOWN) -> xorgevdev:186 */
+ 0xad, /* rfb:144 -> linux:165 (KEY_PREVIOUSSONG) -> xorgevdev:173 */
+ 0, /* rfb:145 -> linux:None (unnamed) -> xorgevdev:None */
+ 0xa0, /* rfb:146 -> linux:152 (KEY_SCREENLOCK) -> xorgevdev:160 */
+ 0x9b, /* rfb:147 -> linux:147 (KEY_XFER) -> xorgevdev:155 */
+ 0xe6, /* rfb:148 -> linux:222 (KEY_ALTERASE) -> xorgevdev:230 */
+ 0xcb, /* rfb:149 -> linux:195 (unnamed) -> xorgevdev:203 */
+ 0xcc, /* rfb:150 -> linux:196 (unnamed) -> xorgevdev:204 */
+ 0x9d, /* rfb:151 -> linux:149 (KEY_PROG2) -> xorgevdev:157 */
+ 0xb0, /* rfb:152 -> linux:168 (KEY_REWIND) -> xorgevdev:176 */
+ 0xab, /* rfb:153 -> linux:163 (KEY_NEXTSONG) -> xorgevdev:171 */
+ 0xcd, /* rfb:154 -> linux:197 (unnamed) -> xorgevdev:205 */
+ 0xce, /* rfb:155 -> linux:198 (unnamed) -> xorgevdev:206 */
+ 0x68, /* rfb:156 -> linux:96 (KEY_KPENTER) -> xorgevdev:104 */
+ 0x69, /* rfb:157 -> linux:97 (KEY_RIGHTCTRL) -> xorgevdev:105 */
+ 0x93, /* rfb:158 -> linux:139 (KEY_MENU) -> xorgevdev:147 */
+ 0x9c, /* rfb:159 -> linux:148 (KEY_PROG1) -> xorgevdev:156 */
+ 0x79, /* rfb:160 -> linux:113 (KEY_MUTE) -> xorgevdev:121 */
+ 0x94, /* rfb:161 -> linux:140 (KEY_CALC) -> xorgevdev:148 */
+ 0xac, /* rfb:162 -> linux:164 (KEY_PLAYPAUSE) -> xorgevdev:172 */
+ 0xa8, /* rfb:163 -> linux:160 (KEY_CLOSECD) -> xorgevdev:168 */
+ 0xae, /* rfb:164 -> linux:166 (KEY_STOPCD) -> xorgevdev:174 */
+ 0xd5, /* rfb:165 -> linux:205 (KEY_SUSPEND) -> xorgevdev:213 */
+ 0xa2, /* rfb:166 -> linux:154 (KEY_CYCLEWINDOWS) -> xorgevdev:162 */
+ 0xcf, /* rfb:167 -> linux:199 (unnamed) -> xorgevdev:207 */
+ 0xd0, /* rfb:168 -> linux:200 (KEY_PLAYCD) -> xorgevdev:208 */
+ 0xd1, /* rfb:169 -> linux:201 (KEY_PAUSECD) -> xorgevdev:209 */
+ 0, /* rfb:170 -> linux:None (unnamed) -> xorgevdev:None */
+ 0xd2, /* rfb:171 -> linux:202 (KEY_PROG3) -> xorgevdev:210 */
+ 0xd3, /* rfb:172 -> linux:203 (KEY_PROG4) -> xorgevdev:211 */
+ 0xd4, /* rfb:173 -> linux:204 (KEY_DASHBOARD) -> xorgevdev:212 */
+ 0x7a, /* rfb:174 -> linux:114 (KEY_VOLUMEDOWN) -> xorgevdev:122 */
+ 0xd6, /* rfb:175 -> linux:206 (KEY_CLOSE) -> xorgevdev:214 */
+ 0x7b, /* rfb:176 -> linux:115 (KEY_VOLUMEUP) -> xorgevdev:123 */
+ 0xaf, /* rfb:177 -> linux:167 (KEY_RECORD) -> xorgevdev:175 */
+ 0xb4, /* rfb:178 -> linux:172 (KEY_HOMEPAGE) -> xorgevdev:180 */
+ 0xd7, /* rfb:179 -> linux:207 (KEY_PLAY) -> xorgevdev:215 */
+ 0xd8, /* rfb:180 -> linux:208 (KEY_FASTFORWARD) -> xorgevdev:216 */
+ 0x6a, /* rfb:181 -> linux:98 (KEY_KPSLASH) -> xorgevdev:106 */
+ 0xd9, /* rfb:182 -> linux:209 (KEY_BASSBOOST) -> xorgevdev:217 */
+ 0x6b, /* rfb:183 -> linux:99 (KEY_SYSRQ) -> xorgevdev:107 (qemu compat) */
+ 0x6c, /* rfb:184 -> linux:100 (KEY_RIGHTALT) -> xorgevdev:108 */
+ 0xda, /* rfb:185 -> linux:210 (KEY_PRINT) -> xorgevdev:218 */
+ 0xdb, /* rfb:186 -> linux:211 (KEY_HP) -> xorgevdev:219 */
+ 0xdc, /* rfb:187 -> linux:212 (KEY_CAMERA) -> xorgevdev:220 */
+ 0x91, /* rfb:188 -> linux:137 (KEY_CUT) -> xorgevdev:145 */
+ 0xdd, /* rfb:189 -> linux:213 (KEY_SOUND) -> xorgevdev:221 */
+ 0xde, /* rfb:190 -> linux:214 (KEY_QUESTION) -> xorgevdev:222 */
+ 0xdf, /* rfb:191 -> linux:215 (KEY_EMAIL) -> xorgevdev:223 */
+ 0xe0, /* rfb:192 -> linux:216 (KEY_CHAT) -> xorgevdev:224 */
+ 0x90, /* rfb:193 -> linux:136 (KEY_FIND) -> xorgevdev:144 */
+ 0xe2, /* rfb:194 -> linux:218 (KEY_CONNECT) -> xorgevdev:226 */
+ 0xe3, /* rfb:195 -> linux:219 (KEY_FINANCE) -> xorgevdev:227 */
+ 0xe4, /* rfb:196 -> linux:220 (KEY_SPORT) -> xorgevdev:228 */
+ 0x7f, /* rfb:197 -> linux:119 (KEY_PAUSE) -> xorgevdev:127 (qemu compat) */
+ 0x7f, /* rfb:198 -> linux:119 (KEY_PAUSE) -> xorgevdev:127 */
+ 0x6e, /* rfb:199 -> linux:102 (KEY_HOME) -> xorgevdev:110 */
+ 0x6f, /* rfb:200 -> linux:103 (KEY_UP) -> xorgevdev:111 */
+ 0x70, /* rfb:201 -> linux:104 (KEY_PAGEUP) -> xorgevdev:112 */
+ 0xe7, /* rfb:202 -> linux:223 (KEY_CANCEL) -> xorgevdev:231 */
+ 0x71, /* rfb:203 -> linux:105 (KEY_LEFT) -> xorgevdev:113 */
+ 0xe8, /* rfb:204 -> linux:224 (KEY_BRIGHTNESSDOWN) -> xorgevdev:232 */
+ 0x72, /* rfb:205 -> linux:106 (KEY_RIGHT) -> xorgevdev:114 */
+ 0x7e, /* rfb:206 -> linux:118 (KEY_KPPLUSMINUS) -> xorgevdev:126 */
+ 0x73, /* rfb:207 -> linux:107 (KEY_END) -> xorgevdev:115 */
+ 0x74, /* rfb:208 -> linux:108 (KEY_DOWN) -> xorgevdev:116 */
+ 0x75, /* rfb:209 -> linux:109 (KEY_PAGEDOWN) -> xorgevdev:117 */
+ 0x76, /* rfb:210 -> linux:110 (KEY_INSERT) -> xorgevdev:118 */
+ 0x77, /* rfb:211 -> linux:111 (KEY_DELETE) -> xorgevdev:119 */
+ 0xe9, /* rfb:212 -> linux:225 (KEY_BRIGHTNESSUP) -> xorgevdev:233 */
+ 0xf2, /* rfb:213 -> linux:234 (KEY_SAVE) -> xorgevdev:242 */
+ 0xeb, /* rfb:214 -> linux:227 (KEY_SWITCHVIDEOMODE) -> xorgevdev:235 */
+ 0xec, /* rfb:215 -> linux:228 (KEY_KBDILLUMTOGGLE) -> xorgevdev:236 */
+ 0xed, /* rfb:216 -> linux:229 (KEY_KBDILLUMDOWN) -> xorgevdev:237 */
+ 0xee, /* rfb:217 -> linux:230 (KEY_KBDILLUMUP) -> xorgevdev:238 */
+ 0xef, /* rfb:218 -> linux:231 (KEY_SEND) -> xorgevdev:239 */
+ 0x85, /* rfb:219 -> linux:125 (KEY_LEFTMETA) -> xorgevdev:133 */
+ 0x86, /* rfb:220 -> linux:126 (KEY_RIGHTMETA) -> xorgevdev:134 */
+ 0x87, /* rfb:221 -> linux:127 (KEY_COMPOSE) -> xorgevdev:135 */
+ 0x7c, /* rfb:222 -> linux:116 (KEY_POWER) -> xorgevdev:124 */
+ 0x96, /* rfb:223 -> linux:142 (KEY_SLEEP) -> xorgevdev:150 */
+ 0, /* rfb:224 -> linux:None (unnamed) -> xorgevdev:None */
+ 0, /* rfb:225 -> linux:None (unnamed) -> xorgevdev:None */
+ 0, /* rfb:226 -> linux:None (unnamed) -> xorgevdev:None */
+ 0x97, /* rfb:227 -> linux:143 (KEY_WAKEUP) -> xorgevdev:151 */
+ 0xf0, /* rfb:228 -> linux:232 (KEY_REPLY) -> xorgevdev:240 */
+ 0xe1, /* rfb:229 -> linux:217 (KEY_SEARCH) -> xorgevdev:225 */
+ 0xa4, /* rfb:230 -> linux:156 (KEY_BOOKMARKS) -> xorgevdev:164 */
+ 0xb5, /* rfb:231 -> linux:173 (KEY_REFRESH) -> xorgevdev:181 */
+ 0x88, /* rfb:232 -> linux:128 (KEY_STOP) -> xorgevdev:136 */
+ 0xa7, /* rfb:233 -> linux:159 (KEY_FORWARD) -> xorgevdev:167 */
+ 0xa6, /* rfb:234 -> linux:158 (KEY_BACK) -> xorgevdev:166 */
+ 0xa5, /* rfb:235 -> linux:157 (KEY_COMPUTER) -> xorgevdev:165 */
+ 0xa3, /* rfb:236 -> linux:155 (KEY_MAIL) -> xorgevdev:163 */
+ 0xea, /* rfb:237 -> linux:226 (KEY_MEDIA) -> xorgevdev:234 */
+ 0, /* rfb:238 -> linux:None (unnamed) -> xorgevdev:None */
+ 0x78, /* rfb:239 -> linux:112 (KEY_MACRO) -> xorgevdev:120 */
+ 0xf3, /* rfb:240 -> linux:235 (KEY_DOCUMENTS) -> xorgevdev:243 */
+ 0xf4, /* rfb:241 -> linux:236 (KEY_BATTERY) -> xorgevdev:244 */
+ 0xf5, /* rfb:242 -> linux:237 (KEY_BLUETOOTH) -> xorgevdev:245 */
+ 0xf6, /* rfb:243 -> linux:238 (KEY_WLAN) -> xorgevdev:246 */
+ 0xf7, /* rfb:244 -> linux:239 (KEY_UWB) -> xorgevdev:247 */
+ 0x92, /* rfb:245 -> linux:138 (KEY_HELP) -> xorgevdev:146 */
+ 0xbb, /* rfb:246 -> linux:179 (KEY_KPLEFTPAREN) -> xorgevdev:187 */
+ 0xc4, /* rfb:247 -> linux:188 (KEY_F18) -> xorgevdev:196 */
+ 0x8d, /* rfb:248 -> linux:133 (KEY_COPY) -> xorgevdev:141 */
+ 0xc8, /* rfb:249 -> linux:192 (KEY_F22) -> xorgevdev:200 */
+ 0, /* rfb:250 -> linux:None (unnamed) -> xorgevdev:None */
+ 0xbc, /* rfb:251 -> linux:180 (KEY_KPRIGHTPAREN) -> xorgevdev:188 */
+ 0, /* rfb:252 -> linux:None (unnamed) -> xorgevdev:None */
+ 0xaa, /* rfb:253 -> linux:162 (KEY_EJECTCLOSECD) -> xorgevdev:170 */
+};
diff --git a/unix/x0vncserver/rfb_to_xorgkbd.h b/unix/x0vncserver/rfb_to_xorgkbd.h
new file mode 100644
index 00000000..ee935520
--- /dev/null
+++ b/unix/x0vncserver/rfb_to_xorgkbd.h
@@ -0,0 +1,262 @@
+/*
+ * This file is auto-generated from keymaps.csv on 2017-05-22 17:20
+ * Database checksum sha256(f45720dc09778503dea402d7b4c742d746b01d4c74155c4633a69f40d938a363)
+ * To re-generate, run:
+ * keymap-gen --lang=stdc++ code-map keymaps.csv rfb xorgkbd
+*/
+const unsigned short code_map_rfb_to_xorgkbd[254] = {
+ 0, /* rfb:0 -> linux:None (unnamed) -> xorgkbd:None */
+ 0x9, /* rfb:1 -> linux:1 (KEY_ESC) -> xorgkbd:9 */
+ 0xa, /* rfb:2 -> linux:2 (KEY_1) -> xorgkbd:10 */
+ 0xb, /* rfb:3 -> linux:3 (KEY_2) -> xorgkbd:11 */
+ 0xc, /* rfb:4 -> linux:4 (KEY_3) -> xorgkbd:12 */
+ 0xd, /* rfb:5 -> linux:5 (KEY_4) -> xorgkbd:13 */
+ 0xe, /* rfb:6 -> linux:6 (KEY_5) -> xorgkbd:14 */
+ 0xf, /* rfb:7 -> linux:7 (KEY_6) -> xorgkbd:15 */
+ 0x10, /* rfb:8 -> linux:8 (KEY_7) -> xorgkbd:16 */
+ 0x11, /* rfb:9 -> linux:9 (KEY_8) -> xorgkbd:17 */
+ 0x12, /* rfb:10 -> linux:10 (KEY_9) -> xorgkbd:18 */
+ 0x13, /* rfb:11 -> linux:11 (KEY_0) -> xorgkbd:19 */
+ 0x14, /* rfb:12 -> linux:12 (KEY_MINUS) -> xorgkbd:20 */
+ 0x15, /* rfb:13 -> linux:13 (KEY_EQUAL) -> xorgkbd:21 */
+ 0x16, /* rfb:14 -> linux:14 (KEY_BACKSPACE) -> xorgkbd:22 */
+ 0x17, /* rfb:15 -> linux:15 (KEY_TAB) -> xorgkbd:23 */
+ 0x18, /* rfb:16 -> linux:16 (KEY_Q) -> xorgkbd:24 */
+ 0x19, /* rfb:17 -> linux:17 (KEY_W) -> xorgkbd:25 */
+ 0x1a, /* rfb:18 -> linux:18 (KEY_E) -> xorgkbd:26 */
+ 0x1b, /* rfb:19 -> linux:19 (KEY_R) -> xorgkbd:27 */
+ 0x1c, /* rfb:20 -> linux:20 (KEY_T) -> xorgkbd:28 */
+ 0x1d, /* rfb:21 -> linux:21 (KEY_Y) -> xorgkbd:29 */
+ 0x1e, /* rfb:22 -> linux:22 (KEY_U) -> xorgkbd:30 */
+ 0x1f, /* rfb:23 -> linux:23 (KEY_I) -> xorgkbd:31 */
+ 0x20, /* rfb:24 -> linux:24 (KEY_O) -> xorgkbd:32 */
+ 0x21, /* rfb:25 -> linux:25 (KEY_P) -> xorgkbd:33 */
+ 0x22, /* rfb:26 -> linux:26 (KEY_LEFTBRACE) -> xorgkbd:34 */
+ 0x23, /* rfb:27 -> linux:27 (KEY_RIGHTBRACE) -> xorgkbd:35 */
+ 0x24, /* rfb:28 -> linux:28 (KEY_ENTER) -> xorgkbd:36 */
+ 0x25, /* rfb:29 -> linux:29 (KEY_LEFTCTRL) -> xorgkbd:37 */
+ 0x26, /* rfb:30 -> linux:30 (KEY_A) -> xorgkbd:38 */
+ 0x27, /* rfb:31 -> linux:31 (KEY_S) -> xorgkbd:39 */
+ 0x28, /* rfb:32 -> linux:32 (KEY_D) -> xorgkbd:40 */
+ 0x29, /* rfb:33 -> linux:33 (KEY_F) -> xorgkbd:41 */
+ 0x2a, /* rfb:34 -> linux:34 (KEY_G) -> xorgkbd:42 */
+ 0x2b, /* rfb:35 -> linux:35 (KEY_H) -> xorgkbd:43 */
+ 0x2c, /* rfb:36 -> linux:36 (KEY_J) -> xorgkbd:44 */
+ 0x2d, /* rfb:37 -> linux:37 (KEY_K) -> xorgkbd:45 */
+ 0x2e, /* rfb:38 -> linux:38 (KEY_L) -> xorgkbd:46 */
+ 0x2f, /* rfb:39 -> linux:39 (KEY_SEMICOLON) -> xorgkbd:47 */
+ 0x30, /* rfb:40 -> linux:40 (KEY_APOSTROPHE) -> xorgkbd:48 */
+ 0x31, /* rfb:41 -> linux:41 (KEY_GRAVE) -> xorgkbd:49 */
+ 0x32, /* rfb:42 -> linux:42 (KEY_LEFTSHIFT) -> xorgkbd:50 */
+ 0x33, /* rfb:43 -> linux:43 (KEY_BACKSLASH) -> xorgkbd:51 */
+ 0x34, /* rfb:44 -> linux:44 (KEY_Z) -> xorgkbd:52 */
+ 0x35, /* rfb:45 -> linux:45 (KEY_X) -> xorgkbd:53 */
+ 0x36, /* rfb:46 -> linux:46 (KEY_C) -> xorgkbd:54 */
+ 0x37, /* rfb:47 -> linux:47 (KEY_V) -> xorgkbd:55 */
+ 0x38, /* rfb:48 -> linux:48 (KEY_B) -> xorgkbd:56 */
+ 0x39, /* rfb:49 -> linux:49 (KEY_N) -> xorgkbd:57 */
+ 0x3a, /* rfb:50 -> linux:50 (KEY_M) -> xorgkbd:58 */
+ 0x3b, /* rfb:51 -> linux:51 (KEY_COMMA) -> xorgkbd:59 */
+ 0x3c, /* rfb:52 -> linux:52 (KEY_DOT) -> xorgkbd:60 */
+ 0x3d, /* rfb:53 -> linux:53 (KEY_SLASH) -> xorgkbd:61 */
+ 0x3e, /* rfb:54 -> linux:54 (KEY_RIGHTSHIFT) -> xorgkbd:62 */
+ 0x3f, /* rfb:55 -> linux:55 (KEY_KPASTERISK) -> xorgkbd:63 */
+ 0x40, /* rfb:56 -> linux:56 (KEY_LEFTALT) -> xorgkbd:64 */
+ 0x41, /* rfb:57 -> linux:57 (KEY_SPACE) -> xorgkbd:65 */
+ 0x42, /* rfb:58 -> linux:58 (KEY_CAPSLOCK) -> xorgkbd:66 */
+ 0x43, /* rfb:59 -> linux:59 (KEY_F1) -> xorgkbd:67 */
+ 0x44, /* rfb:60 -> linux:60 (KEY_F2) -> xorgkbd:68 */
+ 0x45, /* rfb:61 -> linux:61 (KEY_F3) -> xorgkbd:69 */
+ 0x46, /* rfb:62 -> linux:62 (KEY_F4) -> xorgkbd:70 */
+ 0x47, /* rfb:63 -> linux:63 (KEY_F5) -> xorgkbd:71 */
+ 0x48, /* rfb:64 -> linux:64 (KEY_F6) -> xorgkbd:72 */
+ 0x49, /* rfb:65 -> linux:65 (KEY_F7) -> xorgkbd:73 */
+ 0x4a, /* rfb:66 -> linux:66 (KEY_F8) -> xorgkbd:74 */
+ 0x4b, /* rfb:67 -> linux:67 (KEY_F9) -> xorgkbd:75 */
+ 0x4c, /* rfb:68 -> linux:68 (KEY_F10) -> xorgkbd:76 */
+ 0x4d, /* rfb:69 -> linux:69 (KEY_NUMLOCK) -> xorgkbd:77 */
+ 0x4e, /* rfb:70 -> linux:70 (KEY_SCROLLLOCK) -> xorgkbd:78 */
+ 0x4f, /* rfb:71 -> linux:71 (KEY_KP7) -> xorgkbd:79 */
+ 0x50, /* rfb:72 -> linux:72 (KEY_KP8) -> xorgkbd:80 */
+ 0x51, /* rfb:73 -> linux:73 (KEY_KP9) -> xorgkbd:81 */
+ 0x52, /* rfb:74 -> linux:74 (KEY_KPMINUS) -> xorgkbd:82 */
+ 0x53, /* rfb:75 -> linux:75 (KEY_KP4) -> xorgkbd:83 */
+ 0x54, /* rfb:76 -> linux:76 (KEY_KP5) -> xorgkbd:84 */
+ 0x55, /* rfb:77 -> linux:77 (KEY_KP6) -> xorgkbd:85 */
+ 0x56, /* rfb:78 -> linux:78 (KEY_KPPLUS) -> xorgkbd:86 */
+ 0x57, /* rfb:79 -> linux:79 (KEY_KP1) -> xorgkbd:87 */
+ 0x58, /* rfb:80 -> linux:80 (KEY_KP2) -> xorgkbd:88 */
+ 0x59, /* rfb:81 -> linux:81 (KEY_KP3) -> xorgkbd:89 */
+ 0x5a, /* rfb:82 -> linux:82 (KEY_KP0) -> xorgkbd:90 */
+ 0x5b, /* rfb:83 -> linux:83 (KEY_KPDOT) -> xorgkbd:91 */
+ 0x6f, /* rfb:84 -> linux:99 (KEY_SYSRQ) -> xorgkbd:111 */
+ 0x79, /* rfb:85 -> linux:186 (KEY_F16) -> xorgkbd:121 */
+ 0x5e, /* rfb:86 -> linux:86 (KEY_102ND) -> xorgkbd:94 */
+ 0x5f, /* rfb:87 -> linux:87 (KEY_F11) -> xorgkbd:95 */
+ 0x60, /* rfb:88 -> linux:88 (KEY_F12) -> xorgkbd:96 */
+ 0x7e, /* rfb:89 -> linux:117 (KEY_KPEQUAL) -> xorgkbd:126 */
+ 0, /* rfb:90 -> linux:190 (KEY_F20) -> xorgkbd:None */
+ 0, /* rfb:91 -> linux:101 (KEY_LINEFEED) -> xorgkbd:None */
+ 0, /* rfb:92 -> linux:95 (KEY_KPJPCOMMA) -> xorgkbd:None */
+ 0x76, /* rfb:93 -> linux:183 (KEY_F13) -> xorgkbd:118 */
+ 0x77, /* rfb:94 -> linux:184 (KEY_F14) -> xorgkbd:119 */
+ 0x78, /* rfb:95 -> linux:185 (KEY_F15) -> xorgkbd:120 */
+ 0, /* rfb:96 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:97 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:98 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:99 -> linux:169 (KEY_PHONE) -> xorgkbd:None */
+ 0, /* rfb:100 -> linux:134 (KEY_OPEN) -> xorgkbd:None */
+ 0, /* rfb:101 -> linux:135 (KEY_PASTE) -> xorgkbd:None */
+ 0, /* rfb:102 -> linux:141 (KEY_SETUP) -> xorgkbd:None */
+ 0, /* rfb:103 -> linux:144 (KEY_FILE) -> xorgkbd:None */
+ 0, /* rfb:104 -> linux:145 (KEY_SENDFILE) -> xorgkbd:None */
+ 0, /* rfb:105 -> linux:146 (KEY_DELETEFILE) -> xorgkbd:None */
+ 0, /* rfb:106 -> linux:151 (KEY_MSDOS) -> xorgkbd:None */
+ 0, /* rfb:107 -> linux:153 (KEY_DIRECTION) -> xorgkbd:None */
+ 0, /* rfb:108 -> linux:161 (KEY_EJECTCD) -> xorgkbd:None */
+ 0, /* rfb:109 -> linux:193 (KEY_F23) -> xorgkbd:None */
+ 0, /* rfb:110 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:111 -> linux:194 (KEY_F24) -> xorgkbd:None */
+ 0, /* rfb:112 -> linux:170 (KEY_ISO) -> xorgkbd:None */
+ 0, /* rfb:113 -> linux:174 (KEY_EXIT) -> xorgkbd:None */
+ 0, /* rfb:114 -> linux:175 (KEY_MOVE) -> xorgkbd:None */
+ 0, /* rfb:115 -> linux:89 (KEY_RO) -> xorgkbd:None */
+ 0, /* rfb:116 -> linux:191 (KEY_F21) -> xorgkbd:None */
+ 0, /* rfb:117 -> linux:177 (KEY_SCROLLUP) -> xorgkbd:None */
+ 0, /* rfb:118 -> linux:85 (KEY_ZENKAKUHANKAKU) -> xorgkbd:None */
+ 0, /* rfb:119 -> linux:91 (KEY_HIRAGANA) -> xorgkbd:None */
+ 0, /* rfb:120 -> linux:90 (KEY_KATAKANA) -> xorgkbd:None */
+ 0, /* rfb:121 -> linux:92 (KEY_HENKAN) -> xorgkbd:None */
+ 0, /* rfb:122 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:123 -> linux:94 (KEY_MUHENKAN) -> xorgkbd:None */
+ 0, /* rfb:124 -> linux:None (unnamed) -> xorgkbd:None */
+ 0x85, /* rfb:125 -> linux:124 (KEY_YEN) -> xorgkbd:133 */
+ 0, /* rfb:126 -> linux:121 (KEY_KPCOMMA) -> xorgkbd:None */
+ 0, /* rfb:127 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:128 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:129 -> linux:171 (KEY_CONFIG) -> xorgkbd:None */
+ 0, /* rfb:130 -> linux:150 (KEY_WWW) -> xorgkbd:None */
+ 0x7a, /* rfb:131 -> linux:187 (KEY_F17) -> xorgkbd:122 */
+ 0, /* rfb:132 -> linux:189 (KEY_F19) -> xorgkbd:None */
+ 0, /* rfb:133 -> linux:129 (KEY_AGAIN) -> xorgkbd:None */
+ 0, /* rfb:134 -> linux:130 (KEY_PROPS) -> xorgkbd:None */
+ 0, /* rfb:135 -> linux:131 (KEY_UNDO) -> xorgkbd:None */
+ 0, /* rfb:136 -> linux:176 (KEY_EDIT) -> xorgkbd:None */
+ 0, /* rfb:137 -> linux:181 (KEY_NEW) -> xorgkbd:None */
+ 0, /* rfb:138 -> linux:182 (KEY_REDO) -> xorgkbd:None */
+ 0, /* rfb:139 -> linux:120 (KEY_SCALE) -> xorgkbd:None */
+ 0, /* rfb:140 -> linux:132 (KEY_FRONT) -> xorgkbd:None */
+ 0, /* rfb:141 -> linux:123 (KEY_HANJA) -> xorgkbd:None */
+ 0, /* rfb:142 -> linux:233 (KEY_FORWARDMAIL) -> xorgkbd:None */
+ 0, /* rfb:143 -> linux:178 (KEY_SCROLLDOWN) -> xorgkbd:None */
+ 0, /* rfb:144 -> linux:165 (KEY_PREVIOUSSONG) -> xorgkbd:None */
+ 0, /* rfb:145 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:146 -> linux:152 (KEY_SCREENLOCK) -> xorgkbd:None */
+ 0, /* rfb:147 -> linux:147 (KEY_XFER) -> xorgkbd:None */
+ 0, /* rfb:148 -> linux:222 (KEY_ALTERASE) -> xorgkbd:None */
+ 0, /* rfb:149 -> linux:195 (unnamed) -> xorgkbd:None */
+ 0, /* rfb:150 -> linux:196 (unnamed) -> xorgkbd:None */
+ 0, /* rfb:151 -> linux:149 (KEY_PROG2) -> xorgkbd:None */
+ 0, /* rfb:152 -> linux:168 (KEY_REWIND) -> xorgkbd:None */
+ 0, /* rfb:153 -> linux:163 (KEY_NEXTSONG) -> xorgkbd:None */
+ 0, /* rfb:154 -> linux:197 (unnamed) -> xorgkbd:None */
+ 0, /* rfb:155 -> linux:198 (unnamed) -> xorgkbd:None */
+ 0x6c, /* rfb:156 -> linux:96 (KEY_KPENTER) -> xorgkbd:108 */
+ 0x6d, /* rfb:157 -> linux:97 (KEY_RIGHTCTRL) -> xorgkbd:109 */
+ 0, /* rfb:158 -> linux:139 (KEY_MENU) -> xorgkbd:None */
+ 0, /* rfb:159 -> linux:148 (KEY_PROG1) -> xorgkbd:None */
+ 0, /* rfb:160 -> linux:113 (KEY_MUTE) -> xorgkbd:None */
+ 0, /* rfb:161 -> linux:140 (KEY_CALC) -> xorgkbd:None */
+ 0, /* rfb:162 -> linux:164 (KEY_PLAYPAUSE) -> xorgkbd:None */
+ 0, /* rfb:163 -> linux:160 (KEY_CLOSECD) -> xorgkbd:None */
+ 0, /* rfb:164 -> linux:166 (KEY_STOPCD) -> xorgkbd:None */
+ 0, /* rfb:165 -> linux:205 (KEY_SUSPEND) -> xorgkbd:None */
+ 0, /* rfb:166 -> linux:154 (KEY_CYCLEWINDOWS) -> xorgkbd:None */
+ 0, /* rfb:167 -> linux:199 (unnamed) -> xorgkbd:None */
+ 0, /* rfb:168 -> linux:200 (KEY_PLAYCD) -> xorgkbd:None */
+ 0, /* rfb:169 -> linux:201 (KEY_PAUSECD) -> xorgkbd:None */
+ 0, /* rfb:170 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:171 -> linux:202 (KEY_PROG3) -> xorgkbd:None */
+ 0, /* rfb:172 -> linux:203 (KEY_PROG4) -> xorgkbd:None */
+ 0, /* rfb:173 -> linux:204 (KEY_DASHBOARD) -> xorgkbd:None */
+ 0, /* rfb:174 -> linux:114 (KEY_VOLUMEDOWN) -> xorgkbd:None */
+ 0, /* rfb:175 -> linux:206 (KEY_CLOSE) -> xorgkbd:None */
+ 0, /* rfb:176 -> linux:115 (KEY_VOLUMEUP) -> xorgkbd:None */
+ 0, /* rfb:177 -> linux:167 (KEY_RECORD) -> xorgkbd:None */
+ 0, /* rfb:178 -> linux:172 (KEY_HOMEPAGE) -> xorgkbd:None */
+ 0, /* rfb:179 -> linux:207 (KEY_PLAY) -> xorgkbd:None */
+ 0, /* rfb:180 -> linux:208 (KEY_FASTFORWARD) -> xorgkbd:None */
+ 0x70, /* rfb:181 -> linux:98 (KEY_KPSLASH) -> xorgkbd:112 */
+ 0, /* rfb:182 -> linux:209 (KEY_BASSBOOST) -> xorgkbd:None */
+ 0, /* rfb:183 -> linux:None (unnamed) -> xorgkbd:None */
+ 0x71, /* rfb:184 -> linux:100 (KEY_RIGHTALT) -> xorgkbd:113 */
+ 0, /* rfb:185 -> linux:210 (KEY_PRINT) -> xorgkbd:None */
+ 0, /* rfb:186 -> linux:211 (KEY_HP) -> xorgkbd:None */
+ 0, /* rfb:187 -> linux:212 (KEY_CAMERA) -> xorgkbd:None */
+ 0, /* rfb:188 -> linux:137 (KEY_CUT) -> xorgkbd:None */
+ 0, /* rfb:189 -> linux:213 (KEY_SOUND) -> xorgkbd:None */
+ 0, /* rfb:190 -> linux:214 (KEY_QUESTION) -> xorgkbd:None */
+ 0, /* rfb:191 -> linux:215 (KEY_EMAIL) -> xorgkbd:None */
+ 0, /* rfb:192 -> linux:216 (KEY_CHAT) -> xorgkbd:None */
+ 0, /* rfb:193 -> linux:136 (KEY_FIND) -> xorgkbd:None */
+ 0, /* rfb:194 -> linux:218 (KEY_CONNECT) -> xorgkbd:None */
+ 0, /* rfb:195 -> linux:219 (KEY_FINANCE) -> xorgkbd:None */
+ 0, /* rfb:196 -> linux:220 (KEY_SPORT) -> xorgkbd:None */
+ 0, /* rfb:197 -> linux:221 (KEY_SHOP) -> xorgkbd:None */
+ 0x6e, /* rfb:198 -> linux:119 (KEY_PAUSE) -> xorgkbd:110 */
+ 0x61, /* rfb:199 -> linux:102 (KEY_HOME) -> xorgkbd:97 */
+ 0x62, /* rfb:200 -> linux:103 (KEY_UP) -> xorgkbd:98 */
+ 0x63, /* rfb:201 -> linux:104 (KEY_PAGEUP) -> xorgkbd:99 */
+ 0, /* rfb:202 -> linux:223 (KEY_CANCEL) -> xorgkbd:None */
+ 0x64, /* rfb:203 -> linux:105 (KEY_LEFT) -> xorgkbd:100 */
+ 0, /* rfb:204 -> linux:224 (KEY_BRIGHTNESSDOWN) -> xorgkbd:None */
+ 0x66, /* rfb:205 -> linux:106 (KEY_RIGHT) -> xorgkbd:102 */
+ 0, /* rfb:206 -> linux:118 (KEY_KPPLUSMINUS) -> xorgkbd:None */
+ 0x67, /* rfb:207 -> linux:107 (KEY_END) -> xorgkbd:103 */
+ 0x68, /* rfb:208 -> linux:108 (KEY_DOWN) -> xorgkbd:104 */
+ 0x69, /* rfb:209 -> linux:109 (KEY_PAGEDOWN) -> xorgkbd:105 */
+ 0x6a, /* rfb:210 -> linux:110 (KEY_INSERT) -> xorgkbd:106 */
+ 0x6b, /* rfb:211 -> linux:111 (KEY_DELETE) -> xorgkbd:107 */
+ 0, /* rfb:212 -> linux:225 (KEY_BRIGHTNESSUP) -> xorgkbd:None */
+ 0, /* rfb:213 -> linux:234 (KEY_SAVE) -> xorgkbd:None */
+ 0, /* rfb:214 -> linux:227 (KEY_SWITCHVIDEOMODE) -> xorgkbd:None */
+ 0, /* rfb:215 -> linux:228 (KEY_KBDILLUMTOGGLE) -> xorgkbd:None */
+ 0, /* rfb:216 -> linux:229 (KEY_KBDILLUMDOWN) -> xorgkbd:None */
+ 0, /* rfb:217 -> linux:230 (KEY_KBDILLUMUP) -> xorgkbd:None */
+ 0, /* rfb:218 -> linux:231 (KEY_SEND) -> xorgkbd:None */
+ 0x73, /* rfb:219 -> linux:125 (KEY_LEFTMETA) -> xorgkbd:115 */
+ 0x74, /* rfb:220 -> linux:126 (KEY_RIGHTMETA) -> xorgkbd:116 */
+ 0x75, /* rfb:221 -> linux:127 (KEY_COMPOSE) -> xorgkbd:117 */
+ 0, /* rfb:222 -> linux:116 (KEY_POWER) -> xorgkbd:None */
+ 0, /* rfb:223 -> linux:142 (KEY_SLEEP) -> xorgkbd:None */
+ 0, /* rfb:224 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:225 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:226 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:227 -> linux:143 (KEY_WAKEUP) -> xorgkbd:None */
+ 0, /* rfb:228 -> linux:232 (KEY_REPLY) -> xorgkbd:None */
+ 0, /* rfb:229 -> linux:217 (KEY_SEARCH) -> xorgkbd:None */
+ 0, /* rfb:230 -> linux:156 (KEY_BOOKMARKS) -> xorgkbd:None */
+ 0, /* rfb:231 -> linux:173 (KEY_REFRESH) -> xorgkbd:None */
+ 0, /* rfb:232 -> linux:128 (KEY_STOP) -> xorgkbd:None */
+ 0, /* rfb:233 -> linux:159 (KEY_FORWARD) -> xorgkbd:None */
+ 0, /* rfb:234 -> linux:158 (KEY_BACK) -> xorgkbd:None */
+ 0, /* rfb:235 -> linux:157 (KEY_COMPUTER) -> xorgkbd:None */
+ 0, /* rfb:236 -> linux:155 (KEY_MAIL) -> xorgkbd:None */
+ 0, /* rfb:237 -> linux:226 (KEY_MEDIA) -> xorgkbd:None */
+ 0, /* rfb:238 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:239 -> linux:112 (KEY_MACRO) -> xorgkbd:None */
+ 0, /* rfb:240 -> linux:235 (KEY_DOCUMENTS) -> xorgkbd:None */
+ 0, /* rfb:241 -> linux:236 (KEY_BATTERY) -> xorgkbd:None */
+ 0, /* rfb:242 -> linux:237 (KEY_BLUETOOTH) -> xorgkbd:None */
+ 0, /* rfb:243 -> linux:238 (KEY_WLAN) -> xorgkbd:None */
+ 0, /* rfb:244 -> linux:239 (KEY_UWB) -> xorgkbd:None */
+ 0, /* rfb:245 -> linux:138 (KEY_HELP) -> xorgkbd:None */
+ 0, /* rfb:246 -> linux:179 (KEY_KPLEFTPAREN) -> xorgkbd:None */
+ 0, /* rfb:247 -> linux:188 (KEY_F18) -> xorgkbd:None */
+ 0, /* rfb:248 -> linux:133 (KEY_COPY) -> xorgkbd:None */
+ 0, /* rfb:249 -> linux:192 (KEY_F22) -> xorgkbd:None */
+ 0, /* rfb:250 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:251 -> linux:180 (KEY_KPRIGHTPAREN) -> xorgkbd:None */
+ 0, /* rfb:252 -> linux:None (unnamed) -> xorgkbd:None */
+ 0, /* rfb:253 -> linux:162 (KEY_EJECTCLOSECD) -> xorgkbd:None */
+};
diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx
index e16bd386..114c6f24 100644
--- a/unix/x0vncserver/x0vncserver.cxx
+++ b/unix/x0vncserver/x0vncserver.cxx
@@ -39,6 +39,7 @@
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
+#include <X11/XKBlib.h>
#ifdef HAVE_XTEST
#include <X11/extensions/XTest.h>
#endif
@@ -51,6 +52,9 @@
#include <x0vncserver/XPixelBuffer.h>
#include <x0vncserver/PollingScheduler.h>

+#include <x0vncserver/rfb_to_xorgevdev.h>
+#include <x0vncserver/rfb_to_xorgkbd.h>
+
// XXX Lynx/OS 2.3: protos for select(), bzero()
#ifdef Lynx
#include <sys/proto.h>
@@ -141,7 +145,7 @@ public:
XDesktop(Display* dpy_, Geometry *geometry_)
: dpy(dpy_), geometry(geometry_), pb(0), server(0),
oldButtonMask(0), haveXtest(false), haveDamage(false),
- maxButtons(0), running(false)
+ maxButtons(0), running(false), codeMap(0), codeMapLen(0)
{
#ifdef HAVE_XTEST
int xtestEventBase;
@@ -174,6 +178,34 @@ public:
#ifdef HAVE_XDAMAGE
}
#endif
+
+ // X11 unfortunately uses keyboard driver specific keycodes and provides no
+ // direct way to query this, so guess based on the keyboard mapping
+ XkbDescPtr desc = XkbGetKeyboard(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
+ if (desc && desc->names) {
+ char *keycodes = XGetAtomName(dpy, desc->names->keycodes);
+
+ if (keycodes) {
+ if (strncmp("evdev", keycodes, strlen("evdev")) == 0) {
+ codeMap = code_map_rfb_to_xorgevdev;
+ codeMapLen = sizeof(code_map_rfb_to_xorgevdev) /
+ sizeof(code_map_rfb_to_xorgevdev[0]);
+ vlog.info("Using evdev codemap\n");
+ } else if (strncmp("xfree86", keycodes, strlen("xfree86")) == 0) {
+ codeMap = code_map_rfb_to_xorgkbd;
+ codeMapLen = sizeof(code_map_rfb_to_xorgkbd) /
+ sizeof(code_map_rfb_to_xorgkbd[0]);
+ vlog.info("Using xorgkbd codemap\n");
+ } else {
+ vlog.info("Unknown keycode '%s', no codemap\n", keycodes);
+ }
+ XFree(keycodes);
+ } else {
+ vlog.debug("Unable to get keycode map\n");
+ }
+
+ XkbFreeKeyboard(desc, 0, True);
+ }
}
virtual ~XDesktop() {
stop();
@@ -255,8 +287,16 @@ public:

virtual void keyEvent(rdr::U32 key, rdr::U32 code, bool down) {
#ifdef HAVE_XTEST
+ int keycode = 0;
if (!haveXtest) return;
- int keycode = XKeysymToKeycode(dpy, key);
+
+ // Use scan code if provided and mapping exists
+ if (codeMap && code < codeMapLen)
+ keycode = codeMap[code];
+
+ if (!keycode)
+ keycode = XKeysymToKeycode(dpy, key);
+
if (keycode)
XTestFakeKeyEvent(dpy, keycode, down, CurrentTime);
#endif
@@ -306,6 +346,8 @@ protected:
Damage damage;
int xdamageEventBase;
#endif
+ const unsigned short *codeMap;
+ unsigned codeMapLen;
};


--
2.11.0

Peter Korsgaard

unread,
Jul 12, 2017, 6:36:22 PM7/12/17
to tigervn...@googlegroups.com, Rahul Kale, Peter Korsgaard
From: Rahul Kale <Rahul...@barco.com>

LED support added using Windows GetKeyState() API call.

The state is polled for change in CapsLock/NumLock/ScrollLock
status in the same code block where chages to Cursor shape is polled.

Signed-off-by: Rahul Kale <Rahul...@barco.com>
Signed-off-by: Peter Korsgaard <peter.k...@barco.com>
---
win/rfb_win32/SDisplay.cxx | 28 +++++++++++++++++++++++++++-
win/rfb_win32/SDisplay.h | 3 +++
2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/win/rfb_win32/SDisplay.cxx b/win/rfb_win32/SDisplay.cxx
index 9a56c7d3..e8d2960f 100644
--- a/win/rfb_win32/SDisplay.cxx
+++ b/win/rfb_win32/SDisplay.cxx
@@ -65,7 +65,7 @@ SDisplay::SDisplay()
: server(0), pb(0), device(0),
core(0), ptr(0), kbd(0), clipboard(0),
inputs(0), monitor(0), cleanDesktop(0), cursor(0),
- statusLocation(0)
+ statusLocation(0), ledState(0)
{
updateEvent.h = CreateEvent(0, TRUE, FALSE, 0);
}
@@ -196,6 +196,10 @@ void SDisplay::startCore() {
cleanDesktop->disableEffects();
isWallpaperRemoved = removeWallpaper;
areEffectsDisabled = disableEffects;
+
+ checkLedState();
+ if (server)
+ server->setLedState(ledState);
}

void SDisplay::stopCore() {
@@ -283,6 +287,24 @@ void SDisplay::keyEvent(rdr::U32 key, rdr::U32 code, bool down) {
kbd->keyEvent(key, code, down);
}

+bool SDisplay::checkLedState() {
+ unsigned state = 0;
+
+ if (GetKeyState(VK_SCROLL) & 0x0001)
+ state |= 0x1;
+ if (GetKeyState(VK_NUMLOCK) & 0x0001)
+ state |= 0x2;
+ if (GetKeyState(VK_CAPITAL) & 0x0001)
+ state |= 0x4;
+
+ if (ledState != state) {
+ ledState = sState;
+ return true;
+ }
+
+ return false;
+}
+
void SDisplay::clientCutText(const char* text, int len) {
CharArray clip_sz(len+1);
memcpy(clip_sz.buf, text, len);
@@ -384,6 +406,10 @@ SDisplay::processEvent(HANDLE event) {

// Flush any changes to the server
flushChangeTracker();
+
+ // Forward current LED state to the server
+ if (checkLedState())
+ server->setLedState(ledState);
}
return;
}
diff --git a/win/rfb_win32/SDisplay.h b/win/rfb_win32/SDisplay.h
index 1006ea0d..b84091a1 100644
--- a/win/rfb_win32/SDisplay.h
+++ b/win/rfb_win32/SDisplay.h
@@ -106,6 +106,7 @@ namespace rfb {
void restartCore();
void recreatePixelBuffer(bool force=false);
bool flushChangeTracker(); // true if flushed, false if empty
+ bool checkLedState();

VNCServer* server;

@@ -151,6 +152,8 @@ namespace rfb {

// -=- Where to write the active/inactive indicator to
bool* statusLocation;
+
+ unsigned ledState;
};

}
--
2.11.0

Peter Korsgaard

unread,
Jul 12, 2017, 6:36:23 PM7/12/17
to tigervn...@googlegroups.com, Rahul Kale, Peter Korsgaard
From: Rahul Kale <Rahul...@barco.com>

If scan codes are available using QEMU Extended Keyboard Messages
from clients, use that to inject scancodes directly into the
system using the SendInput API.

No conversion is needed as Windows uses the same scancode encoding.

Signed-off-by: Rahul Kale <Rahul...@barco.com>
Signed-off-by: Peter Korsgaard <peter.k...@barco.com>
---
win/rfb_win32/SInput.cxx | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)

diff --git a/win/rfb_win32/SInput.cxx b/win/rfb_win32/SInput.cxx
index e40323a7..4e76c5a2 100644
--- a/win/rfb_win32/SInput.cxx
+++ b/win/rfb_win32/SInput.cxx
@@ -229,6 +229,31 @@ inline void doKeyboardEvent(BYTE vkCode, DWORD flags) {
keybd_event(vkCode, MapVirtualKey(vkCode, 0), flags, 0);
}

+inline void doScanCodeEvent(BYTE scancode, bool down) {
+ INPUT evt;
+
+ evt.type = INPUT_KEYBOARD;
+ evt.ki.wVk = 0;
+ evt.ki.dwFlags = KEYEVENTF_SCANCODE;
+
+ if (!down)
+ evt.ki.dwFlags |= KEYEVENTF_KEYUP;
+
+ if (scancode & 0x80) {
+ evt.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
+ scancode &= ~0x80;
+ }
+
+ evt.ki.wScan = scancode;
+ evt.ki.dwExtraInfo = 0;
+ evt.ki.time = 0;
+ vlog.debug("SendInput ScanCode: 0x%x Flags: 0x%lx %s", scancode,
+ evt.ki.dwFlags, down ? "Down" : "Up");
+
+ if (SendInput(1, &evt, sizeof(evt)) != 1)
+ vlog.error("SendInput %lu", GetLastError());
+}
+
// KeyStateModifier is a class which helps simplify generating a "fake" press
// or release of shift, ctrl, alt, etc. An instance of the class is created
// for every key which may need to be pressed or released. Then either press()
@@ -323,6 +348,13 @@ win32::SKeyboard::SKeyboard()

void win32::SKeyboard::keyEvent(rdr::U32 keysym, rdr::U32 code, bool down)
{
+ // If scan code is available use that directly as windows uses
+ // compatible scancodes
+ if (code) {
+ doScanCodeEvent(code, down);
+ return;
+ }
+
for (unsigned int i = 0; i < sizeof(keysymToAscii) / sizeof(keysymToAscii_t); i++) {
if (keysymToAscii[i].keysym == keysym) {
keysym = keysymToAscii[i].ascii;
--
2.11.0

Peter Korsgaard

unread,
Jul 12, 2017, 6:36:23 PM7/12/17
to tigervn...@googlegroups.com, Peter Korsgaard
Add an interface to the server to push led state changes to clients
supporting it and ensure notifications are sent at connection time and
when changes occur.

As led state notification doesn't make much sense without the extended keys
support, also protect it behind the "AcceptExtendedKeyEvents" option.

Signed-off-by: Peter Korsgaard <peter.k...@barco.com>
---
common/rfb/ConnParams.cxx | 2 +-
common/rfb/ConnParams.h | 1 +
common/rfb/SMsgHandler.cxx | 10 +++++++++-
common/rfb/SMsgHandler.h | 4 ++++
common/rfb/SMsgWriter.cxx | 28 +++++++++++++++++++++++++++-
common/rfb/SMsgWriter.h | 3 +++
common/rfb/VNCSConnectionST.cxx | 26 ++++++++++++++++++++++++++
common/rfb/VNCSConnectionST.h | 2 ++
common/rfb/VNCServer.h | 4 ++++
common/rfb/VNCServerST.cxx | 13 ++++++++++++-
common/rfb/VNCServerST.h | 3 +++
11 files changed, 92 insertions(+), 4 deletions(-)

diff --git a/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx
index dfcfb84c..3a580c67 100644
--- a/common/rfb/ConnParams.cxx
+++ b/common/rfb/ConnParams.cxx
@@ -38,7 +38,7 @@ ConnParams::ConnParams()
supportsContinuousUpdates(false), supportsExtendedKey(false),
supportsLedState(false),
compressLevel(2), qualityLevel(-1), fineQualityLevel(-1),
- subsampling(subsampleUndefined), name_(0), verStrPos(0)
+ subsampling(subsampleUndefined), ledState(0), name_(0), verStrPos(0)
{
setName("");
cursor_ = new Cursor(0, 0, Point(), NULL);
diff --git a/common/rfb/ConnParams.h b/common/rfb/ConnParams.h
index 4a9c340a..5d415aba 100644
--- a/common/rfb/ConnParams.h
+++ b/common/rfb/ConnParams.h
@@ -104,6 +104,7 @@ namespace rfb {
int qualityLevel;
int fineQualityLevel;
int subsampling;
+ unsigned ledState;

private:

diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx
index 8cb8992b..c62dc0a6 100644
--- a/common/rfb/SMsgHandler.cxx
+++ b/common/rfb/SMsgHandler.cxx
@@ -41,11 +41,12 @@ void SMsgHandler::setPixelFormat(const PixelFormat& pf)

void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings)
{
- bool firstFence, firstContinuousUpdates, firstExtendedKey;
+ bool firstFence, firstContinuousUpdates, firstExtendedKey, firstLedState;

firstFence = !cp.supportsFence;
firstContinuousUpdates = !cp.supportsContinuousUpdates;
firstExtendedKey = !cp.supportsExtendedKey;
+ firstLedState = !cp.supportsLedState;

cp.setEncodings(nEncodings, encodings);

@@ -58,6 +59,9 @@ void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings)

if (cp.supportsExtendedKey && firstExtendedKey)
supportsExtendedKey();
+
+ if (cp.supportsLedState && firstLedState)
+ supportsLedState();
}

void SMsgHandler::supportsLocalCursor()
@@ -76,6 +80,10 @@ void SMsgHandler::supportsExtendedKey()
{
}

+void SMsgHandler::supportsLedState()
+{
+}
+
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 2a949fcd..ba59df20 100644
--- a/common/rfb/SMsgHandler.h
+++ b/common/rfb/SMsgHandler.h
@@ -78,6 +78,10 @@ namespace rfb {
// client supports the extended key message.
virtual void supportsExtendedKey();

+ // supportsLedState() is called the first time we detect that the
+ // client supports the led state pseudo encoding
+ virtual void supportsLedState();
+
ConnParams cp;
};
}
diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx
index 97306b1a..232c9967 100644
--- a/common/rfb/SMsgWriter.cxx
+++ b/common/rfb/SMsgWriter.cxx
@@ -38,7 +38,7 @@ SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
needSetDesktopSize(false), needExtendedDesktopSize(false),
needSetDesktopName(false), needSetCursor(false),
needSetXCursor(false), needSetCursorWithAlpha(false),
- needExtendedKey(false)
+ needExtendedKey(false), needLedState(false)
{
}

@@ -173,6 +173,15 @@ bool SMsgWriter::writeExtendedKey() {
return true;
}

+bool SMsgWriter::writeLedState() {
+ if (!cp->supportsLedState)
+ return false;
+
+ needLedState = true;
+
+ return true;
+}
+
bool SMsgWriter::writeSetCursor()
{
if (!cp->supportsLocalCursor)
@@ -223,6 +232,8 @@ bool SMsgWriter::needNoDataUpdate()
return true;
if (needExtendedKey)
return true;
+ if (needLedState)
+ return true;

return false;
}
@@ -241,6 +252,8 @@ void SMsgWriter::writeNoDataUpdate()
nRects += extendedDesktopSizeMsgs.size();
if (needExtendedKey)
nRects++;
+ if (needLedState)
+ nRects++;

writeFramebufferUpdateStart(nRects);
writeNoDataRects();
@@ -411,6 +424,19 @@ void SMsgWriter::writeNoDataRects()
needExtendedKey = false;
}

+ if (needLedState) {
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriter::writeNoDataRects: nRects out of sync");
+
+ os->writeS16(0);
+ os->writeS16(0);
+ os->writeU16(0);
+ os->writeU16(0);
+ os->writeU32(pseudoEncodingLedState);
+ os->writeU8(cp->ledState);
+ needLedState = false;
+ }
+
// Some clients assume this is the last rectangle so don't send anything
// more after this
if (needSetDesktopSize) {
diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h
index 98617231..85eee889 100644
--- a/common/rfb/SMsgWriter.h
+++ b/common/rfb/SMsgWriter.h
@@ -78,6 +78,8 @@ namespace rfb {

bool writeExtendedKey();

+ bool writeLedState();
+
// Like setDesktopSize, we can't just write out a cursor message
// immediately.
bool writeSetCursor();
@@ -148,6 +150,7 @@ namespace rfb {
bool needSetXCursor;
bool needSetCursorWithAlpha;
bool needExtendedKey;
+ bool needLedState;

typedef struct {
rdr::U16 reason, result;
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index fd67302b..6342214c 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -301,6 +301,24 @@ void VNCSConnectionST::setDesktopNameOrClose(const char *name)
}


+void VNCSConnectionST::setLedStateOrClose(unsigned mask)
+{
+ if (!rfb::Server::acceptExtendedKeyEvents) return;
+
+ cp.ledState = mask;
+
+ try {
+ if (state() == RFBSTATE_NORMAL) {
+ writer()->writeLedState();
+ if (writer()->needNoDataUpdate())
+ writer()->writeNoDataUpdate();
+ }
+ } catch(rdr::Exception& e) {
+ close(e.str());
+ }
+}
+
+
void VNCSConnectionST::setCursorOrClose()
{
try {
@@ -422,6 +440,8 @@ void VNCSConnectionST::authSuccess()
cp.pf().print(buffer, 256);
vlog.info("Server default pixel format %s", buffer);

+ cp.ledState = server->ledState;
+
// - Mark the entire display as "dirty"
updates.add_changed(server->pb->getRect());
startTime = time(0);
@@ -755,6 +775,12 @@ void VNCSConnectionST::supportsExtendedKey()
writer()->writeExtendedKey();
}

+void VNCSConnectionST::supportsLedState()
+{
+ if (!rfb::Server::acceptExtendedKeyEvents) return;
+ writer()->writeLedState();
+}
+
bool VNCSConnectionST::handleTimeout(Timer* t)
{
try {
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index 9f7ab8e1..8daa561c 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -78,6 +78,7 @@ namespace rfb {
void bellOrClose();
void serverCutTextOrClose(const char *str, int len);
void setDesktopNameOrClose(const char *name);
+ void setLedStateOrClose(unsigned mask);

// checkIdleTimeout() returns the number of milliseconds left until the
// idle timeout expires. If it has expired, the connection is closed and
@@ -147,6 +148,7 @@ namespace rfb {
virtual void supportsFence();
virtual void supportsContinuousUpdates();
virtual void supportsExtendedKey();
+ virtual void supportsLedState();

// setAccessRights() allows a security package to limit the access rights
// of a VNCSConnectioST to the server. These access rights are applied
diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h
index 982a4ff5..c7bfb431 100644
--- a/common/rfb/VNCServer.h
+++ b/common/rfb/VNCServer.h
@@ -74,6 +74,10 @@ namespace rfb {

// setName() tells the server what desktop title to supply to clients
virtual void setName(const char* name) = 0;
+
+ // setLedState() tells the server the current CapsLock/NumLock/ScrollLock state
+ virtual void setLedState(unsigned mask) = 0;
+
};
}
#endif
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index ec5e962f..fa42f964 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -80,7 +80,7 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
renderedCursorInvalid(false),
queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
lastConnectionTime(0), disableclients(false),
- frameTimer(this)
+ frameTimer(this), ledState(0)
{
lastUserInputTime = lastDisconnectTime = time(0);
slog.debug("creating single-threaded server %s", name.buf);
@@ -393,6 +393,17 @@ void VNCServerST::bell()
}
}

+void VNCServerST::setLedState(unsigned mask)
+{
+ ledState = mask;
+
+ std::list<VNCSConnectionST*>::iterator ci, ci_next;
+ for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+ ci_next = ci; ci_next++;
+ (*ci)->setLedStateOrClose(mask);
+ }
+}
+
void VNCServerST::serverCutText(const char* str, int len)
{
std::list<VNCSConnectionST*>::iterator ci, ci_next;
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index 00f77c73..4aaded5b 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -103,6 +103,7 @@ namespace rfb {
virtual void setCursorPos(const Point& p);

virtual void bell();
+ virtual void setLedState(unsigned mask);

// - Close all currently-connected clients, by calling
// their close() method with the supplied reason.
@@ -247,6 +248,8 @@ namespace rfb {
bool disableclients;

Timer frameTimer;

Peter Korsgaard

unread,
Jul 12, 2017, 6:36:24 PM7/12/17
to tigervn...@googlegroups.com, Peter Korsgaard
Signed-off-by: Peter Korsgaard <peter.k...@barco.com>
---
common/rfb/ConnParams.cxx | 4 ++++
common/rfb/ConnParams.h | 1 +
common/rfb/encodings.h | 1 +
3 files changed, 6 insertions(+)

diff --git a/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx
index 4d4ca658..dfcfb84c 100644
--- a/common/rfb/ConnParams.cxx
+++ b/common/rfb/ConnParams.cxx
@@ -36,6 +36,7 @@ ConnParams::ConnParams()
supportsDesktopRename(false), supportsLastRect(false),
supportsSetDesktopSize(false), supportsFence(false),
supportsContinuousUpdates(false), supportsExtendedKey(false),
+ supportsLedState(false),
compressLevel(2), qualityLevel(-1), fineQualityLevel(-1),
subsampling(subsampleUndefined), name_(0), verStrPos(0)
{
@@ -150,6 +151,9 @@ void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings)
case pseudoEncodingExtendedKey:
supportsExtendedKey = true;
break;
+ case pseudoEncodingLedState:
+ supportsLedState = true;
+ break;
case pseudoEncodingSubsamp1X:
subsampling = subsampleNone;
break;
diff --git a/common/rfb/ConnParams.h b/common/rfb/ConnParams.h
index f6b87db3..4a9c340a 100644
--- a/common/rfb/ConnParams.h
+++ b/common/rfb/ConnParams.h
@@ -98,6 +98,7 @@ namespace rfb {
bool supportsFence;
bool supportsContinuousUpdates;
bool supportsExtendedKey;
+ bool supportsLedState;

int compressLevel;
int qualityLevel;
diff --git a/common/rfb/encodings.h b/common/rfb/encodings.h
index 6026bb71..bac40010 100644
--- a/common/rfb/encodings.h
+++ b/common/rfb/encodings.h
@@ -59,6 +59,7 @@ namespace rfb {

// QEMU-specific
const int pseudoEncodingExtendedKey = -258;
+ const int pseudoEncodingLedState = -261;

Peter Korsgaard

unread,
Jul 12, 2017, 6:36:27 PM7/12/17
to tigervn...@googlegroups.com, Peter Korsgaard
Listen for XKb XkbIndicatorStateNotify events for scroll/num/caps lock and
map them to the RFB protocol.

Signed-off-by: Peter Korsgaard <peter.k...@barco.com>
---
unix/x0vncserver/x0vncserver.cxx | 64 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx
index 114c6f24..387b49ca 100644
--- a/unix/x0vncserver/x0vncserver.cxx
+++ b/unix/x0vncserver/x0vncserver.cxx
@@ -62,6 +62,14 @@

extern char buildtime[];

+// number of XKb indicator leds to handle
+static const int N_LEDS = 3;
+
+// order is important as it must match RFB extension
+static const char * ledNames[N_LEDS] = {
+ "Scroll Lock", "Num Lock", "Caps Lock"
+};
+
using namespace rfb;
using namespace network;

@@ -145,7 +153,8 @@ public:
XDesktop(Display* dpy_, Geometry *geometry_)
: dpy(dpy_), geometry(geometry_), pb(0), server(0),
oldButtonMask(0), haveXtest(false), haveDamage(false),
- maxButtons(0), running(false), codeMap(0), codeMapLen(0)
+ maxButtons(0), running(false), codeMap(0), codeMapLen(0),
+ ledMasks(), ledState(0)
{
#ifdef HAVE_XTEST
int xtestEventBase;
@@ -206,6 +215,37 @@ public:

XkbFreeKeyboard(desc, 0, True);
}
+
+ int xkbOpcode, xkbMajor, xkbMinor, xkbErrorBase;
+ xkbMajor = XkbMajorVersion;
+ xkbMinor = XkbMinorVersion;
+
+ if (XkbQueryExtension(dpy, &xkbOpcode, &xkbEventBase, &xkbErrorBase, &xkbMajor, &xkbMinor)) {
+ XkbSelectEvents(dpy, XkbUseCoreKbd, XkbIndicatorStateNotifyMask,
+ XkbIndicatorStateNotifyMask);
+
+ // figure out bit masks for the indicators we are interested in
+ for (int i = 0; i < N_LEDS; i++) {
+ Atom a;
+ int shift;
+ Bool on;
+
+ a = XInternAtom(dpy, ledNames[i], True);
+ if (!a || !XkbGetNamedIndicator(dpy, a, &shift, &on, NULL, NULL))
+ continue;
+
+ ledMasks[i] = 1u << shift;
+ vlog.debug("Mask for '%s' is 0x%x", ledNames[i], ledMasks[i]);
+ if (on)
+ ledState |= 1u << i;
+ }
+
+ TXWindow::setGlobalEventHandler(this);
+ } else {
+ vlog.info("Xkb extension not present");
+ vlog.info("Indicator LED notifications will not be sent");
+ }
+
}
virtual ~XDesktop() {
stop();
@@ -244,6 +284,8 @@ public:
}
#endif

+ server->setLedState(ledState);
+
running = true;
}

@@ -312,6 +354,23 @@ virtual void keyEvent(rdr::U32 key, rdr::U32 code, bool down) {
// -=- TXGlobalEventHandler interface

virtual bool handleGlobalEvent(XEvent* ev) {
+ XkbEvent *kb = (XkbEvent *)ev;
+
+ if (ev->type == xkbEventBase + XkbEventCode && kb->any.xkb_type == XkbIndicatorStateNotify) {
+ vlog.debug("Got indicator update, mask is now 0x%x", kb->indicators.state);
+
+ ledState = 0;
+ for (int i = 0; i < N_LEDS; i++) {
+ if (kb->indicators.state & ledMasks[i])
+ ledState |= 1u << i;
+ }
+
+ if (running)
+ server->setLedState(ledState);
+
+ return true;
+ }
+
#ifdef HAVE_XDAMAGE
XDamageNotifyEvent* dev;
Rect rect;
@@ -348,6 +407,9 @@ protected:
#endif
const unsigned short *codeMap;
unsigned codeMapLen;
+ int xkbEventBase;
+ int ledMasks[N_LEDS];

Pierre Ossman

unread,
Jul 13, 2017, 1:27:18 AM7/13/17
to Peter Korsgaard, tigervn...@googlegroups.com
On 13/07/17 00:35, Peter Korsgaard wrote:
> For thin client use cases, the key symbol based keyboard handling in
> classical RFB cause problems, as a mapping may not always exist
> between the client and server keymap or the indicator led state may
> get out of sync.
>
> Similar issues exists for VNC connections to virtual machines, so QEMU
> has defined two RFB extensions:
>
> - Extended key events, which transmits a layout independent scancode
> together with the keysym
>
> - Keyboard indicator led state notifications from the server to the
> client
>

Heh. Apparently we've been working on the same thing. :)

Fortunately we seem to have chose basically the same approach. And we
seem to have implemented things in slightly different parts of the tree,
so merging our work should get us more than either patch set. :)

My version of the work is here:

https://github.com/CendioOssman/tigervnc/tree/ledstate
https://github.com/CendioOssman/tigervnc/commits/qemukbd

> And are supported by gtk-vnc and noVNC on the client side, and QEMU on
> the server side.

Have you found some client actually using the LED state extension? I
wasn't able to. :/

Regards
--
Pierre Ossman Software Development
Cendio AB http://cendio.com
Teknikringen 8 http://twitter.com/ThinLinc
583 30 Linköping http://facebook.com/ThinLinc
Phone: +46-13-214600 http://plus.google.com/+CendioThinLinc

A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?

Pierre Ossman

unread,
Jul 13, 2017, 1:29:00 AM7/13/17
to Peter Korsgaard, tigervn...@googlegroups.com
On 13/07/17 00:35, Peter Korsgaard wrote:
> Key events from clients supporting the QEMU extended key event message with
> keycodes may not contain a valid key symbol. From rfbproto.rst:
>
> "An unknown keycode or keysym should have the value 0."
>
> This causes problems with the pressedKeys tracking as it doesn't take the
> keycode into consideration and ignores everything but the first release
> event when multiple keys without a keysym are pressed.
>
> As a workaround, don't update pressedKeys if a valid keysym isn't provided.
>
> Signed-off-by: Peter Korsgaard <peter.k...@barco.com>
> ---

This is unfortunately sent by some clients, so we need to handle it. I
did this instead:

https://github.com/CendioOssman/tigervnc/commit/9b7d42da7fa112ddb6310141ba010a0a951071db

Pierre Ossman

unread,
Jul 13, 2017, 1:30:08 AM7/13/17
to Peter Korsgaard, tigervn...@googlegroups.com
On 13/07/17 00:35, Peter Korsgaard wrote:
> Use the client provided (using QEMU extendend key event) scancodes if
> available instead of reverse mapping the keysym.
>
> X11 unfortunately uses keyboard driver specific keycodes and provides
> no direct way to query this, so guess based on the keyboard mapping.
>
> Handle the two most likely keyboard drivers, the old xorgkbd and evdev.
>

Do you think anyone is still using the old kbd driver? I just mapped to
the evdev codes. :)

Pierre Ossman

unread,
Jul 13, 2017, 1:32:11 AM7/13/17
to Peter Korsgaard, tigervn...@googlegroups.com
On 13/07/17 00:35, Peter Korsgaard wrote:
> And interprete the extended key event messages if received by a client.
>
> Hide the logic behind a "AcceptExtendedKeyEvents" option (disabled by
> default).
>
> Signed-off-by: Peter Korsgaard <peter.k...@barco.com>

I put the setting in each server instead as the server might not have
implemented support for it. Figured it might be confusing to list a
setting that doesn't have any effect.

I.e. in these two commits:

https://github.com/CendioOssman/tigervnc/commit/5b717ae0a04b41e53f26f17d2c7c6fc1ceae512e
https://github.com/CendioOssman/tigervnc/commit/345e299a79a41ce8dfd6a7b68145ba81c77f6c13

Pierre Ossman

unread,
Jul 13, 2017, 1:33:47 AM7/13/17
to Peter Korsgaard, tigervn...@googlegroups.com
On 13/07/17 00:36, Peter Korsgaard wrote:
> Add an interface to the server to push led state changes to clients
> supporting it and ensure notifications are sent at connection time and
> when changes occur.
>
> As led state notification doesn't make much sense without the extended keys
> support, also protect it behind the "AcceptExtendedKeyEvents" option.
>

Actually, it is very useful. By keeping the lock keys in sync we can
avoid a lot of fake modifier key events.

Ben Hildred

unread,
Jul 13, 2017, 1:37:33 AM7/13/17
to Pierre Ossman, Peter Korsgaard, tigervn...@googlegroups.com
On Wed, Jul 12, 2017 at 11:30 PM, Pierre Ossman <oss...@cendio.se> wrote:
On 13/07/17 00:35, Peter Korsgaard wrote:
Use the client provided (using QEMU extendend key event) scancodes if
available instead of reverse mapping the keysym.

X11 unfortunately uses keyboard driver specific keycodes and provides
no direct way to query this, so guess based on the keyboard mapping.

Handle the two most likely keyboard drivers, the old xorgkbd and evdev.


Do you think anyone is still using the old kbd driver? I just mapped to the evdev codes. :)

Yes, everyone not running linux. evdev is linux specific. so you have open bsd,  free bsd, net bsd, solaris, etc.

Regards
--
Pierre Ossman           Software Development
Cendio AB               http://cendio.com
Teknikringen 8          http://twitter.com/ThinLinc
583 30 Linköping        http://facebook.com/ThinLinc
Phone: +46-13-214600 http://plus.google.com/+CendioThinLinc

A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?


--
You received this message because you are subscribed to the Google Groups "TigerVNC Developer Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to tigervnc-devel+unsubscribe@googlegroups.com.
To post to this group, send email to tigervn...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/tigervnc-devel/dd7eeea3-3995-fe65-bdc0-641a9fec86dc%40cendio.se.

For more options, visit https://groups.google.com/d/optout.



--
--
Ben Hildred
Automation Support Services

Pierre Ossman

unread,
Jul 13, 2017, 1:38:35 AM7/13/17
to Ben Hildred, Peter Korsgaard, tigervn...@googlegroups.com
On 13/07/17 07:37, Ben Hildred wrote:
> On Wed, Jul 12, 2017 at 11:30 PM, Pierre Ossman <oss...@cendio.se> wrote:
>
>> On 13/07/17 00:35, Peter Korsgaard wrote:
>>
>>> Use the client provided (using QEMU extendend key event) scancodes if
>>> available instead of reverse mapping the keysym.
>>>
>>> X11 unfortunately uses keyboard driver specific keycodes and provides
>>> no direct way to query this, so guess based on the keyboard mapping.
>>>
>>> Handle the two most likely keyboard drivers, the old xorgkbd and evdev.
>>>
>>>
>> Do you think anyone is still using the old kbd driver? I just mapped to
>> the evdev codes. :)
>>
>
> Yes, everyone not running linux. evdev is linux specific. so you have open
> bsd, free bsd, net bsd, solaris, etc.
>

I see. Good to know. Figured they might have their own variants.

Peter Korsgaard

unread,
Jul 13, 2017, 2:52:53 AM7/13/17
to Pierre Ossman, Peter Korsgaard, tigervn...@googlegroups.com
>>>>> "Pierre" == Pierre Ossman <oss...@cendio.se> writes:

> On 13/07/17 00:35, Peter Korsgaard wrote:
>> Key events from clients supporting the QEMU extended key event message with
>> keycodes may not contain a valid key symbol. From rfbproto.rst:
>>
>> "An unknown keycode or keysym should have the value 0."
>>
>> This causes problems with the pressedKeys tracking as it doesn't take the
>> keycode into consideration and ignores everything but the first release
>> event when multiple keys without a keysym are pressed.
>>
>> As a workaround, don't update pressedKeys if a valid keysym isn't provided.
>>
>> Signed-off-by: Peter Korsgaard <peter.k...@barco.com>
>> ---

> This is unfortunately sent by some clients, so we need to handle it. I
> did this instead:

> https://github.com/CendioOssman/tigervnc/commit/9b7d42da7fa112ddb6310141ba010a0a951071db

Sorry, what is sent? extended key events with keysym=0?

The whole point of the extended key event is to get rid of all this
complicated heuristics and tracking, which is why I completely disabled
it.

But it is true that it doesn't release any pressed keys on client
disconnect, which isn't good.

It is not right away clear to me if your change solves both of these
issues (all scancodes sent straight though, and release of keys on
disconnect), but it might.

I'll take a closer look.

--
Bye, Peter Korsgaard

Peter Korsgaard

unread,
Jul 13, 2017, 2:55:23 AM7/13/17
to Pierre Ossman, Peter Korsgaard, tigervn...@googlegroups.com
>>>>> "Pierre" == Pierre Ossman <oss...@cendio.se> writes:

> On 13/07/17 00:35, Peter Korsgaard wrote:
>> Use the client provided (using QEMU extendend key event) scancodes if
>> available instead of reverse mapping the keysym.
>>
>> X11 unfortunately uses keyboard driver specific keycodes and provides
>> no direct way to query this, so guess based on the keyboard mapping.
>>
>> Handle the two most likely keyboard drivers, the old xorgkbd and evdev.
>>

> Do you think anyone is still using the old kbd driver? I just mapped
> to the evdev codes. :)

I must say it was a bit of cargo cult as E.G. qemu and gtk-vnc still
do the evdev/kbd dance.

I don't personally need anything else than evdev, but I'm not sure what
the tigervnc policy is / what non-Linux OS'es this gets used on.

--
Bye, Peter Korsgaard

Peter Korsgaard

unread,
Jul 13, 2017, 2:58:28 AM7/13/17
to Pierre Ossman, Peter Korsgaard, tigervn...@googlegroups.com
>>>>> "Pierre" == Pierre Ossman <oss...@cendio.se> writes:

> On 13/07/17 00:35, Peter Korsgaard wrote:
>> And interprete the extended key event messages if received by a client.
>>
>> Hide the logic behind a "AcceptExtendedKeyEvents" option (disabled by
>> default).
>>
>> Signed-off-by: Peter Korsgaard <peter.k...@barco.com>

> I put the setting in each server instead as the server might not have
> implemented support for it. Figured it might be confusing to list a
> setting that doesn't have any effect.

> I.e. in these two commits:

> https://github.com/CendioOssman/tigervnc/commit/5b717ae0a04b41e53f26f17d2c7c6fc1ceae512e
> https://github.com/CendioOssman/tigervnc/commit/345e299a79a41ce8dfd6a7b68145ba81c77f6c13

Correct. I'm fine with it either way, but with the per-server setting it
would be good to completely disable the extension negotiation. Right now
the client thinks the server supports the extension but you finally just
ignore the data.

--
Bye, Peter Korsgaard

Peter Korsgaard

unread,
Jul 13, 2017, 2:58:30 AM7/13/17
to Pierre Ossman, Peter Korsgaard, tigervn...@googlegroups.com
>>>>> "Pierre" == Pierre Ossman <oss...@cendio.se> writes:

Hi,

> On 13/07/17 00:35, Peter Korsgaard wrote:
>> For thin client use cases, the key symbol based keyboard handling in
>> classical RFB cause problems, as a mapping may not always exist
>> between the client and server keymap or the indicator led state may
>> get out of sync.
>>
>> Similar issues exists for VNC connections to virtual machines, so QEMU
>> has defined two RFB extensions:
>>
>> - Extended key events, which transmits a layout independent scancode
>> together with the keysym
>>
>> - Keyboard indicator led state notifications from the server to the
>> client
>>

> Heh. Apparently we've been working on the same thing. :)

Ahh, great minds think alike ;)


> Fortunately we seem to have chose basically the same approach. And we
> seem to have implemented things in slightly different parts of the
> tree, so merging our work should get us more than either patch set. :)

> My version of the work is here:

> https://github.com/CendioOssman/tigervnc/tree/ledstate
> https://github.com/CendioOssman/tigervnc/commits/qemukbd

Thanks. I so far only had a quick look, but it seems doable to merge. I
haven't focused at all on the client side, but you have.

Are the indicator state heuristics in commit e35f370340 (Add server side
lock key sync heuristic) useful? Are there any real use cases where
clients wants to get led state notifications but not send scancodes, or
is it for mixed client setups?


>> And are supported by gtk-vnc and noVNC on the client side, and QEMU on
>> the server side.

> Have you found some client actually using the LED state extension? I
> wasn't able to. :/

Sorry, not really - I've written my own client as part of a closed
source product that uses it. Gtk-vnc has the infrastructure to support
it, but isn't negotiating it. I've sent a patch to at least negotiate it
some time ago, but so far without feedback:

https://mail.gnome.org/archives/gtk-vnc-list/2017-June/msg00000.html

How would you like to progress on this? Do you want me to merge my
changes with yours or do you want to handle it?

--
Bye, Peter Korsgaard

Peter Korsgaard

unread,
Jul 13, 2017, 3:03:49 AM7/13/17
to Pierre Ossman, Peter Korsgaard, tigervn...@googlegroups.com
>>>>> "Pierre" == Pierre Ossman <oss...@cendio.se> writes:

> On 13/07/17 00:36, Peter Korsgaard wrote:
>> Add an interface to the server to push led state changes to clients
>> supporting it and ensure notifications are sent at connection time and
>> when changes occur.
>>
>> As led state notification doesn't make much sense without the extended keys
>> support, also protect it behind the "AcceptExtendedKeyEvents" option.
>>

> Actually, it is very useful. By keeping the lock keys in sync we can
> avoid a lot of fake modifier key events.

sorry, I don't follow. How does that work exactly?

If a client wants to send E.G. 'A', how does knowing the state of the
caps lock key help? It should still just send a keyevent with
keysym=XK_A, right?

--
Bye, Peter Korsgaard

Pierre Ossman

unread,
Jul 13, 2017, 3:27:00 AM7/13/17
to Peter Korsgaard, Peter Korsgaard, tigervn...@googlegroups.com
On 13/07/17 09:03, Peter Korsgaard wrote:
>
> sorry, I don't follow. How does that work exactly?
>
> If a client wants to send E.G. 'A', how does knowing the state of the
> caps lock key help? It should still just send a keyevent with
> keysym=XK_A, right?
>

It helps the server. If a client send XK_A, but caps lock is off on the
server, then no single key press can generated the desired keysym. So
right now it fakes a press of shift, then A, then releases the shift
key. And these extra, fake keys can cause issues with some applications.

If the lock keys are in sync then the server will in most cases be in a
state where a single RFB key event can result in a single server side event.

Regards
--
Pierre Ossman Software Development
Cendio AB https://cendio.com
Teknikringen 8 https://twitter.com/ThinLinc
583 30 Linköping https://facebook.com/ThinLinc
Phone: +46-13-214600 https://plus.google.com/+CendioThinLinc

Pierre Ossman

unread,
Jul 13, 2017, 3:27:01 AM7/13/17
to Peter Korsgaard, Peter Korsgaard, tigervn...@googlegroups.com
On 13/07/17 08:38, Peter Korsgaard wrote:
>
> Are the indicator state heuristics in commit e35f370340 (Add server side
> lock key sync heuristic) useful? Are there any real use cases where
> clients wants to get led state notifications but not send scancodes, or
> is it for mixed client setups?
>

They are very useful as it does a pretty good job of getting the lock
keys right for clients that don't support this extension. See the other
message I sent for an example.

>
> >> And are supported by gtk-vnc and noVNC on the client side, and QEMU on
> >> the server side.
>
> > Have you found some client actually using the LED state extension? I
> > wasn't able to. :/
>
> Sorry, not really - I've written my own client as part of a closed
> source product that uses it. Gtk-vnc has the infrastructure to support
> it, but isn't negotiating it. I've sent a patch to at least negotiate it
> some time ago, but so far without feedback:
>
> https://mail.gnome.org/archives/gtk-vnc-list/2017-June/msg00000.html
>

A shame. But at least you can do some interoperability testing using
your client then. :)

> How would you like to progress on this? Do you want me to merge my
> changes with yours or do you want to handle it?
>

I can sort out the merging. I just need to take a closer look at how our
versions differ so we get the best of both. :)

Regards
--
Pierre Ossman Software Development
Phone: +46-13-214600 https://plus.google.com/+CendioThinLinc

Pierre Ossman

unread,
Jul 13, 2017, 3:29:05 AM7/13/17
to Peter Korsgaard, Peter Korsgaard, tigervn...@googlegroups.com, Ben Hildred
On 13/07/17 08:55, Peter Korsgaard wrote:
>
> > Do you think anyone is still using the old kbd driver? I just mapped
> > to the evdev codes. :)
>
> I must say it was a bit of cargo cult as E.G. qemu and gtk-vnc still
> do the evdev/kbd dance.
>
> I don't personally need anything else than evdev, but I'm not sure what
> the tigervnc policy is / what non-Linux OS'es this gets used on.
>

Well, we don't actively work against them, but we also don't have any
developer working for them. But Ben pointed out that this was useful, so
let's keep it.

I'm wondering if I should do something similar for the Xvnc/libvnc.so
code...

Ben?

Regards
--
Pierre Ossman Software Development
Phone: +46-13-214600 https://plus.google.com/+CendioThinLinc

Pierre Ossman

unread,
Jul 13, 2017, 3:32:33 AM7/13/17
to Peter Korsgaard, Peter Korsgaard, tigervn...@googlegroups.com
On 13/07/17 08:52, Peter Korsgaard wrote:
>
> Sorry, what is sent? extended key events with keysym=0?
>

Right.

> The whole point of the extended key event is to get rid of all this
> complicated heuristics and tracking, which is why I completely disabled
> it.
>

I don't trust clients enough for that. :)

As you noticed, it's nice to have the safety net of releasing all keys
when a client disconnects. We also still need to support clients that
don't use this extension, so we can't get completely rid of the code. We
also need to handle clients of either type being connected to the same
server.

> But it is true that it doesn't release any pressed keys on client
> disconnect, which isn't good.
>
> It is not right away clear to me if your change solves both of these
> issues (all scancodes sent straight though, and release of keys on
> disconnect), but it might.
>
> I'll take a closer look.
>

Please do. Feedback is appreciated. :)

Regards
--
Pierre Ossman Software Development
Phone: +46-13-214600 https://plus.google.com/+CendioThinLinc

Pierre Ossman

unread,
Jul 13, 2017, 3:34:53 AM7/13/17
to Peter Korsgaard, Peter Korsgaard, tigervn...@googlegroups.com
Possibly. But I thought it might be something that could be changed
whilst a client is connected.

I'm on the fence about this one. If all our servers support this, then
why duplicate code... I'll have to mull it over a bit. :)

Regards
--
Pierre Ossman Software Development
Phone: +46-13-214600 https://plus.google.com/+CendioThinLinc

Peter Korsgaard

unread,
Jul 13, 2017, 4:20:26 AM7/13/17
to Pierre Ossman, Peter Korsgaard, tigervn...@googlegroups.com, Ben Hildred
>>>>> "Pierre" == Pierre Ossman <oss...@cendio.se> writes:

Hi,

> Well, we don't actively work against them, but we also don't have any
> developer working for them. But Ben pointed out that this was useful,
> so let's keep it.

Ok.

> I'm wondering if I should do something similar for the Xvnc/libvnc.so
> code...

Hmm, I don't know. What keymapping is Xvnc using? Looks to be evdev
based on xprop -root|grep XKB

--
Bye, Peter Korsgaard

Peter Korsgaard

unread,
Jul 13, 2017, 4:23:05 AM7/13/17
to Pierre Ossman, Peter Korsgaard, tigervn...@googlegroups.com
>>>>> "Pierre" == Pierre Ossman <oss...@cendio.se> writes:

Hi,

>> Correct. I'm fine with it either way, but with the per-server setting it
>> would be good to completely disable the extension negotiation. Right now
>> the client thinks the server supports the extension but you finally just
>> ignore the data.
>>

> Possibly. But I thought it might be something that could be changed
> whilst a client is connected.

It can be. The client is afaik free to use both classic keyevent and
extended keyevent messages - But it is a bit strange to allow
negotiation of extended key event support if we then ignore it
afterwards.

> I'm on the fence about this one. If all our servers support this, then
> why duplicate code... I'll have to mull it over a bit. :)

Ok.

--
Bye, Peter Korsgaard

Pierre Ossman

unread,
Jul 13, 2017, 4:32:25 AM7/13/17
to Peter Korsgaard, Peter Korsgaard, tigervn...@googlegroups.com, Ben Hildred
The current code has no fundamental connection to any system as it only
looks at keysyms. So it depends on what XKB map you decide to load in to
the server.

My new branch however always translates the RFB codes to evdev codes.
This works fine if you load an evdev XKB map, but will break if you load
some other map.

Peter Korsgaard

unread,
Jul 13, 2017, 4:33:48 AM7/13/17
to Pierre Ossman, Peter Korsgaard, tigervn...@googlegroups.com
>>>>> "Pierre" == Pierre Ossman <oss...@cendio.se> writes:

> On 13/07/17 09:03, Peter Korsgaard wrote:
>>
>> sorry, I don't follow. How does that work exactly?
>>
>> If a client wants to send E.G. 'A', how does knowing the state of the
>> caps lock key help? It should still just send a keyevent with
>> keysym=XK_A, right?
>>

> It helps the server. If a client send XK_A, but caps lock is off on
> the server, then no single key press can generated the desired
> keysym. So right now it fakes a press of shift, then A, then releases
> the shift key. And these extra, fake keys can cause issues with some
> applications.

So you mean that if the client learns that the indicator state of the
server doesn't match the state of the client, then it could send fake
capslock/numlock/scrollock keyevent messages to the server until it
matches the local state, so these extra fake shifts don't need to be
generated on the server?

This would break down if more than one client (with different
indicator led state) tries to do this as they would end up figting
eachother, so a better approach is to get the client state to follow the
server state (and then the easiest is imho to just send scancodes).

--
Bye, Peter Korsgaard

Peter Korsgaard

unread,
Jul 13, 2017, 4:35:31 AM7/13/17
to Pierre Ossman, Peter Korsgaard, tigervn...@googlegroups.com
>>>>> "Pierre" == Pierre Ossman <oss...@cendio.se> writes:

> On 13/07/17 08:52, Peter Korsgaard wrote:
>>
>> Sorry, what is sent? extended key events with keysym=0?
>>

> Right.

>> The whole point of the extended key event is to get rid of all this
>> complicated heuristics and tracking, which is why I completely disabled
>> it.
>>

> I don't trust clients enough for that. :)

Heh ;) It helps that I wrote the client myself.


> As you noticed, it's nice to have the safety net of releasing all keys
> when a client disconnects. We also still need to support clients that
> don't use this extension, so we can't get completely rid of the
> code. We also need to handle clients of either type being connected to
> the same server.

Correct.


>> I'll take a closer look.

> Please do. Feedback is appreciated. :)

I'll get back to you later today on that. And likewise on feedback!

--
Bye, Peter Korsgaard

Pierre Ossman

unread,
Jul 13, 2017, 4:40:11 AM7/13/17
to Peter Korsgaard, Peter Korsgaard, tigervn...@googlegroups.com
On 13/07/17 10:33, Peter Korsgaard wrote:
>>>>>> "Pierre" == Pierre Ossman <oss...@cendio.se> writes:
>
> > On 13/07/17 09:03, Peter Korsgaard wrote:
> >>
> >> sorry, I don't follow. How does that work exactly?
> >>
> >> If a client wants to send E.G. 'A', how does knowing the state of the
> >> caps lock key help? It should still just send a keyevent with
> >> keysym=XK_A, right?
> >>
>
> > It helps the server. If a client send XK_A, but caps lock is off on
> > the server, then no single key press can generated the desired
> > keysym. So right now it fakes a press of shift, then A, then releases
> > the shift key. And these extra, fake keys can cause issues with some
> > applications.
>
> So you mean that if the client learns that the indicator state of the
> server doesn't match the state of the client, then it could send fake
> capslock/numlock/scrollock keyevent messages to the server until it
> matches the local state, so these extra fake shifts don't need to be
> generated on the server?
>

Almost. This happens at the server as this heuristic is for clients that
don't have this extension. So if the server notices a state where it
looks like Caps Lock should be toggled, then it sends a fake Caps Lock
to the lower layers.

> This would break down if more than one client (with different
> indicator led state) tries to do this as they would end up figting
> eachother, so a better approach is to get the client state to follow the
> server state (and then the easiest is imho to just send scancodes).
>

Indeed. But we can't force every client to be updated to follow these
extensions. :)

(and if the fighting turns out to be a serious issue then we can
probably tweak things, e.g. turning it off when multiple clients are
connected)

Peter Korsgaard

unread,
Jul 20, 2017, 9:05:02 AM7/20/17
to Pierre Ossman, Peter Korsgaard, tigervn...@googlegroups.com
>>>>> "Pierre" == Pierre Ossman <oss...@cendio.se> writes:

Hi,

>> How would you like to progress on this? Do you want me to merge my
>> changes with yours or do you want to handle it?

> I can sort out the merging. I just need to take a closer look at how
> our versions differ so we get the best of both. :)

Did you manage to make any progress on this? Anything I can do? I'm
leaving on holidays a week from now, so it would be good if we could get
the ball rolling before then.

--
Bye, Peter Korsgaard

Pierre Ossman

unread,
Jul 20, 2017, 9:37:01 AM7/20/17
to Peter Korsgaard, Peter Korsgaard, tigervn...@googlegroups.com
Sorry, I've been absolutely swamped with other things here. I'm leaving
on holiday next week, so unfortunately it looks like this will have to
wait until after that. Realistically I think that means September. :/

Peter Korsgaard

unread,
Jul 20, 2017, 9:38:51 AM7/20/17
to Pierre Ossman, Peter Korsgaard, tigervn...@googlegroups.com
>>>>> "Pierre" == Pierre Ossman <oss...@cendio.se> writes:

Hi,

>> Did you manage to make any progress on this? Anything I can do? I'm
>> leaving on holidays a week from now, so it would be good if we could get
>> the ball rolling before then.
>>

> Sorry, I've been absolutely swamped with other things here. I'm
> leaving on holiday next week, so unfortunately it looks like this will
> have to wait until after that. Realistically I think that means
> September. :/

Ok, I understand - No problem. Let me know if there's anything I can do.

--
Bye, Peter Korsgaard
Reply all
Reply to author
Forward
0 new messages