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. */
/* 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;
}
}
}
}
+ /*
+ * 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
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
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)
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)
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;