aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2013-05-30 14:53:40 +0000
committerPierre Ossman <ossman@cendio.se>2013-05-30 14:53:40 +0000
commit54df2733b61acc19b315459260cfb0564da0a151 (patch)
tree9fdb545fe3815905554340088b165e35041ae497
parent6608411c08b2c9589f7ec6e7e4a03273d3cba636 (diff)
downloadtigervnc-54df2733b61acc19b315459260cfb0564da0a151.tar.gz
tigervnc-54df2733b61acc19b315459260cfb0564da0a151.zip
Copy r5117 through r5119 from trunk.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/branches/1_3@5120 3789f03b-4d11-0410-bbf8-ca57d06f2519
-rw-r--r--unix/xserver/hw/vnc/Input.cc73
-rw-r--r--unix/xserver/hw/vnc/Input.h2
-rw-r--r--unix/xserver/hw/vnc/InputCore.cc20
-rw-r--r--unix/xserver/hw/vnc/InputXKB.cc90
4 files changed, 169 insertions, 16 deletions
diff --git a/unix/xserver/hw/vnc/Input.cc b/unix/xserver/hw/vnc/Input.cc
index 5f96f380..a6a51d7f 100644
--- a/unix/xserver/hw/vnc/Input.cc
+++ b/unix/xserver/hw/vnc/Input.cc
@@ -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;
}
}
@@ -520,6 +522,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
* should always send the plain XK_Tab keysym and the server
diff --git a/unix/xserver/hw/vnc/Input.h b/unix/xserver/hw/vnc/Input.h
index 3a0e9039..e893049e 100644
--- a/unix/xserver/hw/vnc/Input.h
+++ b/unix/xserver/hw/vnc/Input.h
@@ -91,6 +91,8 @@ private:
bool isLockModifier(KeyCode keycode, unsigned state);
+ bool isAffectedByNumLock(KeyCode keycode);
+
KeyCode addKeysym(KeySym keysym, unsigned state);
private:
diff --git a/unix/xserver/hw/vnc/InputCore.cc b/unix/xserver/hw/vnc/InputCore.cc
index de7653ef..a880ca07 100644
--- a/unix/xserver/hw/vnc/InputCore.cc
+++ b/unix/xserver/hw/vnc/InputCore.cc
@@ -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;
diff --git a/unix/xserver/hw/vnc/InputXKB.cc b/unix/xserver/hw/vnc/InputXKB.cc
index 7bc23778..ed93afcc 100644
--- a/unix/xserver/hw/vnc/InputXKB.cc
+++ b/unix/xserver/hw/vnc/InputXKB.cc
@@ -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;