--- server/vino-input.c.orig	2006-12-29 13:08:01.000000000 -0500
+++ server/vino-input.c	2006-12-29 10:05:41.000000000 -0500
@@ -116,6 +116,19 @@
  * use XkbWrapIntoRange, so XkbLatchGroup() works for us in that case,
  * so we just require that, and don't support multiple groups if the
  * layout uses XkbRedirectIntoRange or XkbClampIntoRange.
+ * 
+ * Two additional problems show up with Windows-based clients; first,
+ * Windows considers Alt-Gr to be equivalent to Control_L + Alt_R, so
+ * we have to translate that. Second, Windows clients never send
+ * events for dead keys. Instead, if you type a dead acute accent key
+ * followed by "e", it sends a single keypress event for XK_eacute.
+ * This works fine when the current keyboard layout has a key for that
+ * precomposed keysym, but if it doesn't, we need to decompose it back
+ * into multiple keypresses. There is no guarantee that the
+ * decompositions we use will actually work, but since compositions
+ * happen in the library, not the server, there is no way to find out
+ * 100% reliably what compositions are available to the window
+ * currently being typed into, so this is the best we can do.
  */
 
 #include <config.h>
@@ -144,10 +157,12 @@
 
 typedef enum
 {
-  VINO_LEFT_SHIFT  = 1 << 0,
-  VINO_RIGHT_SHIFT = 1 << 1,
-  VINO_ALT_GR      = 1 << 2,
-  VINO_NUM_LOCK    = 1 << 3,
+  VINO_LEFT_SHIFT    = 1 << 0,
+  VINO_RIGHT_SHIFT   = 1 << 1,
+  VINO_LEFT_CONTROL  = 1 << 2,
+  VINO_RIGHT_ALT     = 1 << 3,
+  VINO_ALT_GR        = 1 << 4,
+  VINO_NUM_LOCK      = 1 << 5
 } VinoModifierState;
 
 typedef enum
@@ -186,8 +201,10 @@
 #endif
 
   GHashTable        *keybindings;
+  GHashTable        *decompositions;
   KeyCode            left_shift_keycode;
   KeyCode            right_shift_keycode;
+  KeyCode            left_control_keycode;
   KeyCode            alt_gr_keycode;
   KeyCode            num_lock_keycode;
 
@@ -209,6 +226,213 @@
 static VinoInputData global_input_data = { 0, };
 
 #ifdef HAVE_XTEST
