]> source.dussan.org Git - tigervnc.git/commitdiff
Copy r5117 through r5119 from trunk.
authorPierre Ossman <ossman@cendio.se>
Thu, 30 May 2013 14:53:40 +0000 (14:53 +0000)
committerPierre Ossman <ossman@cendio.se>
Thu, 30 May 2013 14:53:40 +0000 (14:53 +0000)
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/branches/1_3@5120 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 5f96f3804b72d6ce2c68f94370e4a39ba8ec42de..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. */
@@ -475,18 +477,18 @@ void InputDevice::keyEvent(rdr::U32 keysym, bool down)
        /* Try some equivalent keysyms if we couldn't find a perfect match */
        if (keycode == 0) {
                for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) {
-                       if (altKeysym[i].a == keysym) {
-                               keycode = keysymToKeycode(altKeysym[i].b,
-                                                         state, &new_state);
-                               if (keycode != 0)
-                                       break;
-                       }
-                       if (altKeysym[i].b == keysym) {
-                               keycode = keysymToKeycode(altKeysym[i].a,
-                                                         state, &new_state);
-                               if (keycode != 0)
-                                       break;
-                       }
+                       KeySym altsym;
+
+                       if (altKeysym[i].a == keysym)
+                               altsym = altKeysym[i].b;
+                       else if (altKeysym[i].b == keysym)
+                               altsym = altKeysym[i].a;
+                       else
+                               continue;
+
+                       keycode = keysymToKeycode(altsym, state, &new_state);
+                       if (keycode != 0)
+                               break;
                }
        }
 
@@ -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 7bc23778146078b234a81f221e8befb1c0217902..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
@@ -210,20 +240,25 @@ unsigned InputDevice::getKeyboardState(void)
 
 unsigned InputDevice::getLevelThreeMask(void)
 {
+       unsigned state;
        KeyCode keycode;
        XkbDescPtr xkb;
        XkbAction *act;
 
-       keycode = keysymToKeycode(XK_ISO_Level3_Shift, 0, NULL);
+       /* Group state is still important */
+       state = getKeyboardState();
+       state &= ~0xff;
+
+       keycode = keysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
        if (keycode == 0) {
-               keycode = keysymToKeycode(XK_Mode_switch, 0, NULL);
+               keycode = keysymToKeycode(XK_Mode_switch, state, NULL);
                if (keycode == 0)
                        return 0;
        }
 
        xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
 
-       act = XkbKeyActionPtr(xkb, keycode, 0);
+       act = XkbKeyActionPtr(xkb, keycode, state);
        if (act == NULL)
                return 0;
        if (act->type != XkbSA_SetMods)
@@ -338,7 +373,7 @@ KeyCode InputDevice::pressLevelThree(void)
 
        xkb = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
 
-       act = XkbKeyActionPtr(xkb, keycode, 0);
+       act = XkbKeyActionPtr(xkb, keycode, state);
        if (act == NULL)
                return 0;
        if (act->type != XkbSA_SetMods)
@@ -474,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;