[Bugfix] Handle situation when keyboard has no modifiers in Input.cc well.


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4225 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/unix/xserver/hw/vnc/Input.cc b/unix/xserver/hw/vnc/Input.cc
index c0e28bc..87151d9 100644
--- a/unix/xserver/hw/vnc/Input.cc
+++ b/unix/xserver/hw/vnc/Input.cc
@@ -296,6 +296,19 @@
 #endif
 }
 
+static inline void pressKey(DeviceIntPtr dev, int kc, bool down, const char *msg)
+{
+	int action;
+	unsigned int n;
+
+	if (msg != NULL)
+		vlog.debug("%s %d %s", msg, kc, down ? "down" : "up");
+
+	action = down ? KeyPress : KeyRelease;
+	n = GetKeyboardEvents(eventq, dev, action, kc);
+	enqueueEvents(dev, n);
+}
+
 #define IS_PRESSED(keyc, keycode) \
 	((keyc)->down[(keycode) >> 3] & (1 << ((keycode) & 7)))
 
@@ -319,7 +332,7 @@
 	~ModifierState()
 	{
 		for (int i = 0; i < nKeys; i++)
-			generateXKeyEvent(keys[i], !pressed);
+			pressKey(dev, keys[i], !pressed, "fake keycode");
 		delete [] keys;
 	}
 
@@ -344,6 +357,12 @@
 			return;
 		}
 
+		if (maxKeysPerMod == 0) {
+			vlog.debug("Keyboard has no modifiers");
+			xfree(modmap);
+			return;
+		}
+
 		keycode = modmap[modIndex * maxKeysPerMod];
 		xfree(modmap);
 #else
@@ -376,6 +395,12 @@
 			vlog.error("generate_modkeymap failed");
 			return;
 		}
+
+		if (maxKeysPerMod == 0) {
+			vlog.debug("Keyboard has no modifiers");
+			xfree(modmap);
+			return;
+		}
 #else
 		maxKeysPerMod = keyc->maxKeysPerModifier;
 #endif
@@ -402,22 +427,10 @@
 		if (keycode) {
 			if (!keys) keys = new int[maxKeysPerMod];
 			keys[nKeys++] = keycode;
-			generateXKeyEvent(keycode, down);
+			pressKey(dev, keycode, down, "fake keycode");
 		}
 	}
 
-	void generateXKeyEvent(int keycode, bool down)
-	{
-		int n, action;
-
-		action = down ? KeyPress : KeyRelease;
-		n = GetKeyboardEvents(eventq, dev, action, keycode);
-		enqueueEvents(dev, n);
-
-		vlog.debug("fake keycode %d %s", keycode,
-			   down ? "down" : "up");
-	}
-
 	int modIndex;
 	int nKeys;
 	int *keys;
@@ -518,8 +531,8 @@
 	KeyCode minKeyCode, maxKeyCode;
 	KeyCode *modmap = NULL;
 	int mapWidth;
-	unsigned int i, n;
-	int j, k, action, state, maxKeysPerMod;
+	unsigned int i;
+	int j, k, state, maxKeysPerMod;
 
 	initInputDevice();
 
@@ -553,6 +566,9 @@
 		return;
 	}
 
+	if (maxKeysPerMod == 0)
+		vlog.debug("Keyboard has no modifiers");
+
 	state = XkbStateFieldFromRec(&keyc->xkbInfo->state);
 #else
 	keyc = keyboardDev->key;
@@ -588,11 +604,13 @@
 ModeSwitchFound:
 
 	int col = 0;
-	if ((state & (1 << ShiftMapIndex)) != 0)
-		col |= 1;
-	if (modeSwitchMapIndex != 0 &&
-	    ((state & (1 << modeSwitchMapIndex))) != 0)
-		col |= 2;
+	if (maxKeysPerMod != 0) {
+		if ((state & (1 << ShiftMapIndex)) != 0)
+			col |= 1;
+		if (modeSwitchMapIndex != 0 &&
+		    ((state & (1 << modeSwitchMapIndex))) != 0)
+			col |= 2;
+	}
 
 	int kc = KeysymToKeycode(keymap, keysym, &col);
 
@@ -604,7 +622,8 @@
 	 * We never get ISO_Left_Tab here because it's already been translated
 	 * in VNCSConnectionST.
 	 */
-	if (keysym == XK_Tab && ((state & (1 << ShiftMapIndex))) != 0)
+	if (maxKeysPerMod != 0 && keysym == XK_Tab &&
+	    ((state & (1 << ShiftMapIndex))) != 0)
 		col |= 1;
 
 	if (kc == 0) {
@@ -685,25 +704,29 @@
 		}
 	}
 
-	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();
+	if (maxKeysPerMod != 0) {
+		ModifierState shift(keyboardDev, ShiftMapIndex);
+		ModifierState modeSwitch(keyboardDev, modeSwitchMapIndex);
+		if (down) {
+			if (col & 1)
+				shift.press();
 			else
-				modeSwitch.release();
+				shift.release();
+			if (modeSwitchMapIndex) {
+				if (col & 2)
+					modeSwitch.press();
+				else
+					modeSwitch.release();
+			}
 		}
-	}
+		/*
+		 * Ensure ModifierState objects are not destroyed before
+		 * pressKey call, otherwise fake modifier keypress can be lost.
+		 */
+		pressKey(keyboardDev, kc, down, "keycode");
+	} else
+		pressKey(keyboardDev, kc, down, "keycode");
 
-	vlog.debug("keycode %d %s", kc, down ? "down" : "up");
-	action = down ? KeyPress : KeyRelease;
-	n = GetKeyboardEvents(eventq, keyboardDev, action, kc);
-	enqueueEvents(keyboardDev, n);
 
         FREE_MAPS;