File N_tigervnc_keyboard-layout-handling.patch of Package xorg-x11-Xvnc

Author: Michal Srb <msrb@novell.com>
Subject: Handle keyboard layouts same as tightvnc.
Patch-Mainline: Never

This patch exchanges the core part of input handling of tigervnc with code from tightvnc with Matthias Hopf's patches.


--- a/hw/vnc/Input.cc	2012-08-29 10:56:37.000000000 +0200
+++ b/hw/vnc/Input.cc	2012-12-07 16:11:08.000000000 +0100
@@ -25,6 +25,7 @@
 #include "Input.h"
 #include "xorg-version.h"
 #include "vncExtInit.h"
+#include "keyboard.h"
 
 extern "C" {
 #define public c_public
@@ -76,8 +77,6 @@
 static int pointerProc(DeviceIntPtr pDevice, int onoff);
 
 static int keyboardProc(DeviceIntPtr pDevice, int onoff);
-static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col);
-static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col);
 
 /* Event queue is shared between all devices. */
 #if XORG == 15
@@ -338,188 +337,6 @@
 	((keyc)->down[(keycode) >> 3] & (1 << ((keycode) & 7)))
 
 /*
- * ModifierState is a class which helps simplify generating a "fake" press or
- * release of shift, ctrl, alt, etc.  An instance of the class is created for
- * every modifier which may need to be pressed or released.  Then either
- * press() or release() may be called to make sure that the corresponding keys
- * are in the right state.  The destructor of the class automatically reverts
- * to the previous state.  Each modifier may have multiple keys associated with
- * it, so in the case of a fake release, this may involve releasing more than
- * one key.
- */
-
-class ModifierState {
-public:
-	ModifierState(DeviceIntPtr _dev, int _modIndex)
-		: modIndex(_modIndex), nKeys(0), keys(0), pressed(false),
-		  dev(_dev) {}
-
-	~ModifierState()
-	{
-		for (int i = 0; i < nKeys; i++)
-			pressKey(dev, keys[i], !pressed, "fake keycode");
-		delete [] keys;
-	}
-
-	void press()
-	{
-		int state, maxKeysPerMod, keycode;
-#if XORG >= 17
-		KeyCode *modmap = NULL;
-#if XORG >= 111
-		state = XkbStateFieldFromRec(&dev->master->key->xkbInfo->state);
-#else /* XORG >= 111 */
-		state = XkbStateFieldFromRec(&dev->u.master->key->xkbInfo->state);
-#endif /* XORG >= 111 */
-#else
-		KeyClassPtr keyc = dev->key;
-		state = keyc->state;
-#endif
-		if ((state & (1 << modIndex)) != 0)
-			return;
-
-#if XORG >= 17
-		if (generate_modkeymap(serverClient, dev, &modmap,
-				       &maxKeysPerMod) != Success) {
-			vlog.error("generate_modkeymap failed");
-			return;
-		}
-
-		if (maxKeysPerMod == 0) {
-			vlog.debug("Keyboard has no modifiers");
-			xfree(modmap);
-			return;
-		}
-
-		keycode = modmap[modIndex * maxKeysPerMod];
-		xfree(modmap);
-#else
-		maxKeysPerMod = keyc->maxKeysPerModifier;
-		keycode = keyc->modifierKeyMap[modIndex * maxKeysPerMod];
-#endif
-		tempKeyEvent(keycode, true, maxKeysPerMod);
-		pressed = true;
-	}
-
-	void release()
-	{
-		int state, maxKeysPerMod;
-		KeyClassPtr keyc;
-#if XORG >= 17
-		KeyCode *modmap = NULL;
-
-#if XORG >= 111
-		keyc = dev->master->key;
-#else /* XORG >= 111 */
-		keyc = dev->u.master->key;
-#endif /* XORG >= 111 */
-		state = XkbStateFieldFromRec(&keyc->xkbInfo->state);
-#else
-		keyc = dev->key;
-		state = keyc->state;
-#endif
-		if ((state & (1 << modIndex)) == 0)
-			return;
-
-#if XORG >= 17
-		if (generate_modkeymap(serverClient, dev, &modmap,
-				       &maxKeysPerMod) != Success) {
-			vlog.error("generate_modkeymap failed");
-			return;
-		}
-
-		if (maxKeysPerMod == 0) {
-			vlog.debug("Keyboard has no modifiers");
-			xfree(modmap);
-			return;
-		}
-#else
-		maxKeysPerMod = keyc->maxKeysPerModifier;
-#endif
-
-		for (int k = 0; k < maxKeysPerMod; k++) {
-			int keycode;
-			int index = modIndex * maxKeysPerMod + k;
-#if XORG >= 17
-			keycode = modmap[index];
-#else
-			keycode = keyc->modifierKeyMap[index];
-#endif
-			if (keycode && IS_PRESSED(keyc, keycode))
-				tempKeyEvent(keycode, false, maxKeysPerMod);
-		}
-#if XORG >= 17
-		xfree(modmap);
-#endif
-	}
-
-private:
-	void tempKeyEvent(int keycode, bool down, int maxKeysPerMod)
-	{
-		if (keycode) {
-			if (!keys) keys = new int[maxKeysPerMod];
-			keys[nKeys++] = keycode;
-			pressKey(dev, keycode, down, "fake keycode");
-		}
-	}
-
-	int modIndex;
-	int nKeys;
-	int *keys;
-	bool pressed;
-	DeviceIntPtr dev;
-};
-
-
-/* altKeysym is a table of alternative keysyms which have the same meaning. */
-
-static struct altKeysym_t {
-	KeySym a, b;
-} altKeysym[] = {
-	{ XK_Shift_L,		XK_Shift_R },
-	{ XK_Control_L,		XK_Control_R },
-	{ XK_Meta_L,		XK_Meta_R },
-	{ XK_Alt_L,		XK_Alt_R },
-	{ XK_Super_L,		XK_Super_R },
-	{ XK_Hyper_L,		XK_Hyper_R },
-	{ XK_KP_Space,		XK_space },
-	{ XK_KP_Tab,		XK_Tab },
-	{ XK_KP_Enter,		XK_Return },
-	{ XK_KP_F1,		XK_F1 },
-	{ XK_KP_F2,		XK_F2 },
-	{ XK_KP_F3,		XK_F3 },
-	{ XK_KP_F4,		XK_F4 },
-	{ XK_KP_Home,		XK_Home },
-	{ XK_KP_Left,		XK_Left },
-	{ XK_KP_Up,		XK_Up },
-	{ XK_KP_Right,		XK_Right },
-	{ XK_KP_Down,		XK_Down },
-	{ XK_KP_Page_Up,	XK_Page_Up },
-	{ XK_KP_Page_Down,	XK_Page_Down },
-	{ XK_KP_End,		XK_End },
-	{ XK_KP_Begin,		XK_Begin },
-	{ XK_KP_Insert,		XK_Insert },
-	{ XK_KP_Delete,		XK_Delete },
-	{ XK_KP_Equal,		XK_equal },
-	{ XK_KP_Multiply,	XK_asterisk },
-	{ XK_KP_Add,		XK_plus },
-	{ XK_KP_Separator,	XK_comma },
-	{ XK_KP_Subtract,	XK_minus },
-	{ XK_KP_Decimal,	XK_period },
-	{ XK_KP_Divide,		XK_slash },
-	{ XK_KP_0,		XK_0 },
-	{ XK_KP_1,		XK_1 },
-	{ XK_KP_2,		XK_2 },
-	{ XK_KP_3,		XK_3 },
-	{ XK_KP_4,		XK_4 },
-	{ XK_KP_5,		XK_5 },
-	{ XK_KP_6,		XK_6 },
-	{ XK_KP_7,		XK_7 },
-	{ XK_KP_8,		XK_8 },
-	{ XK_KP_9,		XK_9 },
-};
-
-/*
  * keyEvent() - work out the best keycode corresponding to the keysym sent by
  * the viewer.  This is non-trivial because we can't assume much about the
  * local keyboard layout.  We must also find out which column of the keyboard
@@ -595,19 +412,155 @@
 }
 #endif
 
+static void vncXConvertCase(KeySym sym, KeySym *lower, KeySym *upper)
+{
+    *lower = sym;
+    *upper = sym;
+    switch(sym >> 8) {
+    case 0: /* Latin 1 */
+        if ((sym >= XK_A) && (sym <= XK_Z))
+            *lower += (XK_a - XK_A);
+        else if ((sym >= XK_a) && (sym <= XK_z))
+            *upper -= (XK_a - XK_A);
+        else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
+            *lower += (XK_agrave - XK_Agrave);
+        else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
+            *upper -= (XK_agrave - XK_Agrave);
+        else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
+            *lower += (XK_oslash - XK_Ooblique);
+        else if ((sym >= XK_oslash) && (sym <= XK_thorn))
+            *upper -= (XK_oslash - XK_Ooblique);
+        break;
+    case 1: /* Latin 2 */
+        /* Assume the KeySym is a legal value (ignore discontinuities) */
+        if (sym == XK_Aogonek)
+            *lower = XK_aogonek;
+        else if (sym >= XK_Lstroke && sym <= XK_Sacute)
+            *lower += (XK_lstroke - XK_Lstroke);
+        else if (sym >= XK_Scaron && sym <= XK_Zacute)
+            *lower += (XK_scaron - XK_Scaron);
+        else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
+            *lower += (XK_zcaron - XK_Zcaron);
+        else if (sym == XK_aogonek)
+            *upper = XK_Aogonek;
+        else if (sym >= XK_lstroke && sym <= XK_sacute)
+            *upper -= (XK_lstroke - XK_Lstroke);
+        else if (sym >= XK_scaron && sym <= XK_zacute)
+            *upper -= (XK_scaron - XK_Scaron);
+        else if (sym >= XK_zcaron && sym <= XK_zabovedot)
+            *upper -= (XK_zcaron - XK_Zcaron);
+        else if (sym >= XK_Racute && sym <= XK_Tcedilla)
+            *lower += (XK_racute - XK_Racute);
+        else if (sym >= XK_racute && sym <= XK_tcedilla)
+            *upper -= (XK_racute - XK_Racute);
+        break;
+    case 2: /* Latin 3 */
+        /* Assume the KeySym is a legal value (ignore discontinuities) */
+        if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
+            *lower += (XK_hstroke - XK_Hstroke);
+        else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
+            *lower += (XK_gbreve - XK_Gbreve);
+        else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
+            *upper -= (XK_hstroke - XK_Hstroke);
+        else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
+            *upper -= (XK_gbreve - XK_Gbreve);
+        else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
+            *lower += (XK_cabovedot - XK_Cabovedot);
+        else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
+            *upper -= (XK_cabovedot - XK_Cabovedot);
+        break;
+    case 3: /* Latin 4 */
+        /* Assume the KeySym is a legal value (ignore discontinuities) */
+        if (sym >= XK_Rcedilla && sym <= XK_Tslash)
+            *lower += (XK_rcedilla - XK_Rcedilla);
+        else if (sym >= XK_rcedilla && sym <= XK_tslash)
+            *upper -= (XK_rcedilla - XK_Rcedilla);
+        else if (sym == XK_ENG)
+            *lower = XK_eng;
+        else if (sym == XK_eng)
+            *upper = XK_ENG;
+        else if (sym >= XK_Amacron && sym <= XK_Umacron)
+            *lower += (XK_amacron - XK_Amacron);
+        else if (sym >= XK_amacron && sym <= XK_umacron)
+            *upper -= (XK_amacron - XK_Amacron);
+        break;
+    case 6: /* Cyrillic */
+        /* Assume the KeySym is a legal value (ignore discontinuities) */
+        if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
+            *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
+        else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
+            *upper += (XK_Serbian_DJE - XK_Serbian_dje);
+        else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
+            *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
+        else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
+            *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
+        break;
+    case 7: /* Greek */
+        /* Assume the KeySym is a legal value (ignore discontinuities) */
+        if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
+            *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+        else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
+                 sym != XK_Greek_iotaaccentdieresis &&
+                 sym != XK_Greek_upsilonaccentdieresis)
+            *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+        else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
+            *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
+        else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
+                 sym != XK_Greek_finalsmallsigma)
+            *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
+        break;
+    }
+}
+
+
+/* In-server and highly changed version of XkbKeycodeToKeysym */
+static KeySym
+_XkbKeycodeToKeysym(XkbDescPtr xkb, KeyCode kc, int group, int level)
+{
+    KeySym ks;
+
+    if ((kc<xkb->min_key_code)||(kc>xkb->max_key_code))
+        return NoSymbol;
+    /* Treat single group elements as present in all groups */
+    if (XkbKeyNumGroups (xkb,kc) == 1)
+        group = 0;
+    if ((group<0)||(level<0)||(group>=XkbKeyNumGroups(xkb,kc)))
+        return NoSymbol;
+    if (level < XkbKeyGroupWidth(xkb, kc, group))
+        ks = XkbKeySymEntry(xkb, kc, level, group);
+    else
+        ks = NoSymbol;
+    /* Treat 'K' as 'K K', */
+    if (ks == NoSymbol && (level & 1) && level-1 < XkbKeyGroupWidth(xkb, kc, group))
+        ks = XkbKeySymEntry(xkb, kc, level-1, group);
+    return ks;
+}
+
 void InputDevice::keyEvent(rdr::U32 keysym, bool down)
 {
+	XkbSrvInfoPtr xkbInfo;
+	int group, level;
+	int keyCode = 0;
+	Bool fakeShiftPress = FALSE;
+	Bool fakeShiftLRelease = FALSE;
+	Bool fakeShiftRRelease = FALSE;
+	Bool shiftMustBeReleased = FALSE;
+	Bool shiftMustBePressed = FALSE;
+	Bool fakeLevel3Press = FALSE;
+	Bool fakeLevel3Release = FALSE;
+	Bool level3MustBeReleased = FALSE;
+	Bool level3MustBePressed = FALSE;
 #if XORG < 17
 	DeviceIntPtr master;
 #endif
 	KeyClassPtr keyc;
 	KeySymsPtr keymap = NULL;
 	KeySym *map = NULL;
-	KeyCode minKeyCode, maxKeyCode;
+	KeyCode minKeyCode;
 	KeyCode *modmap = NULL;
 	int mapWidth;
 	unsigned int i;
-	int j, k, state, maxKeysPerMod;
+	int j, k, maxKeysPerMod;
 #if XORG >= 17
 	KeybdCtrl ctrl;
 #endif
@@ -650,18 +603,14 @@
 
 	if (maxKeysPerMod == 0)
 		vlog.debug("Keyboard has no modifiers");
-
-	state = XkbStateFieldFromRec(&keyc->xkbInfo->state);
 #else
 	keyc = keyboardDev->key;
-	state = keyc->state;
 	maxKeysPerMod = keyc->maxKeysPerModifier;
 	keymap = &keyc->curKeySyms;
 	modmap = keyc->modifierKeyMap;
 #endif
 	map = keymap->map;
 	minKeyCode = keymap->minKeyCode;
-	maxKeyCode = keymap->maxKeyCode;
 	mapWidth = keymap->mapWidth;
 
 #if XORG >= 17
@@ -677,7 +626,7 @@
 #endif
 
 	/* find which modifier Mode_switch is on. */
-	int modeSwitchMapIndex = 0;
+	int modeSwitchKeyCode = 0;
 	for (i = 3; i < 8; i++) {
 		for (k = 0; k < maxKeysPerMod; k++) {
 			int index = i * maxKeysPerMod + k;
@@ -689,7 +638,7 @@
 			for (j = 0; j < mapWidth; j++) {
 				if (map[(keycode - minKeyCode) * mapWidth + j]
 				    == XK_Mode_switch) {
-					modeSwitchMapIndex = i;
+					modeSwitchKeyCode = modmap[i * maxKeysPerMod];
 					goto ModeSwitchFound;
 				}
 			}
@@ -698,9 +647,7 @@
 ModeSwitchFound:
 
 	int kc;
-	int col = 0;
 
-#if XORG >= 17
 	if ((kc = isModifier(keymap, modmap, maxKeysPerMod, keysym)) != -1) {
 		/*
 		 * It is a modifier key event.
@@ -712,241 +659,174 @@
 			FREE_MAPS;
 			return;
 		}
-
-		goto press;
 	}
-#endif
 
-	if (maxKeysPerMod != 0) {
-		if ((state & (1 << ShiftMapIndex)) != 0)
-			col |= 1;
-		if (modeSwitchMapIndex != 0 &&
-		    ((state & (1 << modeSwitchMapIndex))) != 0)
-			col |= 2;
+	/* Incomplete maps may create NoSymbol - which lets us
+	* select and/or overwrite otherwise valid entries.
+	* E.g Level3+a in serbian layout creates NoSymbol on os11.4
+	* 2011-05-24 mhopf@suse.de */
+	if (keysym == NoSymbol) {
+	    ErrorF("KbdAddEvent: ignoring illegal NoSymbol\n");
+	    return;
+	}
+
+	xkbInfo = inputInfo.keyboard->key->xkbInfo;
+	group   = xkbInfo->state.group;
+	level   = (IS_PRESSED(inputInfo.keyboard->key, ISO_LEVEL3_KEY_CODE) ? 2 : 0) |
+		  (XkbStateFieldFromRec(&xkbInfo->state) & ShiftMask ? 1 : 0);
+#ifdef DEBUG
+	ErrorF ("VNCkbd:\t%s Sym %04x\n", down ? "+":"-", (int)keysym);
+#endif
+	for (keyCode = MIN_KEY_CODE; keyCode < MIN_KEY_CODE + NO_OF_KEYS; keyCode++) {
+		/* Check whether keysym is reachable in current group
+		* by any shift/Level3_shift state (preferrable w/o change).
+		* This doesn't do real modifyer analysis, only Shift and Level3_Shift.
+		* 2011-05-23 mhopf@suse.de */
+		if (_XkbKeycodeToKeysym(xkbInfo->desc, keyCode, group, level) == keysym)
+			break;
+		if (_XkbKeycodeToKeysym(xkbInfo->desc, keyCode, group, level ^ 2) == keysym) {
+			if (level & 2)
+				level3MustBeReleased = TRUE;
+			else
+				level3MustBePressed = TRUE;
+			break;
+		}
+		if (_XkbKeycodeToKeysym(xkbInfo->desc, keyCode, group, level ^ 1) == keysym) {
+			if (level & 1)
+				shiftMustBeReleased = TRUE;
+			else
+				shiftMustBePressed = TRUE;
+			break;
+		}
+		if (_XkbKeycodeToKeysym(xkbInfo->desc, keyCode, group, level ^ 3) == keysym) {
+			if (level & 2)
+				level3MustBeReleased = TRUE;
+			else
+				level3MustBePressed = TRUE;
+			if (level & 1)
+				shiftMustBeReleased = TRUE;
+			else
+				shiftMustBePressed = TRUE;
+			break;
+		}
 	}
+	if (keyCode == MIN_KEY_CODE + NO_OF_KEYS)
+		keyCode = 0;
 
-	kc = KeysymToKeycode(keymap, keysym, &col);
-
-	/*
-	 * Sort out the "shifted Tab" mess.  If we are sent a shifted Tab,
-	 * generate a local shifted Tab regardless of what the "shifted Tab"
-	 * keysym is on the local keyboard (it might be Tab, ISO_Left_Tab or
-	 * HP's private BackTab keysym, and quite possibly some others too).
-	 * We never get ISO_Left_Tab here because it's already been translated
-	 * in VNCSConnectionST.
-	 */
-	if (maxKeysPerMod != 0 && keysym == XK_Tab &&
-	    ((state & (1 << ShiftMapIndex))) != 0)
-		col |= 1;
-
-	if (kc == 0) {
-		/*
-		 * Not a direct match in the local keyboard mapping.  Check for
-		 * alternative keysyms with the same meaning.
-		 */
-		for (i = 0; i < sizeof(altKeysym) / sizeof(altKeysym_t); i++) {
-			if (keysym == altKeysym[i].a)
-				kc = KeysymToKeycode(keymap, altKeysym[i].b,
-						     &col);
-			else if (keysym == altKeysym[i].b)
-				kc = KeysymToKeycode(keymap, altKeysym[i].a,
-						     &col);
-			if (kc)
+	if (!keyCode) {
+		KeySym lower, upper;
+		KeySymsPtr keySyms = XkbGetCoreMap(inputInfo.keyboard);
+
+		/* we don't have an existing keycode - make one up on the fly and add
+		  it to the keyboard mapping.  Thanks to Vlad Harchev for pointing
+		  out problems with non-ascii capitalisation. */
+
+		/* Find free index for current group. */
+		for (keyCode = MIN_KEY_CODE; keyCode < MIN_KEY_CODE + NO_OF_KEYS; keyCode++) {
+			/* A keyCode is free if no groups are assigned at all */
+			if (XkbKeyNumGroups(xkbInfo->desc, keyCode) == 0)
 				break;
 		}
-	}
 
-	if (kc == 0) {
-		/* Dynamically add a new key to the keyboard mapping. */
-		for (kc = maxKeyCode; kc >= minKeyCode; kc--) {
-			if (map[(kc - minKeyCode) * mapWidth] != 0)
-				continue;
-
-			map[(kc - minKeyCode) * mapWidth] = keysym;
-			col = 0;
+		if (keyCode == MIN_KEY_CODE + NO_OF_KEYS) {
+			ErrorF("KbdAddEvent: ignoring KeySym 0x%x - no free KeyCodes\n",
+			      (int)keysym);
+			free (keySyms->map);
+			free (keySyms);
+			return;
+		}
 
-			vlog.info("Added unknown keysym 0x%x to keycode %d",
-				  keysym, kc);
+		vncXConvertCase(keysym, &lower, &upper);
 
-#if XORG < 17
-#if XORG == 15
-			master = inputInfo.keyboard;
-#else
-			master = keyboardDev->u.master;
-#endif
-			void *slave = dixLookupPrivate(&master->devPrivates,
-						       CoreDevicePrivateKey);
-			if (keyboardDev == slave) {
-				dixSetPrivate(&master->devPrivates,
-					      CoreDevicePrivateKey, NULL);
-#if XORG == 15
-				SwitchCoreKeyboard(keyboardDev);
-#else
-				CopyKeyClass(keyboardDev, master);
-#endif
+		/* Generic layouts needs to set the full map width.
+		* Weird enough, mapWidth seems too big...
+		* 2011-05-23 mhopf@suse.de */
+		for (i = 0; i < (keySyms->mapWidth & ~1); i += 2) {
+			if (lower == upper) {
+				keySyms->map[(keyCode - MIN_KEY_CODE) * keySyms->mapWidth + i]     = keysym;
+				keySyms->map[(keyCode - MIN_KEY_CODE) * keySyms->mapWidth + i + 1] = NoSymbol;
+			} else {
+				keySyms->map[(keyCode - MIN_KEY_CODE) * keySyms->mapWidth + i]     = lower;
+				keySyms->map[(keyCode - MIN_KEY_CODE) * keySyms->mapWidth + i + 1] = upper;
 			}
-#else /* XORG < 17 */
-			XkbApplyMappingChange(keyboardDev, keymap, minKeyCode,
-					      maxKeyCode - minKeyCode + 1,
-					      NULL, serverClient);
-#if XORG >= 111
-			XkbCopyDeviceKeymap(keyboardDev->master, keyboardDev);
-#else
-			XkbCopyDeviceKeymap(keyboardDev->u.master, keyboardDev);
-#endif
-#endif /* XORG < 17 */
-			break;
 		}
-	}
+		if (lower != upper) {
+			if (keysym == lower)
+				shiftMustBeReleased = TRUE;
+			else
+				shiftMustBePressed = TRUE;
+		}
+		level3MustBeReleased = TRUE;
 
-	if (kc < minKeyCode) {
-		vlog.info("Keyboard mapping full - ignoring unknown keysym "
-			  "0x%x",keysym);
-		FREE_MAPS;
-		return;
-	}
+		XkbApplyMappingChange(inputInfo.keyboard, keySyms, keyCode, 1, NULL, serverClient);
 
-#if XORG < 17
-	/*
-	 * See if it's a modifier key.  If so, then don't do any auto-repeat,
-	 * because the X server will translate each press into a release
-	 * followed by a press.
-	 */
-	for (i = 0; i < 8; i++) {
-		for (k = 0; k < maxKeysPerMod; k++) {
-			int index = i * maxKeysPerMod + k;
-			if (kc == modmap[index] && IS_PRESSED(keyc,kc) && down) {
-				FREE_MAPS;
-				return;
-			}	
-		}
-	}
-#else
-	/*
-	 * If you would like to press a key which is already pressed then
-	 * viewer didn't send the "release" event. In this case release it
-	 * before the press.
-	 */
-	if (IS_PRESSED(keyc, kc) && down) {
-		vlog.debug("KeyRelease for %d wasn't sent, releasing", kc);
-		pressKey(keyboardDev, kc, false, "fixing keycode");
+		ErrorF("KbdAddEvent: unknown KeySym 0x%x - allocating KeyCode %d\n",
+		      (int)keysym, keyCode);
+		free (keySyms->map);
+		free (keySyms);
 	}
+
+#ifdef DEBUG
+	ErrorF ("\t%s Sym %04x Code%3d\tState x%02x %s%s%s\tSh %s%s\tL3 %s%s\n",
+		down ? "+":"-", (int)keysym, keyCode, XkbStateFieldFromRec(&xkbInfo->state),
+		IS_PRESSED(inputInfo.keyboard->key, SHIFT_L_KEY_CODE) ? "Sl":"",
+		IS_PRESSED(inputInfo.keyboard->key, SHIFT_R_KEY_CODE) ? "Sr":"",
+		IS_PRESSED(inputInfo.keyboard->key, ISO_LEVEL3_KEY_CODE) ? "L3":"",
+		shiftMustBePressed ? "+":"", shiftMustBeReleased ? "-":"",
+		level3MustBePressed ? "+":"", level3MustBeReleased ? "-":"");
 #endif
 
-	if (maxKeysPerMod != 0) {
-		ModifierState shift(keyboardDev, ShiftMapIndex);
-		ModifierState modeSwitch(keyboardDev, modeSwitchMapIndex);
-		if (down) {
-			if (col & 1)
-				shift.press();
-			else
-				shift.release();
-			if (modeSwitchMapIndex) {
-				if (col & 2)
-					modeSwitch.press();
-				else
-					modeSwitch.release();
+	if (down) {
+		if (level3MustBePressed && !(level & 2)) {
+			fakeLevel3Press = TRUE;
+			pressKey(inputInfo.keyboard, modeSwitchKeyCode, true, "keycode");
+		}
+		if (level3MustBeReleased && (level & 2)) {
+			fakeLevel3Release = TRUE;
+			pressKey(inputInfo.keyboard, modeSwitchKeyCode, false, "keycode");
+		}
+		if (shiftMustBePressed && !(level & 1)) {
+			fakeShiftPress = TRUE;
+			pressKey(inputInfo.keyboard, SHIFT_L_KEY_CODE, true, "keycode");
+		}
+		if (shiftMustBeReleased && (level & 1)) {
+			if (IS_PRESSED(inputInfo.keyboard->key, SHIFT_L_KEY_CODE)) {
+				fakeShiftLRelease = TRUE;
+				pressKey(inputInfo.keyboard, SHIFT_L_KEY_CODE, false, "keycode");
+			}
+			if (IS_PRESSED(inputInfo.keyboard->key, SHIFT_R_KEY_CODE)) {
+				fakeShiftRRelease = TRUE;
+				pressKey(inputInfo.keyboard, SHIFT_R_KEY_CODE, false, "keycode");
 			}
 		}
-		/*
-		 * Ensure ModifierState objects are not destroyed before
-		 * pressKey call, otherwise fake modifier keypress can be lost.
-		 */
-		pressKey(keyboardDev, kc, down, "keycode");
-	} else {
-press:
-		pressKey(keyboardDev, kc, down, "keycode");
 	}
 
+	pressKey(inputInfo.keyboard, keyCode, down, "keycode");
 
-        FREE_MAPS;
-	
-	/*
-	 * When faking a modifier we are putting a keycode (which can
-	 * currently activate the desired modifier) on the input
-	 * queue. A future modmap change can change the mapping so
-	 * that this keycode means something else entirely. Guard
-	 * against this by processing the queue now.
-	 */
-	mieqProcessInputEvents();
-}
-
-static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col)
-{
-	int per = keymap->mapWidth;
-	KeySym *syms;
-	KeySym lsym, usym;
-
-	if ((col < 0) || ((col >= per) && (col > 3)) ||
-	    (keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode))
-		return NoSymbol;
-
-	syms = &keymap->map[(keycode - keymap->minKeyCode) * per];
-	if (col >= 4)
-		return syms[col];
-
-	if (col > 1) {
-		while ((per > 2) && (syms[per - 1] == NoSymbol))
-			per--;
-		if (per < 3)
-			col -= 2;
-	}
-
-	if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) {
-		XkbConvertCase
-			    (syms[col&~1], &lsym, &usym);
-		if (!(col & 1))
-			return lsym;
-		/*
-		 * I'm commenting out this logic because it's incorrect even
-		 * though it was copied from the Xlib sources.  The X protocol
-		 * book quite clearly states that where a group consists of
-		 * element 1 being a non-alphabetic keysym and element 2 being
-		 * NoSymbol that you treat the second element as being the
-		 * same as the first.  This also tallies with the behaviour
-		 * produced by the installed Xlib on my linux box (I believe
-		 * this is because it uses some XKB code rather than the
-		 * original Xlib code - compare XKBBind.c with KeyBind.c in
-		 * lib/X11).
-		 */
-#if 0
-		else if (usym == lsym)
-			return NoSymbol;
-#endif
-		else
-			return usym;
+	if (fakeShiftPress) {
+		pressKey(inputInfo.keyboard, SHIFT_L_KEY_CODE, false, "keycode");
 	}
-
-	return syms[col];
-}
-
-/*
- * KeysymToKeycode() - find the keycode and column corresponding to the given
- * keysym.  The value of col passed in should be the column determined from the
- * current shift state.  If the keysym can be found in that column we prefer
- * that to finding it in a different column (which would require fake events to
- * alter the shift state).
- */
-static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col)
-{
-	int i, j;
-
-	j = *col;
-	for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) {
-		if (KeyCodetoKeySym(keymap, i, j) == ks)
-			return i;
+	if (fakeShiftLRelease) {
+		pressKey(inputInfo.keyboard, SHIFT_L_KEY_CODE, true, "keycode");
 	}
-
-	for (j = 0; j < keymap->mapWidth; j++) {
-		for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) {
-			if (KeyCodetoKeySym(keymap, i, j) == ks) {
-				*col = j;
-				return i;
-			}
-		}
+	if (fakeShiftRRelease) {
+		pressKey(inputInfo.keyboard, SHIFT_R_KEY_CODE, true, "keycode");
+	}
+	if (fakeLevel3Press) {
+		pressKey(inputInfo.keyboard, modeSwitchKeyCode, false, "keycode");
+	}
+	if (fakeLevel3Release) {
+		pressKey(inputInfo.keyboard, modeSwitchKeyCode, true, "keycode");
 	}
 
-	return 0;
+	/*
+	* When faking a modifier we are putting a keycode (which can
+	* currently activate the desired modifier) on the input
+	* queue. A future modmap change can change the mapping so
+	* that this keycode means something else entirely. Guard
+	* against this by processing the queue now.
+	*/
+	mieqProcessInputEvents();
 }
 
 #if XORG < 17
--- /dev/null	2012-11-14 14:33:23.674578655 +0100
+++ b/hw/vnc/keyboard.h	2012-11-09 17:06:22.000000000 +0100
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (C) 2002 Alan Hourihane.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ *
+ *  Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
+ */
+
+#define MIN_KEY_CODE		8
+#define MAX_KEY_CODE		255
+#define NO_OF_KEYS		(MAX_KEY_CODE - MIN_KEY_CODE + 1)
+#define GLYPHS_PER_KEY		4
+
+#define CONTROL_L_KEY_CODE	(MIN_KEY_CODE + 29)
+#define CONTROL_R_KEY_CODE	(MIN_KEY_CODE + 101)
+#define SHIFT_L_KEY_CODE	(MIN_KEY_CODE + 42)
+#define SHIFT_R_KEY_CODE	(MIN_KEY_CODE + 54)
+#define META_L_KEY_CODE		(MIN_KEY_CODE + 107)
+#define META_R_KEY_CODE		(MIN_KEY_CODE + 108)
+#define ALT_L_KEY_CODE		(MIN_KEY_CODE + 56)
+#define ALT_R_KEY_CODE		(MIN_KEY_CODE + 105)
+#define ISO_LEVEL3_KEY_CODE    ALT_R_KEY_CODE
openSUSE Build Service is sponsored by