+
+static struct {
+  guint32 composed;
+  guint32 decomposed[3];
+} decompositions[] = {
+  { XK_Cabovedot, { XK_dead_abovedot, 'C', 0 } },
+  { XK_Eabovedot, { XK_dead_abovedot, 'E', 0 } },
+  { XK_Gabovedot, { XK_dead_abovedot, 'G', 0 } },
+  { XK_Iabovedot, { XK_dead_abovedot, 'I', 0 } },
+  { XK_Zabovedot, { XK_dead_abovedot, 'Z', 0 } },
+  { XK_cabovedot, { XK_dead_abovedot, 'c', 0 } },
+  { XK_eabovedot, { XK_dead_abovedot, 'e', 0 } },
+  { XK_gabovedot, { XK_dead_abovedot, 'g', 0 } },
+  { XK_idotless,  { XK_dead_abovedot, 'i', 0 } },
+  { XK_zabovedot, { XK_dead_abovedot, 'z', 0 } },
+  { XK_abovedot,  { XK_dead_abovedot, XK_dead_abovedot, 0 } },
+
+  { XK_Aring,  { XK_dead_abovering, 'A', 0 } },
+  { XK_Uring,  { XK_dead_abovering, 'U', 0 } },
+  { XK_aring,  { XK_dead_abovering, 'a', 0 } },
+  { XK_uring,  { XK_dead_abovering, 'u', 0 } },
+  { XK_degree, { XK_dead_abovering, XK_dead_abovering, 0 } },
+
+  { XK_Aacute, { XK_dead_acute, 'A', 0 } },
+  { XK_Cacute, { XK_dead_acute, 'C', 0 } },
+  { XK_Eacute, { XK_dead_acute, 'E', 0 } },
+  { XK_Iacute, { XK_dead_acute, 'I', 0 } },
+  { XK_Lacute, { XK_dead_acute, 'L', 0 } },
+  { XK_Nacute, { XK_dead_acute, 'N', 0 } },
+  { XK_Oacute, { XK_dead_acute, 'O', 0 } },
+  { XK_Racute, { XK_dead_acute, 'R', 0 } },
+  { XK_Sacute, { XK_dead_acute, 'S', 0 } },
+  { XK_Uacute, { XK_dead_acute, 'U', 0 } },
+  { XK_Yacute, { XK_dead_acute, 'Y', 0 } },
+  { XK_Zacute, { XK_dead_acute, 'Z', 0 } },
+  { XK_aacute, { XK_dead_acute, 'a', 0 } },
+  { XK_cacute, { XK_dead_acute, 'c', 0 } },
+  { XK_eacute, { XK_dead_acute, 'e', 0 } },
+  { XK_iacute, { XK_dead_acute, 'i', 0 } },
+  { XK_lacute, { XK_dead_acute, 'l', 0 } },
+  { XK_nacute, { XK_dead_acute, 'n', 0 } },
+  { XK_oacute, { XK_dead_acute, 'o', 0 } },
+  { XK_racute, { XK_dead_acute, 'r', 0 } },
+  { XK_sacute, { XK_dead_acute, 's', 0 } },
+  { XK_uacute, { XK_dead_acute, 'u', 0 } },
+  { XK_yacute, { XK_dead_acute, 'y', 0 } },
+  { XK_zacute, { XK_dead_acute, 'z', 0 } },
+  { XK_acute,  { XK_dead_acute, XK_dead_acute, 0 } },
+
+  { XK_Abreve, { XK_dead_breve, 'A', 0 } },
+  { XK_Gbreve, { XK_dead_breve, 'G', 0 } },
+  { XK_Ubreve, { XK_dead_breve, 'U', 0 } },
+  { XK_abreve, { XK_dead_breve, 'a', 0 } },
+  { XK_gbreve, { XK_dead_breve, 'g', 0 } },
+  { XK_ubreve, { XK_dead_breve, 'u', 0 } },
+  { XK_breve,  { XK_dead_breve, XK_dead_breve, 0 } },
+
+  { XK_Ccaron, { XK_dead_caron, 'C', 0 } },
+  { XK_Dcaron, { XK_dead_caron, 'D', 0 } },
+  { XK_Ecaron, { XK_dead_caron, 'E', 0 } },
+  { XK_Lcaron, { XK_dead_caron, 'L', 0 } },
+  { XK_Ncaron, { XK_dead_caron, 'N', 0 } },
+  { XK_Rcaron, { XK_dead_caron, 'R', 0 } },
+  { XK_Scaron, { XK_dead_caron, 'S', 0 } },
+  { XK_Tcaron, { XK_dead_caron, 'T', 0 } },
+  { XK_Zcaron, { XK_dead_caron, 'Z', 0 } },
+  { XK_ccaron, { XK_dead_caron, 'c', 0 } },
+  { XK_dcaron, { XK_dead_caron, 'd', 0 } },
+  { XK_ecaron, { XK_dead_caron, 'e', 0 } },
+  { XK_lcaron, { XK_dead_caron, 'l', 0 } },
+  { XK_ncaron, { XK_dead_caron, 'n', 0 } },
+  { XK_rcaron, { XK_dead_caron, 'r', 0 } },
+  { XK_scaron, { XK_dead_caron, 's', 0 } },
+  { XK_tcaron, { XK_dead_caron, 't', 0 } },
+  { XK_zcaron, { XK_dead_caron, 'z', 0 } },
+  { XK_caron,  { XK_dead_caron, XK_dead_caron, 0 } },
+
+  { XK_Ccedilla, { XK_dead_cedilla, 'C', 0 } },
+  { XK_Gcedilla, { XK_dead_cedilla, 'G', 0 } },
+  { XK_Kcedilla, { XK_dead_cedilla, 'K', 0 } },
+  { XK_Lcedilla, { XK_dead_cedilla, 'L', 0 } },
+  { XK_Ncedilla, { XK_dead_cedilla, 'N', 0 } },
+  { XK_Rcedilla, { XK_dead_cedilla, 'R', 0 } },
+  { XK_Scedilla, { XK_dead_cedilla, 'S', 0 } },
+  { XK_Tcedilla, { XK_dead_cedilla, 'T', 0 } },
+  { XK_ccedilla, { XK_dead_cedilla, 'c', 0 } },
+  { XK_gcedilla, { XK_dead_cedilla, 'g', 0 } },
+  { XK_kcedilla, { XK_dead_cedilla, 'k', 0 } },
+  { XK_lcedilla, { XK_dead_cedilla, 'l', 0 } },
+  { XK_ncedilla, { XK_dead_cedilla, 'n', 0 } },
+  { XK_rcedilla, { XK_dead_cedilla, 'r', 0 } },
+  { XK_scedilla, { XK_dead_cedilla, 's', 0 } },
+  { XK_tcedilla, { XK_dead_cedilla, 't', 0 } },
+  { XK_cedilla,  { XK_dead_cedilla, XK_dead_cedilla, 0 } },
+
+  { XK_Acircumflex, { XK_dead_circumflex, 'A', 0 } },
+  { XK_Ccircumflex, { XK_dead_circumflex, 'C', 0 } },
+  { XK_Ecircumflex, { XK_dead_circumflex, 'E', 0 } },
+  { XK_Gcircumflex, { XK_dead_circumflex, 'G', 0 } },
+  { XK_Hcircumflex, { XK_dead_circumflex, 'H', 0 } },
+  { XK_Icircumflex, { XK_dead_circumflex, 'I', 0 } },
+  { XK_Jcircumflex, { XK_dead_circumflex, 'J', 0 } },
+  { XK_Ocircumflex, { XK_dead_circumflex, 'O', 0 } },
+  { XK_Scircumflex, { XK_dead_circumflex, 'S', 0 } },
+  { XK_Ucircumflex, { XK_dead_circumflex, 'U', 0 } },
+  { XK_acircumflex, { XK_dead_circumflex, 'a', 0 } },
+  { XK_ccircumflex, { XK_dead_circumflex, 'c', 0 } },
+  { XK_ecircumflex, { XK_dead_circumflex, 'e', 0 } },
+  { XK_gcircumflex, { XK_dead_circumflex, 'g', 0 } },
+  { XK_hcircumflex, { XK_dead_circumflex, 'h', 0 } },
+  { XK_icircumflex, { XK_dead_circumflex, 'i', 0 } },
+  { XK_jcircumflex, { XK_dead_circumflex, 'j', 0 } },
+  { XK_ocircumflex, { XK_dead_circumflex, 'o', 0 } },
+  { XK_scircumflex, { XK_dead_circumflex, 's', 0 } },
+  { XK_ucircumflex, { XK_dead_circumflex, 'u', 0 } },
+  { XK_asciicircum, { XK_dead_circumflex, XK_dead_circumflex, 0 } },
+
+  { XK_Adiaeresis, { XK_dead_diaeresis, 'A', 0 } },
+  { XK_Ediaeresis, { XK_dead_diaeresis, 'E', 0 } },
+  { XK_Idiaeresis, { XK_dead_diaeresis, 'I', 0 } },
+  { XK_Odiaeresis, { XK_dead_diaeresis, 'O', 0 } },
+  { XK_Udiaeresis, { XK_dead_diaeresis, 'U', 0 } },
+  { XK_adiaeresis, { XK_dead_diaeresis, 'a', 0 } },
+  { XK_ediaeresis, { XK_dead_diaeresis, 'e', 0 } },
+  { XK_idiaeresis, { XK_dead_diaeresis, 'i', 0 } },
+  { XK_odiaeresis, { XK_dead_diaeresis, 'o', 0 } },
+  { XK_udiaeresis, { XK_dead_diaeresis, 'u', 0 } },
+  { XK_ydiaeresis, { XK_dead_diaeresis, 'y', 0 } },
+  { XK_diaeresis,  { XK_dead_diaeresis, XK_dead_diaeresis, 0 } },
+
+  { XK_Odoubleacute, { XK_dead_doubleacute, 'O', 0 } },
+  { XK_Udoubleacute, { XK_dead_doubleacute, 'U', 0 } },
+  { XK_odoubleacute, { XK_dead_doubleacute, 'o', 0 } },
+  { XK_udoubleacute, { XK_dead_doubleacute, 'u', 0 } },
+  { XK_doubleacute,  { XK_dead_doubleacute, XK_dead_doubleacute, 0 } },
+
+  { XK_Agrave, { XK_dead_grave, 'A', 0 } },
+  { XK_Egrave, { XK_dead_grave, 'E', 0 } },
+  { XK_Igrave, { XK_dead_grave, 'I', 0 } },
+  { XK_Ograve, { XK_dead_grave, 'O', 0 } },
+  { XK_Ugrave, { XK_dead_grave, 'U', 0 } },
+  { XK_agrave, { XK_dead_grave, 'a', 0 } },
+  { XK_egrave, { XK_dead_grave, 'e', 0 } },
+  { XK_igrave, { XK_dead_grave, 'i', 0 } },
+  { XK_ograve, { XK_dead_grave, 'o', 0 } },
+  { XK_ugrave, { XK_dead_grave, 'u', 0 } },
+  { XK_grave,  { XK_dead_grave, XK_dead_grave, 0 } },
+
+  { XK_Amacron, { XK_dead_macron, 'A', 0 } },
+  { XK_Emacron, { XK_dead_macron, 'E', 0 } },
+  { XK_Imacron, { XK_dead_macron, 'I', 0 } },
+  { XK_Omacron, { XK_dead_macron, 'O', 0 } },
+  { XK_Umacron, { XK_dead_macron, 'U', 0 } },
+  { XK_amacron, { XK_dead_macron, 'a', 0 } },
+  { XK_emacron, { XK_dead_macron, 'e', 0 } },
+  { XK_imacron, { XK_dead_macron, 'i', 0 } },
+  { XK_omacron, { XK_dead_macron, 'o', 0 } },
+  { XK_umacron, { XK_dead_macron, 'u', 0 } },
+  { XK_macron,  { XK_dead_macron, XK_dead_macron, 0 } },
+
+  { XK_Aogonek, { XK_dead_ogonek, 'A', 0 } },
+  { XK_Eogonek, { XK_dead_ogonek, 'E', 0 } },
+  { XK_Iogonek, { XK_dead_ogonek, 'I', 0 } },
+  { XK_Uogonek, { XK_dead_ogonek, 'U', 0 } },
+  { XK_aogonek, { XK_dead_ogonek, 'a', 0 } },
+  { XK_eogonek, { XK_dead_ogonek, 'e', 0 } },
+  { XK_iogonek, { XK_dead_ogonek, 'i', 0 } },
+  { XK_uogonek, { XK_dead_ogonek, 'u', 0 } },
+  { XK_ogonek,  { XK_dead_ogonek, XK_dead_ogonek, 0 } },
+
+  { XK_Atilde, 	 { XK_dead_tilde, 'A', 0 } },
+  { XK_Itilde, 	 { XK_dead_tilde, 'I', 0 } },
+  { XK_Ntilde, 	 { XK_dead_tilde, 'N', 0 } },
+  { XK_Otilde, 	 { XK_dead_tilde, 'O', 0 } },
+  { XK_Utilde, 	 { XK_dead_tilde, 'U', 0 } },
+  { XK_atilde, 	 { XK_dead_tilde, 'a', 0 } },
+  { XK_itilde, 	 { XK_dead_tilde, 'i', 0 } },
+  { XK_ntilde, 	 { XK_dead_tilde, 'n', 0 } },
+  { XK_otilde, 	 { XK_dead_tilde, 'o', 0 } },
+  { XK_utilde, 	 { XK_dead_tilde, 'u', 0 } },
+  { XK_asciitilde, { XK_dead_tilde, XK_dead_tilde, 0 } },
+
+  { XK_Greek_ALPHAaccent,   { XK_dead_acute, XK_Greek_ALPHA, 0 } },
+  { XK_Greek_EPSILONaccent, { XK_dead_acute, XK_Greek_EPSILON, 0 } },
+  { XK_Greek_ETAaccent,     { XK_dead_acute, XK_Greek_ETA, 0 } },
+  { XK_Greek_IOTAaccent,    { XK_dead_acute, XK_Greek_IOTA, 0 } },
+  { XK_Greek_OMICRONaccent, { XK_dead_acute, XK_Greek_OMICRON, 0 } },
+  { XK_Greek_UPSILONaccent, { XK_dead_acute, XK_Greek_UPSILON, 0 } },
+  { XK_Greek_OMEGAaccent,   { XK_dead_acute, XK_Greek_OMEGA, 0 } },
+  { XK_Greek_alphaaccent,   { XK_dead_acute, XK_Greek_alpha, 0 } },
+  { XK_Greek_epsilonaccent, { XK_dead_acute, XK_Greek_epsilon, 0 } },
+  { XK_Greek_etaaccent,     { XK_dead_acute, XK_Greek_eta, 0 } },
+  { XK_Greek_iotaaccent,    { XK_dead_acute, XK_Greek_iota, 0 } },
+  { XK_Greek_omicronaccent, { XK_dead_acute, XK_Greek_omicron, 0 } },
+  { XK_Greek_upsilonaccent, { XK_dead_acute, XK_Greek_upsilon, 0 } },
+  { XK_Greek_omegaaccent,   { XK_dead_acute, XK_Greek_omega, 0 } },
+
+  { XK_Greek_IOTAdieresis,    { XK_dead_diaeresis, XK_Greek_IOTA, 0 } },
+  { XK_Greek_UPSILONdieresis, { XK_dead_diaeresis, XK_Greek_UPSILON, 0 } },
+  { XK_Greek_iotadieresis,    { XK_dead_diaeresis, XK_Greek_iota, 0 } },
+  { XK_Greek_upsilondieresis, { XK_dead_diaeresis, XK_Greek_upsilon, 0 } },
+
+  { XK_Greek_iotaaccentdieresis,    { XK_dead_acute, XK_dead_diaeresis, XK_Greek_iota } },
+  { XK_Greek_upsilonaccentdieresis, { XK_dead_acute, XK_dead_diaeresis, XK_Greek_upsilon } }
+};
+static const int num_decompositions = G_N_ELEMENTS (decompositions);
+
 static void vino_input_initialize_keycodes (Display *xdisplay);
 
 static void
