]> source.dussan.org Git - tigervnc.git/commitdiff
Add server side lock key sync heuristic
authorPierre Ossman <ossman@cendio.se>
Sun, 11 Dec 2016 11:41:26 +0000 (12:41 +0100)
committerPierre Ossman <ossman@cendio.se>
Thu, 24 Aug 2017 10:33:08 +0000 (12:33 +0200)
Based on QEMU's behaviour.

common/rfb/VNCSConnectionST.cxx
common/rfb/VNCServer.h
common/rfb/VNCServerST.cxx
common/rfb/VNCServerST.h
unix/xserver/hw/vnc/Input.c
unix/xserver/hw/vnc/Input.h
unix/xserver/hw/vnc/InputXKB.c

index 53dd364a6ad89a307a631a6e0d273de294b8f882..de41e8fc8ccfe33f6cd47686a5d513329ab2ff10 100644 (file)
 #include <rfb/Security.h>
 #include <rfb/screenTypes.h>
 #include <rfb/fenceTypes.h>
+#include <rfb/ledStates.h>
 #include <rfb/ServerCore.h>
 #include <rfb/ComparingUpdateTracker.h>
 #include <rfb/KeyRemapper.h>
 #include <rfb/Encoder.h>
+#define XK_LATIN1
 #define XK_MISCELLANY
 #define XK_XKB_KEYS
 #include <rfb/keysymdef.h>
@@ -560,6 +562,73 @@ void VNCSConnectionST::keyEvent(rdr::U32 key, bool down) {
     }
   }
 
+  // Avoid lock keys if we don't know the server state
+  if ((server->ledState == ledUnknown) &&
+      ((key == XK_Caps_Lock) ||
+       (key == XK_Num_Lock) ||
+       (key == XK_Scroll_Lock))) {
+    vlog.debug("Ignoring lock key (e.g. caps lock)");
+    return;
+  }
+  // Always ignore ScrollLock though as we don't have a heuristic
+  // for that
+  if (key == XK_Scroll_Lock) {
+    vlog.debug("Ignoring lock key (e.g. caps lock)");
+    return;
+  }
+
+  if (down && (server->ledState != ledUnknown)) {
+    // CapsLock synchronisation heuristic
+    // (this assumes standard interaction between CapsLock the Shift
+    // keys and normal characters)
+    if (((key >= XK_A) && (key <= XK_Z)) ||
+        ((key >= XK_a) && (key <= XK_z))) {
+      bool uppercase, shift, lock;
+
+      uppercase = (key >= XK_A) && (key <= XK_Z);
+      shift = pressedKeys.find(XK_Shift_L) != pressedKeys.end() ||
+              pressedKeys.find(XK_Shift_R) != pressedKeys.end();
+      lock = server->ledState & ledCapsLock;
+
+      if (lock == (uppercase == shift)) {
+        vlog.debug("Inserting fake CapsLock to get in sync with client");
+        server->desktop->keyEvent(XK_Caps_Lock, true);
+        server->desktop->keyEvent(XK_Caps_Lock, false);
+      }
+    }
+
+    // NumLock synchronisation heuristic
+    // (this is more cautious because of the differences between Unix,
+    // Windows and macOS)
+    if (((key >= XK_KP_Home) && (key <= XK_KP_Delete)) ||
+        ((key >= XK_KP_0) && (key <= XK_KP_9)) ||
+        (key == XK_KP_Separator) || (key == XK_KP_Decimal)) {
+      bool number, shift, lock;
+
+      number = ((key >= XK_KP_0) && (key <= XK_KP_9)) ||
+                (key == XK_KP_Separator) || (key == XK_KP_Decimal);
+      shift = pressedKeys.find(XK_Shift_L) != pressedKeys.end() ||
+              pressedKeys.find(XK_Shift_R) != pressedKeys.end();
+      lock = server->ledState & ledNumLock;
+
+      if (shift) {
+        // We don't know the appropriate NumLock state for when Shift
+        // is pressed as it could be one of:
+        //
+        // a) A Unix client where Shift negates NumLock
+        //
+        // b) A Windows client where Shift only cancels NumLock
+        //
+        // c) A macOS client where Shift doesn't have any effect
+        //
+      } else if (lock == (number == shift)) {
+        vlog.debug("Inserting fake NumLock to get in sync with client");
+        server->desktop->keyEvent(XK_Num_Lock, true);
+        server->desktop->keyEvent(XK_Num_Lock, false);
+      }
+    }
+  }
+
   // Turn ISO_Left_Tab into shifted Tab.
   VNCSConnectionSTShiftPresser shiftPresser(server->desktop);
   if (key == XK_ISO_Left_Tab) {
index 982a4ff54e9b3f203910ad117bf61ded37bac9d5..c5335ad2f8d0291eb20d37e67eb206d902bf4be6 100644 (file)
@@ -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 what the current lock keys LED
+    // state is
+    virtual void setLEDState(unsigned int state) = 0;
   };
 }
 #endif
