Merge branch 'x0vncshift' of https://github.com/CendioOssman/tigervnc
diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx
index 1ca7378..025a095 100644
--- a/unix/x0vncserver/x0vncserver.cxx
+++ b/unix/x0vncserver/x0vncserver.cxx
@@ -332,20 +332,67 @@
 #endif
   }
 
+#ifdef HAVE_XTEST
+  KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym) {
+    XkbDescPtr xkb;
+    XkbStateRec state;
+    unsigned keycode;
+
+    xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
+    if (!xkb)
+      return 0;
+
+    XkbGetState(dpy, XkbUseCoreKbd, &state);
+
+    for (keycode = xkb->min_key_code;
+         keycode <= xkb->max_key_code;
+         keycode++) {
+      KeySym cursym;
+      unsigned int mods;
+      XkbTranslateKeyCode(xkb, keycode, state.compat_state, &mods, &cursym);
+      if (cursym == keysym)
+        break;
+    }
+
+    if (keycode > xkb->max_key_code)
+      keycode = 0;
+
+    XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);
+
+    return keycode;
+  }
+#endif
+
   virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down) {
 #ifdef HAVE_XTEST
     int keycode = 0;
-    if (!haveXtest) return;
+
+    if (!haveXtest)
+      return;
 
     // Use scan code if provided and mapping exists
     if (codeMap && rawKeyboard && xtcode < codeMapLen)
         keycode = codeMap[xtcode];
 
-    if (!keycode)
-        keycode = XKeysymToKeycode(dpy, keysym);
+    if (!keycode) {
+      if (!down || (pressedKeys.find(keysym) != pressedKeys.end()))
+        keycode = pressedKeys[keysym];
+      else {
+        // XKeysymToKeycode() doesn't respect state, so we have to use
+        // something slightly more complex
+        keycode = XkbKeysymToKeycode(dpy, keysym);
+      }
+    }
 
-    if (keycode)
-      XTestFakeKeyEvent(dpy, keycode, down, CurrentTime);
+    if (!keycode)
+      return;
+
+    if (down)
+      pressedKeys[keysym] = keycode;
+    else
+      pressedKeys.erase(keysym);
+
+    XTestFakeKeyEvent(dpy, keycode, down, CurrentTime);
 #endif
   }
 
@@ -405,6 +452,7 @@
   bool haveXtest;
   bool haveDamage;
   int maxButtons;
+  std::map<KeySym, KeyCode> pressedKeys;
   bool running;
 #ifdef HAVE_XDAMAGE
   Damage damage;