@@ -233,7 +457,7 @@
       for (keycode = min_keycodes; keycode < max_keycodes; keycode++)
 	{
 	  VinoKeybinding *binding;
-	  gboolean unmodifiable;
+	  gboolean unmodifiable = FALSE;
 
 	  sym = XKeycodeToKeysym (xdisplay, keycode, level);
 	  if (sym == NoSymbol)
@@ -509,6 +733,7 @@
 
   global_input_data.left_shift_keycode   = XKeysymToKeycode (xdisplay, XK_Shift_L);
   global_input_data.right_shift_keycode  = XKeysymToKeycode (xdisplay, XK_Shift_R);
+  global_input_data.left_control_keycode = XKeysymToKeycode (xdisplay, XK_Control_L);
   global_input_data.num_lock_keycode     = XKeysymToKeycode (xdisplay, XK_Num_Lock);
   global_input_data.alt_gr_keycode       = XKeysymToKeycode (xdisplay, global_input_data.alt_gr_keysym);
 }
@@ -520,6 +745,7 @@
 #ifdef HAVE_XTEST
   Display *xdisplay;
   int      ignore, *i = &ignore;
+  int      d;
 
   g_assert (global_input_data.initialized != TRUE);
 
@@ -559,6 +785,14 @@
 #endif
     global_input_data.xkb_supported = FALSE;
 