index ec5e962f04bf142d8447fb76c8b65956a52ecccb..28f6a62be66026113fdfcf81539c4abcc2cc4452 100644 (file)
@@ -58,6 +58,7 @@
 #include <rfb/Security.h>
 #include <rfb/KeyRemapper.h>
 #include <rfb/util.h>
+#include <rfb/ledStates.h>
 
 #include <rdr/types.h>
 
@@ -74,7 +75,7 @@ LogWriter VNCServerST::connectionsLog("Connections");
 
 VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
   : blHosts(&blacklist), desktop(desktop_), desktopStarted(false),
-    blockCounter(0), pb(0),
+    blockCounter(0), pb(0), ledState(ledUnknown),
     name(strDup(name_)), pointerClient(0), comparer(0),
     cursor(new Cursor(0, 0, Point(), NULL)),
     renderedCursorInvalid(false),
@@ -458,6 +459,11 @@ void VNCServerST::setCursorPos(const Point& pos)
   }
 }
 
+void VNCServerST::setLEDState(unsigned int state)
+{
+  ledState = state;
+}
+
 // Other public methods
 
 void VNCServerST::approveConnection(network::Socket* sock, bool accept,
index 00f77c733d5cbae7291427b667146cd3d586304a..2dfdbbdbcff984e5f79940289103a18c19de2736 100644 (file)
@@ -101,6 +101,7 @@ namespace rfb {
     virtual void setCursor(int width, int height, const Point& hotspot,
                            const rdr::U8* data);
     virtual void setCursorPos(const Point& p);
+    virtual void setLEDState(unsigned state);
 
     virtual void bell();
 
@@ -209,6 +210,7 @@ namespace rfb {
     int blockCounter;
     PixelBuffer* pb;
     ScreenSet screenLayout;
+    unsigned int ledState;
 
     CharArray name;
 
index 33e8604bfde61d7454952bee3ccd599d161c2f1c..1d7183b90092f112eb17e797a54dadfaf637872c 100644 (file)
@@ -437,12 +437,6 @@ void vncKeyboardEvent(KeySym keysym, int down)
                }
        }
 
-       /* We don't have lock synchronisation... */
-       if (vncIsLockModifier(keycode, new_state)) {
-               LOG_DEBUG("Ignoring lock key (e.g. caps lock)");
-               return;
-       }
-
        /* No matches. Will have to add a new entry... */
        if (keycode == 0) {
                keycode = vncAddKeysym(keysym, state);
index 11e887108e8a7dcea25881a3e3f0f49386bc4ea9..67b9c8db69d536f14bf1d54ccf5e3a84dd0ec0ca 100644 (file)
@@ -53,8 +53,6 @@ size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys);
 
 KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state);
 
-int vncIsLockModifier(KeyCode keycode, unsigned state);
-
 int vncIsAffectedByNumLock(KeyCode keycode);
 
 KeyCode vncAddKeysym(KeySym keysym, unsigned state);
index 2a3f7afb0223c4b44b098e988bc6f4e94692e34d..a9bd11d13b32ac1a0ef1f9cbbf633fc1d8e05319 100644 (file)
@@ -485,23 +485,6 @@ KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
        return 0;
 }
 
-int vncIsLockModifier(KeyCode keycode, unsigned state)
-{
-       XkbDescPtr xkb;
-       XkbAction *act;
-
-       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
-
-       act = XkbKeyActionPtr(xkb, keycode, state);
-       if (act == NULL)
-               return 0;
-
-       if (act->type != XkbSA_LockMods)
-               return 0;
-
-       return 1;
-}
-
 int vncIsAffectedByNumLock(KeyCode keycode)
 {
        unsigned state;