]> source.dussan.org Git - tigervnc.git/commitdiff
Some applications (e.g. wine and rdesktop) tend to misbehave
authorPierre Ossman <ossman@cendio.se>
Thu, 30 May 2013 14:50:57 +0000 (14:50 +0000)
committerPierre Ossman <ossman@cendio.se>
Thu, 30 May 2013 14:50:57 +0000 (14:50 +0000)
when we use fake shift to get different symbols on the numpad.
So avoid using fake shifts on NumLock related keys and hope
that other applications won't get upset by getting the
non-numpad keysym counterparts.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@5119 3789f03b-4d11-0410-bbf8-ca57d06f2519

unix/xserver/hw/vnc/Input.cc
unix/xserver/hw/vnc/Input.h
unix/xserver/hw/vnc/InputCore.cc
unix/xserver/hw/vnc/InputXKB.cc

index 83f2ef3e1c7652ba1b916a3b7369a260e693da99..a6a51d7fc28e5880923017f201e358399570a33d 100644 (file)
@@ -64,6 +64,8 @@ using namespace rfb;
 
 static LogWriter vlog("Input");
 
+rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock", "Avoid fake Shift presses for keys affected by NumLock.", true);
+
 #define BUTTONS 7
 
 /* Event queue is shared between all devices. */
@@ -519,6 +521,53 @@ void InputDevice::keyEvent(rdr::U32 keysym, bool down)
                }
        }
 
+       /*
+        * X11 generally lets shift toggle the keys on the numeric pad
+        * the same way NumLock does. This is however not the case on
+        * other systems like Windows. As a result, some applications
+        * get confused when we do a fake shift to get the same effect
+        * that having NumLock active would produce.
+        *
+        * Until we have proper NumLock synchronisation (so we can
+        * avoid faking shift), we try to avoid the fake shifts if we
+        * can use an alternative keysym.
+        */
+       if (((state & ShiftMask) != (new_state & ShiftMask)) &&
+           avoidShiftNumLock && isAffectedByNumLock(keycode)) {
+               KeyCode keycode2;
+               unsigned new_state2;
+
+               vlog.debug("Finding alternative to keysym 0x%x to avoid fake shift for numpad", keysym);
+
+               for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) {
+                       KeySym altsym;
+
+                       if (altKeysym[i].a == keysym)
+                               altsym = altKeysym[i].b;
+                       else if (altKeysym[i].b == keysym)
+                               altsym = altKeysym[i].a;
+                       else
+                               continue;
+
+                       keycode2 = keysymToKeycode(altsym, state, &new_state2);
+                       if (keycode2 == 0)
+                               continue;
+
+                       if (((state & ShiftMask) != (new_state2 & ShiftMask)) &&
+                           isAffectedByNumLock(keycode2))
+                               continue;
+
+                       break;
+               }
+
+               if (i == sizeof(altKeysym)/sizeof(altKeysym[0]))
+                       vlog.debug("No alternative keysym found");
+               else {
+                       keycode = keycode2;
+                       new_state = new_state2;
+               }
+       }
+
        /*
         * "Shifted Tab" is a bit of a mess. Some systems have varying,
         * special keysyms for this symbol. VNC mandates that clients
index 3a0e90392f52b30203273329715bc7cfb2d04769..e893049e5f5df6273f94b2966fa232b7890a88f7 100644 (file)
@@ -91,6 +91,8 @@ private:
 
        bool isLockModifier(KeyCode keycode, unsigned state);
 
+       bool isAffectedByNumLock(KeyCode keycode);
+
        KeyCode addKeysym(KeySym keysym, unsigned state);
 
 private:
index de7653ef514341a20587f0d85cc68ccf9b98911a..a880ca07ace283aa2735ebd9250a996218611a3b 100644 (file)
@@ -514,6 +514,26 @@ done:
        return false;
 }
 
+bool InputDevice::isAffectedByNumLock(KeyCode keycode)
+{
+       KeySymsPtr keymap;
+       int i, per;
+       KeySym *syms;
+
+       keymap = &keyboardDev->key->curKeySyms;
+       per = keymap->mapWidth;
+       syms = &keymap->map[(keycode - keymap->minKeyCode) * per];
+
+       for (i = 0;i < per;i++) {
+               if (IsKeypadKey(syms[i]))
+                       return true;
+               if (IsPrivateKeypadKey(syms[i]))
+                       return true;
+       }
+
+       return false;
+}
+
 KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state)
 {
        KeyCode kc;
index 4c04ef9fcca490b243b9b24854daa09ac223c926..ed93afcc84ce8e3d4257e79e7924575b1709e70e 100644 (file)
@@ -177,6 +177,36 @@ static XkbAction *XkbKeyActionPtr(XkbDescPtr xkb, KeyCode key, unsigned int mods
        return &acts[col];
 }
 
+static unsigned XkbKeyEffectiveGroup(XkbDescPtr xkb, KeyCode key, unsigned int mods)
+{
+       int nKeyGroups;
+       unsigned effectiveGroup;
+
+       nKeyGroups= XkbKeyNumGroups(xkb,key);
+       if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0))
+               return 0;
+
+       effectiveGroup= XkbGroupForCoreState(mods);
+       if ( effectiveGroup>=nKeyGroups ) {
+               unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
+               switch (XkbOutOfRangeGroupAction(groupInfo)) {
+               default:
+                       effectiveGroup %= nKeyGroups;
+                       break;
+               case XkbClampIntoRange:
+                       effectiveGroup = nKeyGroups-1;
+                       break;
+               case XkbRedirectIntoRange:
+                       effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
+                       if (effectiveGroup>=nKeyGroups)
+                               effectiveGroup= 0;
+                       break;
+               }
+       }
+
+       return effectiveGroup;
+}
+
 void InputDevice::PrepareInputDevices(void)
 {
 #if XORG < 19
@@ -479,6 +509,53 @@ bool InputDevice::isLockModifier(KeyCode keycode, unsigned state)
        return true;
 }
 
+bool InputDevice::isAffectedByNumLock(KeyCode keycode)
+{
+       unsigned state;
+
+       KeyCode numlock_keycode;
+       unsigned numlock_mask;
+
+       XkbDescPtr xkb;
+       XkbAction *act;
+
+       unsigned group;
+       XkbKeyTypeRec *type;
+
+       /* Group state is still important */
+       state = getKeyboardState();
+       state &= ~0xff;
+
+       /*
+        * Not sure if hunting for a virtual modifier called "NumLock",
+        * or following the keysym Num_Lock is the best approach. We
+        * try the latter.
+        */
+       numlock_keycode = keysymToKeycode(XK_Num_Lock, state, NULL);
+       if (numlock_keycode == 0)
+               return false;
+
+       xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+
+       act = XkbKeyActionPtr(xkb, numlock_keycode, state);
+       if (act == NULL)
+               return false;
+       if (act->type != XkbSA_LockMods)
+               return false;
+
+       if (act->mods.flags & XkbSA_UseModMapMods)
+               numlock_mask = xkb->map->modmap[keycode];
+       else
+               numlock_mask = act->mods.mask;
+
+       group = XkbKeyEffectiveGroup(xkb, keycode, state);
+       type = XkbKeyKeyType(xkb, keycode, group);
+       if ((type->mods.mask & numlock_mask) == 0)
+               return false;
+
+       return true;
+}
+
 KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state)
 {
        DeviceIntPtr master;