+  global_input_data.decompositions = g_hash_table_new (NULL, NULL);
+  for (d = 0; d < num_decompositions; d++)
+    {
+      g_hash_table_insert (global_input_data.decompositions,
+			   GUINT_TO_POINTER (decompositions[d].composed),
+			   decompositions[d].decomposed);
+    }
+
   vino_input_initialize_keycodes (xdisplay);
 
   global_input_data.initialized = TRUE;
@@ -768,7 +1002,25 @@
       return TRUE;
     }
   else
-    return FALSE;
+    {
+      guint32 *decomposition =
+	g_hash_table_lookup (global_input_data.decompositions,
+			     GUINT_TO_POINTER (keysym));
+      int i;
+
+      if (decomposition)
+	{
+	  for (i = 0; i < 3 && decomposition[i]; i++)
+	    {
+	      if (!vino_input_fake_keypress (xdisplay, decomposition[i]))
+		return FALSE;
+	    }
+
+	  return TRUE;
+	}
+    }
+
+  return FALSE;
 }
 #endif /* HAVE_XTEST */
 
@@ -802,6 +1054,10 @@
 				    keysym, key_press);
 
   vino_input_update_modifier_state (&global_input_data,
+				    VINO_LEFT_CONTROL, XK_Control_L,
+				    keysym, key_press);
+
+  vino_input_update_modifier_state (&global_input_data,
 				    VINO_ALT_GR, global_input_data.alt_gr_keysym,
 				    keysym, key_press);
 
@@ -809,6 +1065,30 @@
     {
       vino_input_fake_keypress (xdisplay, keysym);
     }
+  else if (key_press && keysym == XK_Alt_R &&
+	   (global_input_data.modifier_state & VINO_LEFT_CONTROL))
+    {
+      /* Windows translates Alt-Gr to XK_Ctrl_L + XK_Alt_R */
+
+      dprintf (INPUT, "Translating Ctrl+Alt press into Alt-Gr\n");
+
+      XTestFakeKeyEvent (xdisplay, global_input_data.left_control_keycode,
+			 FALSE,  CurrentTime);
+      XTestFakeKeyEvent (xdisplay, global_input_data.alt_gr_keycode,
+			 TRUE, CurrentTime);
+
+      global_input_data.modifier_state |= (VINO_RIGHT_ALT | VINO_ALT_GR);
+    }
+  else if (!key_press && keysym == XK_Control_L &&
+	   (global_input_data.modifier_state & VINO_RIGHT_ALT))
+    {
+      dprintf (INPUT, "Translating Ctrl+Alt release into Alt-Gr\n");
+
+      XTestFakeKeyEvent (xdisplay, global_input_data.alt_gr_keycode,
+			 FALSE, CurrentTime);
+
+      global_input_data.modifier_state &= ~(VINO_RIGHT_ALT | VINO_ALT_GR);
+    }
   else if (keysym != XK_Caps_Lock && keysym != XK_Num_Lock)
     {
       KeyCode keycode;
