]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkimcontextsimple.c
stylecontext: If we force invalidate, invalidate all properties
[~andy/gtk] / gtk / gtkimcontextsimple.c
index 03ddcc3310bf2ead5d90aa37352d4ec801d064a5..87debf226b9baaaeb4f3c3729aa6b25b79933e0b 100644 (file)
  * Copyright (C) 2000 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library 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
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <unicode.h>
-#include <gdk/gdkkeysyms.h>
-#include "gtksignal.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gtkprivate.h"
+#include "gtkaccelgroup.h"
 #include "gtkimcontextsimple.h"
+#include "gtksettings.h"
+#include "gtkwidget.h"
+#include "gtkdebug.h"
+#include "gtkintl.h"
+
+
+/**
+ * SECTION:gtkimcontextsimple
+ * @Short_description: An input method context supporting table-based input methods
+ * @Title: GtkIMContextSimple
+ */
 
-typedef struct _GtkComposeSeq GtkComposeSeq;
 
-struct _GtkComposeSeq
+typedef struct _GtkComposeTable GtkComposeTable;
+typedef struct _GtkComposeTableCompact GtkComposeTableCompact;
+
+struct _GtkIMContextSimplePrivate
 {
-  guint16 keysyms[GTK_MAX_COMPOSE_LEN];
-  guint16 unicode;
-};
+  GSList        *tables;
 
-/* The following table was generated from the X compose tables include with
- * XFree86 4.0 using a set of Perl scripts. Contact Owen Taylor <otaylor@redhat.com>
- * to obtain the relevant perl scripts.
- *
- * The following compose letter letter sequences confliced
- *   Dstroke/dstroke and ETH/eth; resolved to Dstroke (Croation, Vietnamese, Lappish), over 
- *                                ETH (Icelandic, Faroese, old English, IPA)   [ D- -D d- -d ]
- *   Amacron/amacron and ordfeminine; resolved to ordfeminine                  [ _A A_ a_ _a ]
- *   Amacron/amacron and Atilde/atilde; resolved to atilde                   [ -A A- a- -a ]
- *   Omacron/Omacron and masculine; resolved to masculine                    [ _A A_ a_ _a ]
- *   Omacron/omacron and Otilde/atilde; resolved to otilde                   [ -O O- o- -o ]
- *
- * [ Amacron and Omacron are in Latin-4 (Baltic). ordfeminine and masculine are used for
- *   spanish. atilde and otilde are used at least for Portuguese ]
- *
- *   at and Aring; resolved to Aring                                         [ AA ]
- *   guillemotleft and caron; resolved to guillemotleft                              [ << ]
- *   ogonek and cedilla; resolved to cedilla                                 [ ,, ]
- * 
- * This probably should be resolved by first checking an additional set of compose tables
- * that depend on the locale or selected input method. 
- */
+  guint          compose_buffer[GTK_MAX_COMPOSE_LEN + 1];
+  gunichar       tentative_match;
+  gint           tentative_match_len;
 
-GtkComposeSeq gtk_compose_seqs[] = {
-  { { GDK_dead_grave,  GDK_space,      0,      0 },    0x0060 },       /* GRAVE_ACCENT */
-  { { GDK_dead_grave,  GDK_A,  0,      0 },    0x00C0 },       /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_E,  0,      0 },    0x00C8 },       /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_I,  0,      0 },    0x00CC },       /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_O,  0,      0 },    0x00D2 },       /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_U,  0,      0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_a,  0,      0 },    0x00E0 },       /* LATIN_SMALL_LETTER_A_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_e,  0,      0 },    0x00E8 },       /* LATIN_SMALL_LETTER_E_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_i,  0,      0 },    0x00EC },       /* LATIN_SMALL_LETTER_I_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_o,  0,      0 },    0x00F2 },       /* LATIN_SMALL_LETTER_O_WITH_GRAVE */
-  { { GDK_dead_grave,  GDK_u,  0,      0 },    0x00F9 },       /* LATIN_SMALL_LETTER_U_WITH_GRAVE */
-  { { GDK_dead_acute,  GDK_space,      0,      0 },    0x0027 },       /* APOSTROPHE */
-  { { GDK_dead_acute,  GDK_apostrophe, 0,      0 },    0x00B4 },       /* ACUTE_ACCENT */
-  { { GDK_dead_acute,  GDK_A,  0,      0 },    0x00C1 },       /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_E,  0,      0 },    0x00C9 },       /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_I,  0,      0 },    0x00CD },       /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_O,  0,      0 },    0x00D3 },       /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_U,  0,      0 },    0x00DA },       /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_Y,  0,      0 },    0x00DD },       /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_a,  0,      0 },    0x00E1 },       /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_e,  0,      0 },    0x00E9 },       /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_i,  0,      0 },    0x00ED },       /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_o,  0,      0 },    0x00F3 },       /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_u,  0,      0 },    0x00FA },       /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_y,  0,      0 },    0x00FD },       /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
-  { { GDK_dead_acute,  GDK_acute,      0,      0 },    0x00B4 },       /* ACUTE_ACCENT */
-  { { GDK_dead_acute,  GDK_dead_acute, 0,      0 },    0x00B4 },       /* ACUTE_ACCENT */
-  { { GDK_dead_circumflex,     GDK_space,      0,      0 },    0x005E },       /* CIRCUMFLEX_ACCENT */
-  { { GDK_dead_circumflex,     GDK_minus,      0,      0 },    0x00AF },       /* MACRON */
-  { { GDK_dead_circumflex,     GDK_period,     0,      0 },    0x00B7 },       /* MIDDLE_DOT */
-  { { GDK_dead_circumflex,     GDK_slash,      0,      0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_dead_circumflex,     GDK_0,  0,      0 },    0x00B0 },       /* DEGREE_SIGN */
-  { { GDK_dead_circumflex,     GDK_1,  0,      0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_dead_circumflex,     GDK_2,  0,      0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_dead_circumflex,     GDK_3,  0,      0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_dead_circumflex,     GDK_A,  0,      0 },    0x00C2 },       /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_E,  0,      0 },    0x00CA },       /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_I,  0,      0 },    0x00CE },       /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_O,  0,      0 },    0x00D4 },       /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_U,  0,      0 },    0x00DB },       /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_underscore, 0,      0 },    0x00AF },       /* MACRON */
-  { { GDK_dead_circumflex,     GDK_a,  0,      0 },    0x00E2 },       /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_e,  0,      0 },    0x00EA },       /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_i,  0,      0 },    0x00EE },       /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_o,  0,      0 },    0x00F4 },       /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_dead_circumflex,     GDK_u,  0,      0 },    0x00FB },       /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_dead_tilde,  GDK_space,      0,      0 },    0x007E },       /* TILDE */
-  { { GDK_dead_tilde,  GDK_A,  0,      0 },    0x00C3 },       /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_I,  0,      0 },    0x0128 },       /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_N,  0,      0 },    0x00D1 },       /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_O,  0,      0 },    0x00D5 },       /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_U,  0,      0 },    0x0168 },       /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_a,  0,      0 },    0x00E3 },       /* LATIN_SMALL_LETTER_A_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_i,  0,      0 },    0x0129 },       /* LATIN_SMALL_LETTER_I_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_n,  0,      0 },    0x00F1 },       /* LATIN_SMALL_LETTER_N_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_o,  0,      0 },    0x00F5 },       /* LATIN_SMALL_LETTER_O_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_u,  0,      0 },    0x0169 },       /* LATIN_SMALL_LETTER_U_WITH_TILDE */
-  { { GDK_dead_tilde,  GDK_asciitilde, 0,      0 },    0x007E },       /* TILDE */
-  { { GDK_dead_tilde,  GDK_dead_tilde, 0,      0 },    0x007E },       /* TILDE */
-  { { GDK_dead_macron, GDK_A,  0,      0 },    0x0100 },       /* LATIN_CAPITAL_LETTER_A_WITH_MACRON */
-  { { GDK_dead_macron, GDK_E,  0,      0 },    0x0112 },       /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
-  { { GDK_dead_macron, GDK_I,  0,      0 },    0x012A },       /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
-  { { GDK_dead_macron, GDK_O,  0,      0 },    0x014C },       /* LATIN_CAPITAL_LETTER_O_WITH_MACRON */
-  { { GDK_dead_macron, GDK_U,  0,      0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_dead_macron, GDK_a,  0,      0 },    0x0101 },       /* LATIN_SMALL_LETTER_A_WITH_MACRON */
-  { { GDK_dead_macron, GDK_e,  0,      0 },    0x0113 },       /* LATIN_SMALL_LETTER_E_WITH_MACRON */
-  { { GDK_dead_macron, GDK_i,  0,      0 },    0x012B },       /* LATIN_SMALL_LETTER_I_WITH_MACRON */
-  { { GDK_dead_macron, GDK_o,  0,      0 },    0x014D },       /* LATIN_SMALL_LETTER_O_WITH_MACRON */
-  { { GDK_dead_macron, GDK_u,  0,      0 },    0x016B },       /* LATIN_SMALL_LETTER_U_WITH_MACRON */
-  { { GDK_dead_macron, GDK_macron,     0,      0 },    0x00AF },       /* MACRON */
-  { { GDK_dead_macron, GDK_dead_macron,        0,      0 },    0x00AF },       /* MACRON */
-  { { GDK_dead_breve,  GDK_G,  0,      0 },    0x011E },       /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
-  { { GDK_dead_breve,  GDK_g,  0,      0 },    0x011F },       /* LATIN_SMALL_LETTER_G_WITH_BREVE */
-  { { GDK_dead_abovedot,       GDK_E,  0,      0 },    0x0116 },       /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */
-  { { GDK_dead_abovedot,       GDK_I,  0,      0 },    0x0130 },       /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */
-  { { GDK_dead_abovedot,       GDK_e,  0,      0 },    0x0117 },       /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */
-  { { GDK_dead_abovedot,       GDK_i,  0,      0 },    0x0131 },       /* LATIN_SMALL_LETTER_DOTLESS_I */
-  { { GDK_dead_abovedot,       GDK_abovedot,   0,      0 },    0x02D9 },       /* DOT_ABOVE */
-  { { GDK_dead_abovedot,       GDK_dead_abovedot,      0,      0 },    0x02D9 },       /* DOT_ABOVE */
-  { { GDK_dead_diaeresis,      GDK_space,      0,      0 },    0x00A8 },       /* DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_quotedbl,   0,      0 },    0x00A8 },       /* DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_A,  0,      0 },    0x00C4 },       /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_E,  0,      0 },    0x00CB },       /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_I,  0,      0 },    0x00CF },       /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_O,  0,      0 },    0x00D6 },       /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_U,  0,      0 },    0x00DC },       /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_Y,  0,      0 },    0x0178 },       /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_a,  0,      0 },    0x00E4 },       /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_e,  0,      0 },    0x00EB },       /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_i,  0,      0 },    0x00EF },       /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_o,  0,      0 },    0x00F6 },       /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_u,  0,      0 },    0x00FC },       /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_y,  0,      0 },    0x00FF },       /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_diaeresis,  0,      0 },    0x00A8 },       /* DIAERESIS */
-  { { GDK_dead_diaeresis,      GDK_dead_diaeresis,     0,      0 },    0x00A8 },       /* DIAERESIS */
-  { { GDK_dead_abovering,      GDK_A,  0,      0 },    0x00C5 },       /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_dead_abovering,      GDK_a,  0,      0 },    0x00E5 },       /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_dead_abovering,      GDK_dead_abovering,     0,      0 },    0x02DA },       /* RING_ABOVE */
-  { { GDK_dead_caron,  GDK_C,  0,      0 },    0x010C },       /* LATIN_CAPITAL_LETTER_C_WITH_CARON */
-  { { GDK_dead_caron,  GDK_S,  0,      0 },    0x0160 },       /* LATIN_CAPITAL_LETTER_S_WITH_CARON */
-  { { GDK_dead_caron,  GDK_Z,  0,      0 },    0x017D },       /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */
-  { { GDK_dead_caron,  GDK_c,  0,      0 },    0x010D },       /* LATIN_SMALL_LETTER_C_WITH_CARON */
-  { { GDK_dead_caron,  GDK_s,  0,      0 },    0x0161 },       /* LATIN_SMALL_LETTER_S_WITH_CARON */
-  { { GDK_dead_caron,  GDK_z,  0,      0 },    0x017E },       /* LATIN_SMALL_LETTER_Z_WITH_CARON */
-  { { GDK_dead_caron,  GDK_caron,      0,      0 },    0x02C7 },       /* CARON */
-  { { GDK_dead_caron,  GDK_dead_caron, 0,      0 },    0x02C7 },       /* CARON */
-  { { GDK_dead_cedilla,        GDK_comma,      0,      0 },    0x00B8 },       /* CEDILLA */
-  { { GDK_dead_cedilla,        GDK_minus,      0,      0 },    0x00AC },       /* NOT_SIGN */
-  { { GDK_dead_cedilla,        GDK_C,  0,      0 },    0x00C7 },       /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_G,  0,      0 },    0x0122 },       /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_K,  0,      0 },    0x0136 },       /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_L,  0,      0 },    0x013B },       /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_N,  0,      0 },    0x0145 },       /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_R,  0,      0 },    0x0156 },       /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_S,  0,      0 },    0x015E },       /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_c,  0,      0 },    0x00E7 },       /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_g,  0,      0 },    0x0123 },       /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_k,  0,      0 },    0x0137 },       /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_l,  0,      0 },    0x013C },       /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_n,  0,      0 },    0x0146 },       /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_r,  0,      0 },    0x0157 },       /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_s,  0,      0 },    0x015F },       /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
-  { { GDK_dead_cedilla,        GDK_cedilla,    0,      0 },    0x00B8 },       /* CEDILLA */
-  { { GDK_dead_cedilla,        GDK_dead_cedilla,       0,      0 },    0x00B8 },       /* CEDILLA */
-  { { GDK_dead_ogonek, GDK_A,  0,      0 },    0x0104 },       /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_E,  0,      0 },    0x0118 },       /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_I,  0,      0 },    0x012E },       /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_U,  0,      0 },    0x0172 },       /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_a,  0,      0 },    0x0105 },       /* LATIN_SMALL_LETTER_A_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_e,  0,      0 },    0x0119 },       /* LATIN_SMALL_LETTER_E_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_i,  0,      0 },    0x012F },       /* LATIN_SMALL_LETTER_I_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_u,  0,      0 },    0x0173 },       /* LATIN_SMALL_LETTER_U_WITH_OGONEK */
-  { { GDK_dead_ogonek, GDK_ogonek,     0,      0 },    0x02DB },       /* OGONEK */
-  { { GDK_dead_ogonek, GDK_dead_ogonek,        0,      0 },    0x02DB },       /* OGONEK */
-  { { GDK_Multi_key,   GDK_space,      GDK_space,      0 },    0x00A0 },       /* NOxBREAK_SPACE */
-  { { GDK_Multi_key,   GDK_space,      GDK_apostrophe, 0 },    0x0027 },       /* APOSTROPHE */
-  { { GDK_Multi_key,   GDK_space,      GDK_minus,      0 },    0x007E },       /* TILDE */
-  { { GDK_Multi_key,   GDK_space,      GDK_greater,    0 },    0x005E },       /* CIRCUMFLEX_ACCENT */
-  { { GDK_Multi_key,   GDK_space,      GDK_asciicircum,        0 },    0x005E },       /* CIRCUMFLEX_ACCENT */
-  { { GDK_Multi_key,   GDK_space,      GDK_grave,      0 },    0x0060 },       /* GRAVE_ACCENT */
-  { { GDK_Multi_key,   GDK_space,      GDK_asciitilde, 0 },    0x007E },       /* TILDE */
-  { { GDK_Multi_key,   GDK_exclam,     GDK_exclam,     0 },    0x00A1 },       /* INVERTED_EXCLAMATION_MARK */
-  { { GDK_Multi_key,   GDK_exclam,     GDK_P,  0 },    0x00B6 },       /* PILCROW_SIGN */
-  { { GDK_Multi_key,   GDK_exclam,     GDK_S,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_exclam,     GDK_p,  0 },    0x00B6 },       /* PILCROW_SIGN */
-  { { GDK_Multi_key,   GDK_exclam,     GDK_s,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_quotedbl,   0 },    0x00A8 },       /* DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_A,  0 },    0x00C4 },       /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_E,  0 },    0x00CB },       /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_I,  0 },    0x00CF },       /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_O,  0 },    0x00D6 },       /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_U,  0 },    0x00DC },       /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_Y,  0 },    0x0178 },       /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_a,  0 },    0x00E4 },       /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_e,  0 },    0x00EB },       /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_i,  0 },    0x00EF },       /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_o,  0 },    0x00F6 },       /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_u,  0 },    0x00FC },       /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_quotedbl,   GDK_y,  0 },    0x00FF },       /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_space,      0 },    0x0027 },       /* APOSTROPHE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_apostrophe, 0 },    0x00B4 },       /* ACUTE_ACCENT */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_A,  0 },    0x00C1 },       /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_E,  0 },    0x00C9 },       /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_I,  0 },    0x00CD },       /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_O,  0 },    0x00D3 },       /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_U,  0 },    0x00DA },       /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_Y,  0 },    0x00DD },       /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_a,  0 },    0x00E1 },       /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_e,  0 },    0x00E9 },       /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_i,  0 },    0x00ED },       /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_o,  0 },    0x00F3 },       /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_u,  0 },    0x00FA },       /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_apostrophe, GDK_y,  0 },    0x00FD },       /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_parenleft,  GDK_parenleft,  0 },    0x005B },       /* LEFT_SQUARE_BRACKET */
-  { { GDK_Multi_key,   GDK_parenleft,  GDK_minus,      0 },    0x007B },       /* LEFT_CURLY_BRACKET */
-  { { GDK_Multi_key,   GDK_parenleft,  GDK_G,  0 },    0x011E },       /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_parenleft,  GDK_c,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_parenleft,  GDK_g,  0 },    0x011F },       /* LATIN_SMALL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_parenleft,  GDK_r,  0 },    0x00AE },       /* REGISTERED_SIGN */
-  { { GDK_Multi_key,   GDK_parenright, GDK_parenright, 0 },    0x005D },       /* RIGHT_SQUARE_BRACKET */
-  { { GDK_Multi_key,   GDK_parenright, GDK_minus,      0 },    0x007D },       /* RIGHT_CURLY_BRACKET */
-  { { GDK_Multi_key,   GDK_asterisk,   GDK_0,  0 },    0x00B0 },       /* DEGREE_SIGN */
-  { { GDK_Multi_key,   GDK_asterisk,   GDK_A,  0 },    0x00C5 },       /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_Multi_key,   GDK_asterisk,   GDK_a,  0 },    0x00E5 },       /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_Multi_key,   GDK_plus,       GDK_plus,       0 },    0x0023 },       /* NUMBER_SIGN */
-  { { GDK_Multi_key,   GDK_plus,       GDK_minus,      0 },    0x00B1 },       /* PLUSxMINUS_SIGN */
-  { { GDK_Multi_key,   GDK_comma,      GDK_comma,      0 },    0x00B8 },       /* CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_minus,      0 },    0x00AC },       /* NOT_SIGN */
-  { { GDK_Multi_key,   GDK_comma,      GDK_A,  0 },    0x0104 },       /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_C,  0 },    0x00C7 },       /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_E,  0 },    0x0118 },       /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_G,  0 },    0x0122 },       /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_I,  0 },    0x012E },       /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_K,  0 },    0x0136 },       /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_L,  0 },    0x013B },       /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_N,  0 },    0x0145 },       /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_R,  0 },    0x0156 },       /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_S,  0 },    0x015E },       /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_U,  0 },    0x0172 },       /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_a,  0 },    0x0105 },       /* LATIN_SMALL_LETTER_A_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_c,  0 },    0x00E7 },       /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_e,  0 },    0x0119 },       /* LATIN_SMALL_LETTER_E_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_g,  0 },    0x0123 },       /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_i,  0 },    0x012F },       /* LATIN_SMALL_LETTER_I_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_comma,      GDK_k,  0 },    0x0137 },       /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_l,  0 },    0x013C },       /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_n,  0 },    0x0146 },       /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_r,  0 },    0x0157 },       /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_s,  0 },    0x015F },       /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_comma,      GDK_u,  0 },    0x0173 },       /* LATIN_SMALL_LETTER_U_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_minus,      GDK_space,      0 },    0x007E },       /* TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_parenleft,  0 },    0x007B },       /* LEFT_CURLY_BRACKET */
-  { { GDK_Multi_key,   GDK_minus,      GDK_parenright, 0 },    0x007D },       /* RIGHT_CURLY_BRACKET */
-  { { GDK_Multi_key,   GDK_minus,      GDK_plus,       0 },    0x00B1 },       /* PLUSxMINUS_SIGN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_comma,      0 },    0x00AC },       /* NOT_SIGN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_minus,      0 },    0x00AD },       /* SOFT_HYPHEN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_colon,      0 },    0x00F7 },       /* DIVISION_SIGN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_A,  0 },    0x00C3 },       /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_D,  0 },    0x0110 },       /* LATIN_CAPITAL_LETTER_D_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_E,  0 },    0x0112 },       /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_minus,      GDK_I,  0 },    0x012A },       /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_minus,      GDK_L,  0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_N,  0 },    0x00D1 },       /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_O,  0 },    0x00D5 },       /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_U,  0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_Y,  0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_asciicircum,        0 },    0x00AF },       /* MACRON */
-  { { GDK_Multi_key,   GDK_minus,      GDK_a,  0 },    0x00E3 },       /* LATIN_SMALL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_d,  0 },    0x0111 },       /* LATIN_SMALL_LETTER_D_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_e,  0 },    0x0113 },       /* LATIN_SMALL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_minus,      GDK_i,  0 },    0x012B },       /* LATIN_SMALL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_minus,      GDK_l,  0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_minus,      GDK_n,  0 },    0x00F1 },       /* LATIN_SMALL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_o,  0 },    0x00F5 },       /* LATIN_SMALL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_minus,      GDK_u,  0 },    0x016B },       /* LATIN_SMALL_LETTER_U_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_minus,      GDK_y,  0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_period,     GDK_period,     0 },    0x02D9 },       /* DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_B,  0 },    0x1E02 },       /* LATIN_CAPITAL_LETTER_B_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_C,  0 },    0x010A },       /* LATIN_CAPITAL_LETTER_C_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_D,  0 },    0x1E0A },       /* LATIN_CAPITAL_LETTER_D_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_E,  0 },    0x0116 },       /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_F,  0 },    0x1E1E },       /* LATIN_CAPITAL_LETTER_F_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_G,  0 },    0x0120 },       /* LATIN_CAPITAL_LETTER_G_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_I,  0 },    0x0130 },       /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_M,  0 },    0x1E40 },       /* LATIN_CAPITAL_LETTER_M_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_P,  0 },    0x1E56 },       /* LATIN_CAPITAL_LETTER_P_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_S,  0 },    0x1E60 },       /* LATIN_CAPITAL_LETTER_S_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_T,  0 },    0x1E6A },       /* LATIN_CAPITAL_LETTER_T_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_asciicircum,        0 },    0x00B7 },       /* MIDDLE_DOT */
-  { { GDK_Multi_key,   GDK_period,     GDK_b,  0 },    0x1E03 },       /* LATIN_SMALL_LETTER_B_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_c,  0 },    0x010B },       /* LATIN_SMALL_LETTER_C_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_d,  0 },    0x1E0B },       /* LATIN_SMALL_LETTER_D_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_e,  0 },    0x0117 },       /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_f,  0 },    0x1E1F },       /* LATIN_SMALL_LETTER_F_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_g,  0 },    0x0121 },       /* LATIN_SMALL_LETTER_G_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_i,  0 },    0x0131 },       /* LATIN_SMALL_LETTER_DOTLESS_I */
-  { { GDK_Multi_key,   GDK_period,     GDK_m,  0 },    0x1E41 },       /* LATIN_SMALL_LETTER_M_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_p,  0 },    0x1E57 },       /* LATIN_SMALL_LETTER_P_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_s,  0 },    0x1E61 },       /* LATIN_SMALL_LETTER_S_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_period,     GDK_t,  0 },    0x1E6B },       /* LATIN_SMALL_LETTER_T_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_slash,      GDK_slash,      0 },    0x005C },       /* REVERSE_SOLIDUS */
-  { { GDK_Multi_key,   GDK_slash,      GDK_less,       0 },    0x005C },       /* REVERSE_SOLIDUS */
-  { { GDK_Multi_key,   GDK_slash,      GDK_C,  0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_slash,      GDK_O,  0 },    0x00D8 },       /* LATIN_CAPITAL_LETTER_O_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_slash,      GDK_T,  0 },    0x0166 },       /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_slash,      GDK_U,  0 },    0x00B5 },       /* MICRO_SIGN */
-  { { GDK_Multi_key,   GDK_slash,      GDK_asciicircum,        0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_Multi_key,   GDK_slash,      GDK_c,  0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_slash,      GDK_o,  0 },    0x00F8 },       /* LATIN_SMALL_LETTER_O_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_slash,      GDK_t,  0 },    0x0167 },       /* LATIN_SMALL_LETTER_T_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_slash,      GDK_u,  0 },    0x00B5 },       /* MICRO_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_asterisk,   0 },    0x00B0 },       /* DEGREE_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_C,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_S,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_X,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_asciicircum,        0 },    0x00B0 },       /* DEGREE_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_c,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_s,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_0,  GDK_x,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_1,  GDK_S,  0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_Multi_key,   GDK_1,  GDK_asciicircum,        0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_Multi_key,   GDK_1,  GDK_s,  0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_Multi_key,   GDK_2,  GDK_S,  0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_Multi_key,   GDK_2,  GDK_asciicircum,        0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_Multi_key,   GDK_2,  GDK_s,  0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_Multi_key,   GDK_3,  GDK_S,  0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_Multi_key,   GDK_3,  GDK_asciicircum,        0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_Multi_key,   GDK_3,  GDK_s,  0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_Multi_key,   GDK_colon,      GDK_minus,      0 },    0x00F7 },       /* DIVISION_SIGN */
-  { { GDK_Multi_key,   GDK_less,       GDK_slash,      0 },    0x005C },       /* REVERSE_SOLIDUS */
-  { { GDK_Multi_key,   GDK_less,       GDK_less,       0 },    0x00AB },       /* LEFTxPOINTING_DOUBLE_ANGLE_QUOTATION_MARK */
-  { { GDK_Multi_key,   GDK_less,       GDK_C,  0 },    0x010C },       /* LATIN_CAPITAL_LETTER_C_WITH_CARON */
-  { { GDK_Multi_key,   GDK_less,       GDK_S,  0 },    0x0160 },       /* LATIN_CAPITAL_LETTER_S_WITH_CARON */
-  { { GDK_Multi_key,   GDK_less,       GDK_Z,  0 },    0x017D },       /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */
-  { { GDK_Multi_key,   GDK_less,       GDK_c,  0 },    0x010D },       /* LATIN_SMALL_LETTER_C_WITH_CARON */
-  { { GDK_Multi_key,   GDK_less,       GDK_s,  0 },    0x0161 },       /* LATIN_SMALL_LETTER_S_WITH_CARON */
-  { { GDK_Multi_key,   GDK_less,       GDK_z,  0 },    0x017E },       /* LATIN_SMALL_LETTER_Z_WITH_CARON */
-  { { GDK_Multi_key,   GDK_equal,      GDK_C,  0 },    0x20AC },       /* EURO_SIGN */
-  { { GDK_Multi_key,   GDK_equal,      GDK_L,  0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_equal,      GDK_Y,  0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_equal,      GDK_e,  0 },    0x20AC },       /* EURO_SIGN */
-  { { GDK_Multi_key,   GDK_equal,      GDK_l,  0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_equal,      GDK_y,  0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_greater,    GDK_space,      0 },    0x005E },       /* CIRCUMFLEX_ACCENT */
-  { { GDK_Multi_key,   GDK_greater,    GDK_greater,    0 },    0x00BB },       /* RIGHTxPOINTING_DOUBLE_ANGLE_QUOTATION_MARK */
-  { { GDK_Multi_key,   GDK_greater,    GDK_A,  0 },    0x00C2 },       /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_E,  0 },    0x00CA },       /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_I,  0 },    0x00CE },       /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_O,  0 },    0x00D4 },       /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_U,  0 },    0x00DB },       /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_a,  0 },    0x00E2 },       /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_e,  0 },    0x00EA },       /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_i,  0 },    0x00EE },       /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_o,  0 },    0x00F4 },       /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_greater,    GDK_u,  0 },    0x00FB },       /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_question,   GDK_question,   0 },    0x00BF },       /* INVERTED_QUESTION_MARK */
-  { { GDK_Multi_key,   GDK_A,  GDK_quotedbl,   0 },    0x00C4 },       /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_A,  GDK_apostrophe, 0 },    0x00C1 },       /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_A,  GDK_asterisk,   0 },    0x00C5 },       /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_Multi_key,   GDK_A,  GDK_comma,      0 },    0x0104 },       /* LATIN_CAPITAL_LETTER_A_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_A,  GDK_minus,      0 },    0x00C3 },       /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_A,  GDK_greater,    0 },    0x00C2 },       /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_A,  GDK_A,  0 },    0x00C5 },       /* LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_Multi_key,   GDK_A,  GDK_E,  0 },    0x00C6 },       /* LATIN_CAPITAL_LETTER_AE */
-  { { GDK_Multi_key,   GDK_A,  GDK_asciicircum,        0 },    0x00C2 },       /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_A,  GDK_underscore, 0 },    0x00AA },       /* FEMININE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_A,  GDK_grave,      0 },    0x00C0 },       /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_A,  GDK_asciitilde, 0 },    0x00C3 },       /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_A,  GDK_diaeresis,  0 },    0x00C4 },       /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_A,  GDK_acute,      0 },    0x00C1 },       /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_B,  GDK_period,     0 },    0x1E02 },       /* LATIN_CAPITAL_LETTER_B_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_C,  GDK_comma,      0 },    0x00C7 },       /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_C,  GDK_period,     0 },    0x010A },       /* LATIN_CAPITAL_LETTER_C_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_C,  GDK_slash,      0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_C,  GDK_0,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_C,  GDK_less,       0 },    0x010C },       /* LATIN_CAPITAL_LETTER_C_WITH_CARON */
-  { { GDK_Multi_key,   GDK_C,  GDK_equal,      0 },    0x20AC },       /* EURO_SIGN */
-  { { GDK_Multi_key,   GDK_C,  GDK_O,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_C,  GDK_o,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_C,  GDK_bar,        0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_D,  GDK_minus,      0 },    0x0110 },       /* LATIN_CAPITAL_LETTER_D_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_D,  GDK_period,     0 },    0x1E0A },       /* LATIN_CAPITAL_LETTER_D_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_E,  GDK_quotedbl,   0 },    0x00CB },       /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_E,  GDK_apostrophe, 0 },    0x00C9 },       /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_E,  GDK_comma,      0 },    0x0118 },       /* LATIN_CAPITAL_LETTER_E_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_E,  GDK_minus,      0 },    0x0112 },       /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_E,  GDK_period,     0 },    0x0116 },       /* LATIN_CAPITAL_LETTER_E_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_E,  GDK_greater,    0 },    0x00CA },       /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_E,  GDK_asciicircum,        0 },    0x00CA },       /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_E,  GDK_underscore, 0 },    0x0112 },       /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_E,  GDK_grave,      0 },    0x00C8 },       /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_E,  GDK_diaeresis,  0 },    0x00CB },       /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_E,  GDK_acute,      0 },    0x00C9 },       /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_F,  GDK_period,     0 },    0x1E1E },       /* LATIN_CAPITAL_LETTER_F_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_G,  GDK_parenleft,  0 },    0x011E },       /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_G,  GDK_comma,      0 },    0x0122 },       /* LATIN_CAPITAL_LETTER_G_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_G,  GDK_period,     0 },    0x0120 },       /* LATIN_CAPITAL_LETTER_G_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_G,  GDK_U,  0 },    0x011E },       /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_G,  GDK_breve,      0 },    0x011E },       /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_I,  GDK_quotedbl,   0 },    0x00CF },       /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_I,  GDK_apostrophe, 0 },    0x00CD },       /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_I,  GDK_comma,      0 },    0x012E },       /* LATIN_CAPITAL_LETTER_I_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_I,  GDK_minus,      0 },    0x012A },       /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_I,  GDK_period,     0 },    0x0130 },       /* LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_I,  GDK_greater,    0 },    0x00CE },       /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_I,  GDK_asciicircum,        0 },    0x00CE },       /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_I,  GDK_underscore, 0 },    0x012A },       /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_I,  GDK_grave,      0 },    0x00CC },       /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_I,  GDK_asciitilde, 0 },    0x0128 },       /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_I,  GDK_diaeresis,  0 },    0x00CF },       /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_I,  GDK_acute,      0 },    0x00CD },       /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_K,  GDK_comma,      0 },    0x0136 },       /* LATIN_CAPITAL_LETTER_K_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_L,  GDK_comma,      0 },    0x013B },       /* LATIN_CAPITAL_LETTER_L_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_L,  GDK_minus,      0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_L,  GDK_equal,      0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_L,  GDK_V,  0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_Multi_key,   GDK_M,  GDK_period,     0 },    0x1E40 },       /* LATIN_CAPITAL_LETTER_M_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_N,  GDK_comma,      0 },    0x0145 },       /* LATIN_CAPITAL_LETTER_N_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_N,  GDK_minus,      0 },    0x00D1 },       /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_N,  GDK_G,  0 },    0x014A },       /* LATIN_CAPITAL_LETTER_ENG */
-  { { GDK_Multi_key,   GDK_N,  GDK_asciitilde, 0 },    0x00D1 },       /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_O,  GDK_quotedbl,   0 },    0x00D6 },       /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_O,  GDK_apostrophe, 0 },    0x00D3 },       /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_O,  GDK_minus,      0 },    0x00D5 },       /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_O,  GDK_slash,      0 },    0x00D8 },       /* LATIN_CAPITAL_LETTER_O_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_O,  GDK_greater,    0 },    0x00D4 },       /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_O,  GDK_C,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_O,  GDK_E,  0 },    0x0152 },       /* LATIN_CAPITAL_LIGATURE_OE */
-  { { GDK_Multi_key,   GDK_O,  GDK_R,  0 },    0x00AE },       /* REGISTERED_SIGN */
-  { { GDK_Multi_key,   GDK_O,  GDK_S,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_O,  GDK_X,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_O,  GDK_asciicircum,        0 },    0x00D4 },       /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_O,  GDK_underscore, 0 },    0x00BA },       /* MASCULINE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_O,  GDK_grave,      0 },    0x00D2 },       /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_O,  GDK_c,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_O,  GDK_x,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_O,  GDK_asciitilde, 0 },    0x00D5 },       /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_O,  GDK_diaeresis,  0 },    0x00D6 },       /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_O,  GDK_acute,      0 },    0x00D3 },       /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_P,  GDK_exclam,     0 },    0x00B6 },       /* PILCROW_SIGN */
-  { { GDK_Multi_key,   GDK_P,  GDK_period,     0 },    0x1E56 },       /* LATIN_CAPITAL_LETTER_P_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_R,  GDK_comma,      0 },    0x0156 },       /* LATIN_CAPITAL_LETTER_R_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_R,  GDK_O,  0 },    0x00AE },       /* REGISTERED_SIGN */
-  { { GDK_Multi_key,   GDK_S,  GDK_exclam,     0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_S,  GDK_comma,      0 },    0x015E },       /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_S,  GDK_period,     0 },    0x1E60 },       /* LATIN_CAPITAL_LETTER_S_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_S,  GDK_0,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_S,  GDK_1,  0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_Multi_key,   GDK_S,  GDK_2,  0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_Multi_key,   GDK_S,  GDK_3,  0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_Multi_key,   GDK_S,  GDK_less,       0 },    0x0160 },       /* LATIN_CAPITAL_LETTER_S_WITH_CARON */
-  { { GDK_Multi_key,   GDK_S,  GDK_O,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_S,  GDK_cedilla,    0 },    0x015E },       /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_T,  GDK_minus,      0 },    0x0166 },       /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_T,  GDK_period,     0 },    0x1E6A },       /* LATIN_CAPITAL_LETTER_T_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_T,  GDK_slash,      0 },    0x0166 },       /* LATIN_CAPITAL_LETTER_T_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_T,  GDK_H,  0 },    0x00DE },       /* LATIN_CAPITAL_LETTER_THORN */
-  { { GDK_Multi_key,   GDK_U,  GDK_quotedbl,   0 },    0x00DC },       /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_U,  GDK_apostrophe, 0 },    0x00DA },       /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_U,  GDK_comma,      0 },    0x0172 },       /* LATIN_CAPITAL_LETTER_U_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_U,  GDK_minus,      0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_U,  GDK_slash,      0 },    0x00B5 },       /* MICRO_SIGN */
-  { { GDK_Multi_key,   GDK_U,  GDK_greater,    0 },    0x00DB },       /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_U,  GDK_asciicircum,        0 },    0x00DB },       /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_U,  GDK_underscore, 0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_U,  GDK_grave,      0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_U,  GDK_asciitilde, 0 },    0x0168 },       /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_U,  GDK_diaeresis,  0 },    0x00DC },       /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_U,  GDK_acute,      0 },    0x00DA },       /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_V,  GDK_L,  0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_Multi_key,   GDK_W,  GDK_asciicircum,        0 },    0x0174 },       /* LATIN_CAPITAL_LETTER_W_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_X,  GDK_0,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_X,  GDK_O,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_X,  GDK_o,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_Y,  GDK_quotedbl,   0 },    0x0178 },       /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_Y,  GDK_apostrophe, 0 },    0x00DD },       /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_Y,  GDK_minus,      0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_Y,  GDK_equal,      0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_Y,  GDK_asciicircum,        0 },    0x0176 },       /* LATIN_CAPITAL_LETTER_Y_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_Y,  GDK_diaeresis,  0 },    0x0178 },       /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_Y,  GDK_acute,      0 },    0x00DD },       /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_Z,  GDK_less,       0 },    0x017D },       /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_space,      0 },    0x005E },       /* CIRCUMFLEX_ACCENT */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_minus,      0 },    0x00AF },       /* MACRON */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_period,     0 },    0x00B7 },       /* MIDDLE_DOT */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_slash,      0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_0,  0 },    0x00B0 },       /* DEGREE_SIGN */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_1,  0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_2,  0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_3,  0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_A,  0 },    0x00C2 },       /* LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_E,  0 },    0x00CA },       /* LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_I,  0 },    0x00CE },       /* LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_O,  0 },    0x00D4 },       /* LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_U,  0 },    0x00DB },       /* LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_W,  0 },    0x0174 },       /* LATIN_CAPITAL_LETTER_W_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_Y,  0 },    0x0176 },       /* LATIN_CAPITAL_LETTER_Y_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_underscore, 0 },    0x00AF },       /* MACRON */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_a,  0 },    0x00E2 },       /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_e,  0 },    0x00EA },       /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_i,  0 },    0x00EE },       /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_o,  0 },    0x00F4 },       /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_u,  0 },    0x00FB },       /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_w,  0 },    0x0175 },       /* LATIN_SMALL_LETTER_W_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_asciicircum,        GDK_y,  0 },    0x0177 },       /* LATIN_SMALL_LETTER_Y_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_underscore, GDK_A,  0 },    0x00AA },       /* FEMININE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_underscore, GDK_E,  0 },    0x0112 },       /* LATIN_CAPITAL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_underscore, GDK_I,  0 },    0x012A },       /* LATIN_CAPITAL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_underscore, GDK_O,  0 },    0x00BA },       /* MASCULINE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_underscore, GDK_U,  0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_underscore, GDK_asciicircum,        0 },    0x00AF },       /* MACRON */
-  { { GDK_Multi_key,   GDK_underscore, GDK_underscore, 0 },    0x00AF },       /* MACRON */
-  { { GDK_Multi_key,   GDK_underscore, GDK_a,  0 },    0x00AA },       /* FEMININE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_underscore, GDK_e,  0 },    0x0113 },       /* LATIN_SMALL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_underscore, GDK_i,  0 },    0x012B },       /* LATIN_SMALL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_underscore, GDK_o,  0 },    0x00BA },       /* MASCULINE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_underscore, GDK_u,  0 },    0x016B },       /* LATIN_SMALL_LETTER_U_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_grave,      GDK_space,      0 },    0x0060 },       /* GRAVE_ACCENT */
-  { { GDK_Multi_key,   GDK_grave,      GDK_A,  0 },    0x00C0 },       /* LATIN_CAPITAL_LETTER_A_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_E,  0 },    0x00C8 },       /* LATIN_CAPITAL_LETTER_E_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_I,  0 },    0x00CC },       /* LATIN_CAPITAL_LETTER_I_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_O,  0 },    0x00D2 },       /* LATIN_CAPITAL_LETTER_O_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_U,  0 },    0x00D9 },       /* LATIN_CAPITAL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_a,  0 },    0x00E0 },       /* LATIN_SMALL_LETTER_A_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_e,  0 },    0x00E8 },       /* LATIN_SMALL_LETTER_E_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_i,  0 },    0x00EC },       /* LATIN_SMALL_LETTER_I_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_o,  0 },    0x00F2 },       /* LATIN_SMALL_LETTER_O_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_grave,      GDK_u,  0 },    0x00F9 },       /* LATIN_SMALL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_a,  GDK_quotedbl,   0 },    0x00E4 },       /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_a,  GDK_apostrophe, 0 },    0x00E1 },       /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_a,  GDK_asterisk,   0 },    0x00E5 },       /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_Multi_key,   GDK_a,  GDK_comma,      0 },    0x0105 },       /* LATIN_SMALL_LETTER_A_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_a,  GDK_minus,      0 },    0x00E3 },       /* LATIN_SMALL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_a,  GDK_greater,    0 },    0x00E2 },       /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_a,  GDK_asciicircum,        0 },    0x00E2 },       /* LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_a,  GDK_underscore, 0 },    0x00AA },       /* FEMININE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_a,  GDK_grave,      0 },    0x00E0 },       /* LATIN_SMALL_LETTER_A_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_a,  GDK_a,  0 },    0x00E5 },       /* LATIN_SMALL_LETTER_A_WITH_RING_ABOVE */
-  { { GDK_Multi_key,   GDK_a,  GDK_e,  0 },    0x00E6 },       /* LATIN_SMALL_LETTER_AE */
-  { { GDK_Multi_key,   GDK_a,  GDK_asciitilde, 0 },    0x00E3 },       /* LATIN_SMALL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_a,  GDK_diaeresis,  0 },    0x00E4 },       /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_a,  GDK_acute,      0 },    0x00E1 },       /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_b,  GDK_period,     0 },    0x1E03 },       /* LATIN_SMALL_LETTER_B_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_c,  GDK_comma,      0 },    0x00E7 },       /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_c,  GDK_period,     0 },    0x010B },       /* LATIN_SMALL_LETTER_C_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_c,  GDK_slash,      0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_c,  GDK_0,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_c,  GDK_less,       0 },    0x010D },       /* LATIN_SMALL_LETTER_C_WITH_CARON */
-  { { GDK_Multi_key,   GDK_c,  GDK_O,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_c,  GDK_o,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_c,  GDK_bar,        0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_d,  GDK_minus,      0 },    0x0111 },       /* LATIN_SMALL_LETTER_D_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_d,  GDK_period,     0 },    0x1E0B },       /* LATIN_SMALL_LETTER_D_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_e,  GDK_quotedbl,   0 },    0x00EB },       /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_e,  GDK_apostrophe, 0 },    0x00E9 },       /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_e,  GDK_comma,      0 },    0x0119 },       /* LATIN_SMALL_LETTER_E_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_e,  GDK_minus,      0 },    0x0113 },       /* LATIN_SMALL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_e,  GDK_period,     0 },    0x0117 },       /* LATIN_SMALL_LETTER_E_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_e,  GDK_equal,      0 },    0x20AC },       /* EURO_SIGN */
-  { { GDK_Multi_key,   GDK_e,  GDK_greater,    0 },    0x00EA },       /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_e,  GDK_asciicircum,        0 },    0x00EA },       /* LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_e,  GDK_underscore, 0 },    0x0113 },       /* LATIN_SMALL_LETTER_E_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_e,  GDK_grave,      0 },    0x00E8 },       /* LATIN_SMALL_LETTER_E_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_e,  GDK_diaeresis,  0 },    0x00EB },       /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_e,  GDK_acute,      0 },    0x00E9 },       /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_f,  GDK_period,     0 },    0x1E1F },       /* LATIN_SMALL_LETTER_F_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_g,  GDK_parenleft,  0 },    0x011F },       /* LATIN_SMALL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_g,  GDK_comma,      0 },    0x0123 },       /* LATIN_SMALL_LETTER_G_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_g,  GDK_period,     0 },    0x0121 },       /* LATIN_SMALL_LETTER_G_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_g,  GDK_U,  0 },    0x011F },       /* LATIN_SMALL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_g,  GDK_breve,      0 },    0x011F },       /* LATIN_SMALL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_i,  GDK_quotedbl,   0 },    0x00EF },       /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_i,  GDK_apostrophe, 0 },    0x00ED },       /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_i,  GDK_comma,      0 },    0x012F },       /* LATIN_SMALL_LETTER_I_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_i,  GDK_minus,      0 },    0x012B },       /* LATIN_SMALL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_i,  GDK_period,     0 },    0x0131 },       /* LATIN_SMALL_LETTER_DOTLESS_I */
-  { { GDK_Multi_key,   GDK_i,  GDK_greater,    0 },    0x00EE },       /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_i,  GDK_asciicircum,        0 },    0x00EE },       /* LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_i,  GDK_underscore, 0 },    0x012B },       /* LATIN_SMALL_LETTER_I_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_i,  GDK_grave,      0 },    0x00EC },       /* LATIN_SMALL_LETTER_I_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_i,  GDK_asciitilde, 0 },    0x0129 },       /* LATIN_SMALL_LETTER_I_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_i,  GDK_diaeresis,  0 },    0x00EF },       /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_i,  GDK_acute,      0 },    0x00ED },       /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_k,  GDK_comma,      0 },    0x0137 },       /* LATIN_SMALL_LETTER_K_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_k,  GDK_k,  0 },    0x0138 },       /* LATIN_SMALL_LETTER_KRA */
-  { { GDK_Multi_key,   GDK_l,  GDK_comma,      0 },    0x013C },       /* LATIN_SMALL_LETTER_L_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_l,  GDK_minus,      0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_l,  GDK_equal,      0 },    0x00A3 },       /* POUND_SIGN */
-  { { GDK_Multi_key,   GDK_l,  GDK_v,  0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_Multi_key,   GDK_m,  GDK_period,     0 },    0x1E41 },       /* LATIN_SMALL_LETTER_M_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_n,  GDK_comma,      0 },    0x0146 },       /* LATIN_SMALL_LETTER_N_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_n,  GDK_minus,      0 },    0x00F1 },       /* LATIN_SMALL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_n,  GDK_g,  0 },    0x014B },       /* LATIN_SMALL_LETTER_ENG */
-  { { GDK_Multi_key,   GDK_n,  GDK_asciitilde, 0 },    0x00F1 },       /* LATIN_SMALL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_o,  GDK_quotedbl,   0 },    0x00F6 },       /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_o,  GDK_apostrophe, 0 },    0x00F3 },       /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_o,  GDK_minus,      0 },    0x00F5 },       /* LATIN_SMALL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_o,  GDK_slash,      0 },    0x00F8 },       /* LATIN_SMALL_LETTER_O_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_o,  GDK_greater,    0 },    0x00F4 },       /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_o,  GDK_C,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_o,  GDK_X,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_o,  GDK_asciicircum,        0 },    0x00F4 },       /* LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_o,  GDK_underscore, 0 },    0x00BA },       /* MASCULINE_ORDINAL_INDICATOR */
-  { { GDK_Multi_key,   GDK_o,  GDK_grave,      0 },    0x00F2 },       /* LATIN_SMALL_LETTER_O_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_o,  GDK_c,  0 },    0x00A9 },       /* COPYRIGHT_SIGN */
-  { { GDK_Multi_key,   GDK_o,  GDK_e,  0 },    0x0153 },       /* LATIN_SMALL_LIGATURE_OE */
-  { { GDK_Multi_key,   GDK_o,  GDK_s,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_o,  GDK_x,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_o,  GDK_asciitilde, 0 },    0x00F5 },       /* LATIN_SMALL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_o,  GDK_diaeresis,  0 },    0x00F6 },       /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_o,  GDK_acute,      0 },    0x00F3 },       /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_p,  GDK_exclam,     0 },    0x00B6 },       /* PILCROW_SIGN */
-  { { GDK_Multi_key,   GDK_p,  GDK_period,     0 },    0x1E57 },       /* LATIN_SMALL_LETTER_P_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_r,  GDK_comma,      0 },    0x0157 },       /* LATIN_SMALL_LETTER_R_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_s,  GDK_exclam,     0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_s,  GDK_comma,      0 },    0x015F },       /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_s,  GDK_period,     0 },    0x1E61 },       /* LATIN_SMALL_LETTER_S_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_s,  GDK_0,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_s,  GDK_1,  0 },    0x00B9 },       /* SUPERSCRIPT_ONE */
-  { { GDK_Multi_key,   GDK_s,  GDK_2,  0 },    0x00B2 },       /* SUPERSCRIPT_TWO */
-  { { GDK_Multi_key,   GDK_s,  GDK_3,  0 },    0x00B3 },       /* SUPERSCRIPT_THREE */
-  { { GDK_Multi_key,   GDK_s,  GDK_less,       0 },    0x0161 },       /* LATIN_SMALL_LETTER_S_WITH_CARON */
-  { { GDK_Multi_key,   GDK_s,  GDK_o,  0 },    0x00A7 },       /* SECTION_SIGN */
-  { { GDK_Multi_key,   GDK_s,  GDK_s,  0 },    0x00DF },       /* LATIN_SMALL_LETTER_SHARP_S */
-  { { GDK_Multi_key,   GDK_s,  GDK_cedilla,    0 },    0x015F },       /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_t,  GDK_minus,      0 },    0x0167 },       /* LATIN_SMALL_LETTER_T_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_t,  GDK_period,     0 },    0x1E6B },       /* LATIN_SMALL_LETTER_T_WITH_DOT_ABOVE */
-  { { GDK_Multi_key,   GDK_t,  GDK_slash,      0 },    0x0167 },       /* LATIN_SMALL_LETTER_T_WITH_STROKE */
-  { { GDK_Multi_key,   GDK_t,  GDK_h,  0 },    0x00FE },       /* LATIN_SMALL_LETTER_THORN */
-  { { GDK_Multi_key,   GDK_u,  GDK_quotedbl,   0 },    0x00FC },       /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_u,  GDK_apostrophe, 0 },    0x00FA },       /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_u,  GDK_comma,      0 },    0x0173 },       /* LATIN_SMALL_LETTER_U_WITH_OGONEK */
-  { { GDK_Multi_key,   GDK_u,  GDK_minus,      0 },    0x016B },       /* LATIN_SMALL_LETTER_U_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_u,  GDK_slash,      0 },    0x00B5 },       /* MICRO_SIGN */
-  { { GDK_Multi_key,   GDK_u,  GDK_greater,    0 },    0x00FB },       /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_u,  GDK_asciicircum,        0 },    0x00FB },       /* LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_u,  GDK_underscore, 0 },    0x016B },       /* LATIN_SMALL_LETTER_U_WITH_MACRON */
-  { { GDK_Multi_key,   GDK_u,  GDK_grave,      0 },    0x00F9 },       /* LATIN_SMALL_LETTER_U_WITH_GRAVE */
-  { { GDK_Multi_key,   GDK_u,  GDK_asciitilde, 0 },    0x0169 },       /* LATIN_SMALL_LETTER_U_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_u,  GDK_diaeresis,  0 },    0x00FC },       /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_u,  GDK_acute,      0 },    0x00FA },       /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_v,  GDK_Z,  0 },    0x017D },       /* LATIN_CAPITAL_LETTER_Z_WITH_CARON */
-  { { GDK_Multi_key,   GDK_v,  GDK_l,  0 },    0x007C },       /* VERTICAL_LINE */
-  { { GDK_Multi_key,   GDK_v,  GDK_z,  0 },    0x017E },       /* LATIN_SMALL_LETTER_Z_WITH_CARON */
-  { { GDK_Multi_key,   GDK_w,  GDK_asciicircum,        0 },    0x0175 },       /* LATIN_SMALL_LETTER_W_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_x,  GDK_0,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_x,  GDK_O,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_x,  GDK_o,  0 },    0x00A4 },       /* CURRENCY_SIGN */
-  { { GDK_Multi_key,   GDK_x,  GDK_x,  0 },    0x00D7 },       /* MULTIPLICATION_SIGN */
-  { { GDK_Multi_key,   GDK_y,  GDK_quotedbl,   0 },    0x00FF },       /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_y,  GDK_apostrophe, 0 },    0x00FD },       /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_y,  GDK_minus,      0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_y,  GDK_equal,      0 },    0x00A5 },       /* YEN_SIGN */
-  { { GDK_Multi_key,   GDK_y,  GDK_asciicircum,        0 },    0x0177 },       /* LATIN_SMALL_LETTER_Y_WITH_CIRCUMFLEX */
-  { { GDK_Multi_key,   GDK_y,  GDK_diaeresis,  0 },    0x00FF },       /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_y,  GDK_acute,      0 },    0x00FD },       /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_z,  GDK_less,       0 },    0x017E },       /* LATIN_SMALL_LETTER_Z_WITH_CARON */
-  { { GDK_Multi_key,   GDK_bar,        GDK_C,  0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_bar,        GDK_c,  0 },    0x00A2 },       /* CENT_SIGN */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_space,      0 },    0x007E },       /* TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_A,  0 },    0x00C3 },       /* LATIN_CAPITAL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_I,  0 },    0x0128 },       /* LATIN_CAPITAL_LETTER_I_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_N,  0 },    0x00D1 },       /* LATIN_CAPITAL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_O,  0 },    0x00D5 },       /* LATIN_CAPITAL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_U,  0 },    0x0168 },       /* LATIN_CAPITAL_LETTER_U_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_a,  0 },    0x00E3 },       /* LATIN_SMALL_LETTER_A_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_i,  0 },    0x0129 },       /* LATIN_SMALL_LETTER_I_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_n,  0 },    0x00F1 },       /* LATIN_SMALL_LETTER_N_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_o,  0 },    0x00F5 },       /* LATIN_SMALL_LETTER_O_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_asciitilde, GDK_u,  0 },    0x0169 },       /* LATIN_SMALL_LETTER_U_WITH_TILDE */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_A,  0 },    0x00C4 },       /* LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_E,  0 },    0x00CB },       /* LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_I,  0 },    0x00CF },       /* LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_O,  0 },    0x00D6 },       /* LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_U,  0 },    0x00DC },       /* LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_Y,  0 },    0x0178 },       /* LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_a,  0 },    0x00E4 },       /* LATIN_SMALL_LETTER_A_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_e,  0 },    0x00EB },       /* LATIN_SMALL_LETTER_E_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_i,  0 },    0x00EF },       /* LATIN_SMALL_LETTER_I_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_o,  0 },    0x00F6 },       /* LATIN_SMALL_LETTER_O_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_u,  0 },    0x00FC },       /* LATIN_SMALL_LETTER_U_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_diaeresis,  GDK_y,  0 },    0x00FF },       /* LATIN_SMALL_LETTER_Y_WITH_DIAERESIS */
-  { { GDK_Multi_key,   GDK_acute,      GDK_A,  0 },    0x00C1 },       /* LATIN_CAPITAL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_E,  0 },    0x00C9 },       /* LATIN_CAPITAL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_I,  0 },    0x00CD },       /* LATIN_CAPITAL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_O,  0 },    0x00D3 },       /* LATIN_CAPITAL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_U,  0 },    0x00DA },       /* LATIN_CAPITAL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_Y,  0 },    0x00DD },       /* LATIN_CAPITAL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_a,  0 },    0x00E1 },       /* LATIN_SMALL_LETTER_A_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_e,  0 },    0x00E9 },       /* LATIN_SMALL_LETTER_E_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_i,  0 },    0x00ED },       /* LATIN_SMALL_LETTER_I_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_o,  0 },    0x00F3 },       /* LATIN_SMALL_LETTER_O_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_u,  0 },    0x00FA },       /* LATIN_SMALL_LETTER_U_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_acute,      GDK_y,  0 },    0x00FD },       /* LATIN_SMALL_LETTER_Y_WITH_ACUTE */
-  { { GDK_Multi_key,   GDK_cedilla,    GDK_S,  0 },    0x015E },       /* LATIN_CAPITAL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_cedilla,    GDK_s,  0 },    0x015F },       /* LATIN_SMALL_LETTER_S_WITH_CEDILLA */
-  { { GDK_Multi_key,   GDK_breve,      GDK_G,  0 },    0x011E },       /* LATIN_CAPITAL_LETTER_G_WITH_BREVE */
-  { { GDK_Multi_key,   GDK_breve,      GDK_g,  0 },    0x011F },       /* LATIN_SMALL_LETTER_G_WITH_BREVE */
+  guint          in_hex_sequence : 1;
+  guint          modifiers_dropped : 1;
 };
 
-guint16 gtk_compose_ignore[] = {
-  GDK_Shift_L,
-  GDK_Shift_R,
-  GDK_Control_L,
-  GDK_Control_R,
-  GDK_Caps_Lock,
-  GDK_Shift_Lock,
-  GDK_Meta_L,
-  GDK_Meta_R,
-  GDK_Alt_L,
-  GDK_Alt_R,
-  GDK_Super_L,
-  GDK_Super_R,
-  GDK_Hyper_L,
-  GDK_Hyper_R 
+struct _GtkComposeTable 
+{
+  const guint16 *data;
+  gint max_seq_len;
+  gint n_seqs;
 };
 
-static void     gtk_im_context_simple_class_init (GtkIMContextSimpleClass *class);
-static void     gtk_im_context_simple_init (GtkIMContextSimple *im_context_simple);
+struct _GtkComposeTableCompact
+{
+  const guint16 *data;
+  gint max_seq_len;
+  gint n_index_size;
+  gint n_index_stride;
+};
 
-static gboolean gtk_im_context_simple_filter_keypress (GtkIMContext *context,
-                                                      GdkEventKey  *key);
+/* This file contains the table of the compose sequences,
+ * static const guint16 gtk_compose_seqs_compact[] = {}
+ * It is generated from the compose-parse.py script.
+ */
+#include "gtkimcontextsimpleseqs.h"
 
-GtkType
-gtk_im_context_simple_get_type (void)
-{
-  static GtkType im_context_simple_type = 0;
+/* From the values below, the value 24 means the number of different first keysyms
+ * that exist in the Compose file (from Xorg). When running compose-parse.py without
+ * parameters, you get the count that you can put here. Needed when updating the
+ * gtkimcontextsimpleseqs.h header file (contains the compose sequences).
+ */
+static const GtkComposeTableCompact gtk_compose_table_compact = {
+  gtk_compose_seqs_compact,
+  5,
+  24,
+  6
+};
 
-  if (!im_context_simple_type)
-    {
-      static const GtkTypeInfo im_context_simple_info =
-      {
-       "GtkIMContextSimple",
-       sizeof (GtkIMContextSimple),
-       sizeof (GtkIMContextSimpleClass),
-       (GtkClassInitFunc) gtk_im_context_simple_class_init,
-       (GtkObjectInitFunc) gtk_im_context_simple_init,
-       /* reserved_1 */ NULL,
-        /* reserved_2 */ NULL,
-        (GtkClassInitFunc) NULL,
-      };
+static const guint16 gtk_compose_ignore[] = {
+  GDK_KEY_Shift_L,
+  GDK_KEY_Shift_R,
+  GDK_KEY_Control_L,
+  GDK_KEY_Control_R,
+  GDK_KEY_Caps_Lock,
+  GDK_KEY_Shift_Lock,
+  GDK_KEY_Meta_L,
+  GDK_KEY_Meta_R,
+  GDK_KEY_Alt_L,
+  GDK_KEY_Alt_R,
+  GDK_KEY_Super_L,
+  GDK_KEY_Super_R,
+  GDK_KEY_Hyper_L,
+  GDK_KEY_Hyper_R,
+  GDK_KEY_Mode_switch,
+  GDK_KEY_ISO_Level3_Shift
+};
 
-      im_context_simple_type = gtk_type_unique (GTK_TYPE_IM_CONTEXT, &im_context_simple_info);
-    }
+static void     gtk_im_context_simple_finalize           (GObject                  *obj);
+static gboolean gtk_im_context_simple_filter_keypress    (GtkIMContext             *context,
+                                                         GdkEventKey              *key);
+static void     gtk_im_context_simple_reset              (GtkIMContext             *context);
+static void     gtk_im_context_simple_get_preedit_string (GtkIMContext             *context,
+                                                         gchar                   **str,
+                                                         PangoAttrList           **attrs,
+                                                         gint                     *cursor_pos);
 
-  return im_context_simple_type;
-}
+G_DEFINE_TYPE (GtkIMContextSimple, gtk_im_context_simple, GTK_TYPE_IM_CONTEXT)
 
 static void
 gtk_im_context_simple_class_init (GtkIMContextSimpleClass *class)
 {
   GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);
-  
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
   im_context_class->filter_keypress = gtk_im_context_simple_filter_keypress;
+  im_context_class->reset = gtk_im_context_simple_reset;
+  im_context_class->get_preedit_string = gtk_im_context_simple_get_preedit_string;
+  gobject_class->finalize = gtk_im_context_simple_finalize;
+
+  g_type_class_add_private (class, sizeof (GtkIMContextSimplePrivate));
 }
 
 static void
 gtk_im_context_simple_init (GtkIMContextSimple *im_context_simple)
 {
+  im_context_simple->priv = G_TYPE_INSTANCE_GET_PRIVATE (im_context_simple,
+                                                         GTK_TYPE_IM_CONTEXT_SIMPLE,
+                                                         GtkIMContextSimplePrivate);
 }
 
-GtkIMContext *
-gtk_im_context_simple_new (void)
+static void
+gtk_im_context_simple_finalize (GObject *obj)
 {
-  return GTK_IM_CONTEXT (gtk_type_new (GTK_TYPE_IM_CONTEXT_SIMPLE));
+  GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (obj);
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+
+  if (priv->tables)
+    {
+      g_slist_foreach (priv->tables, (GFunc)g_free, NULL);
+      g_slist_free (priv->tables);
+
+      priv->tables = NULL;
+    }
+
+  G_OBJECT_CLASS (gtk_im_context_simple_parent_class)->finalize (obj);
 }
 
 /**
- * unicode_guchar4_to_utf8:
- * @ch: a ISO10646 character code
- * @out: output buffer, must have at least 6 bytes of space.
- * 
- * Convert a single character to utf8
+ * gtk_im_context_simple_new:
  * 
- * Return value: number of bytes written
+ * Creates a new #GtkIMContextSimple.
+ *
+ * Returns: a new #GtkIMContextSimple.
  **/
+GtkIMContext *
+gtk_im_context_simple_new (void)
+{
+  return g_object_new (GTK_TYPE_IM_CONTEXT_SIMPLE, NULL);
+}
+
+static void
+gtk_im_context_simple_commit_char (GtkIMContext *context,
+                                  gunichar ch)
+{
+  GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+  gchar buf[10];
+  gint len;
+
+  g_return_if_fail (g_unichar_validate (ch));
+
+  len = g_unichar_to_utf8 (ch, buf);
+  buf[len] = '\0';
+
+  if (priv->tentative_match || priv->in_hex_sequence)
+    {
+      priv->in_hex_sequence = FALSE;
+      priv->tentative_match = 0;
+      priv->tentative_match_len = 0;
+      g_signal_emit_by_name (context_simple, "preedit-changed");
+      g_signal_emit_by_name (context_simple, "preedit-end");
+    }
+
+  g_signal_emit_by_name (context, "commit", &buf);
+}
+
 static int
-ucs4_to_utf8 (unicode_char_t c, char *outbuf)
+compare_seq_index (const void *key, const void *value)
 {
-  size_t len = 0;
-  int first;
-  int i;
+  const guint *keysyms = key;
+  const guint16 *seq = value;
+
+  if (keysyms[0] < seq[0])
+    return -1;
+  else if (keysyms[0] > seq[0])
+    return 1;
+
+  return 0;
+}
+
+static int
+compare_seq (const void *key, const void *value)
+{
+  int i = 0;
+  const guint *keysyms = key;
+  const guint16 *seq = value;
 
-  if (c < 0x80)
+  while (keysyms[i])
     {
-      first = 0;
-      len = 1;
+      if (keysyms[i] < seq[i])
+       return -1;
+      else if (keysyms[i] > seq[i])
+       return 1;
+
+      i++;
     }
-  else if (c < 0x800)
+
+  return 0;
+}
+
+static gboolean
+check_table (GtkIMContextSimple    *context_simple,
+            const GtkComposeTable *table,
+            gint                   n_compose)
+{
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+  gint row_stride = table->max_seq_len + 2; 
+  guint16 *seq; 
+  
+  /* Will never match, if the sequence in the compose buffer is longer
+   * than the sequences in the table.  Further, compare_seq (key, val)
+   * will overrun val if key is longer than val. */
+  if (n_compose > table->max_seq_len)
+    return FALSE;
+  
+  seq = bsearch (priv->compose_buffer,
+                table->data, table->n_seqs,
+                sizeof (guint16) *  row_stride, 
+                compare_seq);
+
+  if (seq)
     {
-      first = 0xc0;
-      len = 2;
+      guint16 *prev_seq;
+
+      /* Back up to the first sequence that matches to make sure
+       * we find the exact match if there is one.
+       */
+      while (seq > table->data)
+       {
+         prev_seq = seq - row_stride;
+         if (compare_seq (priv->compose_buffer, prev_seq) != 0)
+           break;
+         seq = prev_seq;
+       }
+      
+      if (n_compose == table->max_seq_len ||
+         seq[n_compose] == 0) /* complete sequence */
+       {
+         guint16 *next_seq;
+         gunichar value = 
+           0x10000 * seq[table->max_seq_len] + seq[table->max_seq_len + 1];
+
+         /* We found a tentative match. See if there are any longer
+          * sequences containing this subsequence
+          */
+         next_seq = seq + row_stride;
+         if (next_seq < table->data + row_stride * table->n_seqs)
+           {
+             if (compare_seq (priv->compose_buffer, next_seq) == 0)
+               {
+                 priv->tentative_match = value;
+                 priv->tentative_match_len = n_compose;
+
+                 g_signal_emit_by_name (context_simple, "preedit-changed");
+
+                 return TRUE;
+               }
+           }
+
+         gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple), value);
+         priv->compose_buffer[0] = 0;
+       }
+      
+      return TRUE;
     }
-  else if (c < 0x10000)
+
+  return FALSE;
+}
+
+/* Checks if a keysym is a dead key. Dead key keysym values are defined in
+ * ../gdk/gdkkeysyms.h and the first is GDK_KEY_dead_grave. As X.Org is updated,
+ * more dead keys are added and we need to update the upper limit.
+ * Currently, the upper limit is GDK_KEY_dead_dasia+1. The +1 has to do with
+ * a temporary issue in the X.Org header files.
+ * In future versions it will be just the keysym (no +1).
+ */
+#define IS_DEAD_KEY(k) \
+    ((k) >= GDK_KEY_dead_grave && (k) <= (GDK_KEY_dead_dasia+1))
+
+#ifdef GDK_WINDOWING_WIN32
+
+/* On Windows, user expectation is that typing a dead accent followed
+ * by space will input the corresponding spacing character. The X
+ * compose tables are different for dead acute and diaeresis, which
+ * when followed by space produce a plain ASCII apostrophe and double
+ * quote respectively. So special-case those.
+ */
+
+static gboolean
+check_win32_special_cases (GtkIMContextSimple    *context_simple,
+                          gint                   n_compose)
+{
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+  if (n_compose == 2 &&
+      priv->compose_buffer[1] == GDK_KEY_space)
     {
-      first = 0xe0;
-      len = 3;
+      gunichar value = 0;
+
+      switch (priv->compose_buffer[0])
+       {
+       case GDK_KEY_dead_acute:
+         value = 0x00B4; break;
+       case GDK_KEY_dead_diaeresis:
+         value = 0x00A8; break;
+       }
+      if (value > 0)
+       {
+         gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple), value);
+         priv->compose_buffer[0] = 0;
+
+         GTK_NOTE (MISC, g_print ("win32: U+%04X\n", value));
+         return TRUE;
+       }
     }
-   else if (c < 0x200000)
+  return FALSE;
+}
+
+static void
+check_win32_special_case_after_compact_match (GtkIMContextSimple    *context_simple,
+                                             gint                   n_compose,
+                                             guint                  value)
+{
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+
+  /* On Windows user expectation is that typing two dead accents will input
+   * two corresponding spacing accents.
+   */
+  if (n_compose == 2 &&
+      priv->compose_buffer[0] == priv->compose_buffer[1] &&
+      IS_DEAD_KEY (priv->compose_buffer[0]))
     {
-      first = 0xf0;
-      len = 4;
+      gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple), value);
+      GTK_NOTE (MISC, g_print ("win32: U+%04X ", value));
     }
-  else if (c < 0x4000000)
+}
+
+#endif
+
+#ifdef GDK_WINDOWING_QUARTZ
+
+static gboolean
+check_quartz_special_cases (GtkIMContextSimple *context_simple,
+                            gint                n_compose)
+{
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+  guint value = 0;
+
+  if (n_compose == 2)
     {
-      first = 0xf8;
-      len = 5;
+      switch (priv->compose_buffer[0])
+        {
+        case GDK_KEY_dead_doubleacute:
+          switch (priv->compose_buffer[1])
+            {
+            case GDK_KEY_dead_doubleacute:
+            case GDK_KEY_space:
+              value = GDK_KEY_quotedbl; break;
+
+            case 'a': value = GDK_KEY_adiaeresis; break;
+            case 'A': value = GDK_KEY_Adiaeresis; break;
+            case 'e': value = GDK_KEY_ediaeresis; break;
+            case 'E': value = GDK_KEY_Ediaeresis; break;
+            case 'i': value = GDK_KEY_idiaeresis; break;
+            case 'I': value = GDK_KEY_Idiaeresis; break;
+            case 'o': value = GDK_KEY_odiaeresis; break;
+            case 'O': value = GDK_KEY_Odiaeresis; break;
+            case 'u': value = GDK_KEY_udiaeresis; break;
+            case 'U': value = GDK_KEY_Udiaeresis; break;
+            case 'y': value = GDK_KEY_ydiaeresis; break;
+            case 'Y': value = GDK_KEY_Ydiaeresis; break;
+            }
+          break;
+
+        case GDK_KEY_dead_acute:
+          switch (priv->compose_buffer[1])
+            {
+            case 'c': value = GDK_KEY_ccedilla; break;
+            case 'C': value = GDK_KEY_Ccedilla; break;
+            }
+          break;
+        }
     }
-  else
+
+  if (value > 0)
     {
-      first = 0xfc;
-      len = 6;
+      gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple),
+                                         gdk_keyval_to_unicode (value));
+      priv->compose_buffer[0] = 0;
+
+      GTK_NOTE (MISC, g_print ("quartz: U+%04X\n", value));
+      return TRUE;
     }
 
-  for (i = len - 1; i > 0; --i)
+  return FALSE;
+}
+
+#endif
+
+static gboolean
+check_compact_table (GtkIMContextSimple           *context_simple,
+                     const GtkComposeTableCompact *table,
+                     gint                          n_compose)
+{
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+  gint row_stride;
+  guint16 *seq_index;
+  guint16 *seq;
+  gint i;
+  gboolean match;
+  gunichar value;
+
+  /* Will never match, if the sequence in the compose buffer is longer
+   * than the sequences in the table.  Further, compare_seq (key, val)
+   * will overrun val if key is longer than val.
+   */
+  if (n_compose > table->max_seq_len)
+    return FALSE;
+
+  seq_index = bsearch (priv->compose_buffer,
+                       table->data,
+                       table->n_index_size,
+                       sizeof (guint16) * table->n_index_stride,
+                       compare_seq_index);
+
+  if (!seq_index)
     {
-      outbuf[i] = (c & 0x3f) | 0x80;
-      c >>= 6;
+      GTK_NOTE (MISC, g_print ("compact: no\n"));
+      return FALSE;
     }
-  outbuf[0] = c | first;
 
-  return len;
+  if (seq_index && n_compose == 1)
+    {
+      GTK_NOTE (MISC, g_print ("compact: yes\n"));
+      return TRUE;
+    }
+
+  GTK_NOTE (MISC, g_print ("compact: %d ", *seq_index));
+  seq = NULL;
+  match = FALSE;
+
+  for (i = n_compose - 1; i < table->max_seq_len; i++)
+    {
+      row_stride = i + 1;
+
+      if (seq_index[i + 1] - seq_index[i] > 0)
+        {
+          seq = bsearch (priv->compose_buffer + 1,
+                         table->data + seq_index[i],
+                         (seq_index[i + 1] - seq_index[i]) / row_stride,
+                         sizeof (guint16) *  row_stride,
+                         compare_seq);
+
+          if (seq)
+            {
+              if (i == n_compose - 1)
+                {
+                  value = seq[row_stride - 1];
+                  match = TRUE;
+                }
+              else
+                {
+                  if (match)
+                    {
+                      GTK_NOTE (MISC, g_print ("tentative match U+%04X ", value));
+                      priv->tentative_match = value;
+                      priv->tentative_match_len = n_compose;
+                    }
+
+                  g_signal_emit_by_name (context_simple, "preedit-changed");
+
+                  GTK_NOTE (MISC, g_print ("yes\n"));
+                  return TRUE;
+                }
+             }
+        }
+    }
+
+  if (match)
+    {
+      gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple), value);
+#ifdef G_OS_WIN32
+      check_win32_special_case_after_compact_match (context_simple, n_compose, value);
+#endif
+      priv->compose_buffer[0] = 0;
+
+      GTK_NOTE (MISC, g_print ("U+%04X\n", value));
+      return TRUE;
+    }
+
+  GTK_NOTE (MISC, g_print ("no\n"));
+  return FALSE;
 }
 
-static void
-gtk_im_context_simple_commit_char (GtkIMContext *context,
-                                  unicode_char_t ch)
+/* This function receives a sequence of Unicode characters and tries to
+ * normalize it (NFC). We check for the case where the resulting string
+ * has length 1 (single character).
+ * NFC normalisation normally rearranges diacritic marks, unless these
+ * belong to the same Canonical Combining Class.
+ * If they belong to the same canonical combining class, we produce all
+ * permutations of the diacritic marks, then attempt to normalize.
+ */
+static gboolean
+check_normalize_nfc (gunichar* combination_buffer, gint n_compose)
 {
+  gunichar combination_buffer_temp[GTK_MAX_COMPOSE_LEN];
+  gchar *combination_utf8_temp = NULL;
+  gchar *nfc_temp = NULL;
+  gint n_combinations;
+  gunichar temp_swap;
+  gint i;
+
+  n_combinations = 1;
+
+  for (i = 1; i < n_compose; i++ )
+     n_combinations *= i;
+
+  /* Xorg reuses dead_tilde for the perispomeni diacritic mark.
+   * We check if base character belongs to Greek Unicode block,
+   * and if so, we replace tilde with perispomeni.
+   */
+  if (combination_buffer[0] >= 0x390 && combination_buffer[0] <= 0x3FF)
+    {
+      for (i = 1; i < n_compose; i++ )
+        if (combination_buffer[i] == 0x303)
+          combination_buffer[i] = 0x342;
+    }
+
+  memcpy (combination_buffer_temp, combination_buffer, GTK_MAX_COMPOSE_LEN * sizeof (gunichar) );
+
+  for (i = 0; i < n_combinations; i++ )
+    {
+      g_unicode_canonical_ordering (combination_buffer_temp, n_compose);
+      combination_utf8_temp = g_ucs4_to_utf8 (combination_buffer_temp, -1, NULL, NULL, NULL);
+      nfc_temp = g_utf8_normalize (combination_utf8_temp, -1, G_NORMALIZE_NFC);
+
+      if (g_utf8_strlen (nfc_temp, -1) == 1)
+        {
+          memcpy (combination_buffer, combination_buffer_temp, GTK_MAX_COMPOSE_LEN * sizeof (gunichar) );
+
+          g_free (combination_utf8_temp);
+          g_free (nfc_temp);
+
+          return TRUE;
+        }
+
+      g_free (combination_utf8_temp);
+      g_free (nfc_temp);
+
+      if (n_compose > 2)
+        {
+          temp_swap = combination_buffer_temp[i % (n_compose - 1) + 1];
+          combination_buffer_temp[i % (n_compose - 1) + 1] = combination_buffer_temp[(i+1) % (n_compose - 1) + 1];
+          combination_buffer_temp[(i+1) % (n_compose - 1) + 1] = temp_swap;
+        }
+      else
+        break;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+check_algorithmically (GtkIMContextSimple *context_simple,
+                       gint                n_compose)
+
+{
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+  gint i;
+  gunichar combination_buffer[GTK_MAX_COMPOSE_LEN];
+  gchar *combination_utf8, *nfc;
+
+  if (n_compose >= GTK_MAX_COMPOSE_LEN)
+    return FALSE;
+
+  for (i = 0; i < n_compose && IS_DEAD_KEY (priv->compose_buffer[i]); i++)
+    ;
+  if (i == n_compose)
+    return TRUE;
+
+  if (i > 0 && i == n_compose - 1)
+    {
+      combination_buffer[0] = gdk_keyval_to_unicode (priv->compose_buffer[i]);
+      combination_buffer[n_compose] = 0;
+      i--;
+      while (i >= 0)
+       {
+         switch (priv->compose_buffer[i])
+           {
+#define CASE(keysym, unicode) \
+           case GDK_KEY_dead_##keysym: combination_buffer[i+1] = unicode; break
+
+           CASE (grave, 0x0300);
+           CASE (acute, 0x0301);
+           CASE (circumflex, 0x0302);
+           CASE (tilde, 0x0303);       /* Also used with perispomeni, 0x342. */
+           CASE (macron, 0x0304);
+           CASE (breve, 0x0306);
+           CASE (abovedot, 0x0307);
+           CASE (diaeresis, 0x0308);
+           CASE (hook, 0x0309);
+           CASE (abovering, 0x030A);
+           CASE (doubleacute, 0x030B);
+           CASE (caron, 0x030C);
+           CASE (abovecomma, 0x0313);         /* Equivalent to psili */
+           CASE (abovereversedcomma, 0x0314); /* Equivalent to dasia */
+           CASE (horn, 0x031B);        /* Legacy use for psili, 0x313 (or 0x343). */
+           CASE (belowdot, 0x0323);
+           CASE (cedilla, 0x0327);
+           CASE (ogonek, 0x0328);      /* Legacy use for dasia, 0x314.*/
+           CASE (iota, 0x0345);
+           CASE (voiced_sound, 0x3099);        /* Per Markus Kuhn keysyms.txt file. */
+           CASE (semivoiced_sound, 0x309A);    /* Per Markus Kuhn keysyms.txt file. */
+
+           /* The following cases are to be removed once xkeyboard-config,
+            * xorg are fully updated.
+            */
+            /* Workaround for typo in 1.4.x xserver-xorg */
+           case 0xfe66: combination_buffer[i+1] = 0x314; break;
+           /* CASE (dasia, 0x314); */
+           /* CASE (perispomeni, 0x342); */
+           /* CASE (psili, 0x343); */
+#undef CASE
+           default:
+             combination_buffer[i+1] = gdk_keyval_to_unicode (priv->compose_buffer[i]);
+           }
+         i--;
+       }
+      
+      /* If the buffer normalizes to a single character, then modify the order
+       * of combination_buffer accordingly, if necessary, and return TRUE.
+       */
+      if (check_normalize_nfc (combination_buffer, n_compose))
+        {
+          gunichar value;
+         combination_utf8 = g_ucs4_to_utf8 (combination_buffer, -1, NULL, NULL, NULL);
+          nfc = g_utf8_normalize (combination_utf8, -1, G_NORMALIZE_NFC);
+
+          value = g_utf8_get_char (nfc);
+          gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple), value);
+          priv->compose_buffer[0] = 0;
+
+          g_free (combination_utf8);
+          g_free (nfc);
+
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+/* In addition to the table-driven sequences, we allow Unicode hex
+ * codes to be entered. The method chosen here is similar to the
+ * one recommended in ISO 14755, but not exactly the same, since we
+ * don't want to steal 16 valuable key combinations.
+ *
+ * A hex Unicode sequence must be started with Ctrl-Shift-U, followed
+ * by a sequence of hex digits entered with Ctrl-Shift still held.
+ * Releasing one of the modifiers or pressing space while the modifiers
+ * are still held commits the character. It is possible to erase
+ * digits using backspace.
+ *
+ * As an extension to the above, we also allow to start the sequence
+ * with Ctrl-Shift-U, then release the modifiers before typing any
+ * digits, and enter the digits without modifiers.
+ */
+
+static gboolean
+check_hex (GtkIMContextSimple *context_simple,
+           gint                n_compose)
+{
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+  /* See if this is a hex sequence, return TRUE if so */
+  gint i;
+  GString *str;
+  gulong n;
+  gchar *nptr = NULL;
   gchar buf[7];
-  gint len;
+
+  priv->tentative_match = 0;
+  priv->tentative_match_len = 0;
+
+  str = g_string_new (NULL);
+  
+  i = 0;
+  while (i < n_compose)
+    {
+      gunichar ch;
       
-  len = ucs4_to_utf8 (ch, buf);
-  buf[len] = '\0';
+      ch = gdk_keyval_to_unicode (priv->compose_buffer[i]);
+      
+      if (ch == 0)
+        return FALSE;
 
-  gtk_signal_emit_by_name (GTK_OBJECT (context), "commit", &buf);
+      if (!g_unichar_isxdigit (ch))
+        return FALSE;
+
+      buf[g_unichar_to_utf8 (ch, buf)] = '\0';
+
+      g_string_append (str, buf);
+      
+      ++i;
+    }
+
+  n = strtoul (str->str, &nptr, 16);
+
+  /* If strtoul fails it probably means non-latin digits were used;
+   * we should in principle handle that, but we probably don't.
+   */
+  if (nptr - str->str < str->len)
+    {
+      g_string_free (str, TRUE);
+      return FALSE;
+    }
+  else
+    g_string_free (str, TRUE);
+
+  if (g_unichar_validate (n))
+    {
+      priv->tentative_match = n;
+      priv->tentative_match_len = n_compose;
+    }
+  
+  return TRUE;
 }
 
-static int
-compare_seq (const void *key, const void *value)
+static void
+beep_window (GdkWindow *window)
 {
-  int i = 0;
-  const guint *keysyms = key;
-  const GtkComposeSeq *seq = value;
+  GdkScreen *screen = gdk_window_get_screen (window);
+  gboolean   beep;
 
-  while (keysyms[i])
+  g_object_get (gtk_settings_get_for_screen (screen),
+                "gtk-error-bell", &beep,
+                NULL);
+
+  if (beep)
+    gdk_window_beep (window);
+}
+
+static gboolean
+no_sequence_matches (GtkIMContextSimple *context_simple,
+                     gint                n_compose,
+                     GdkEventKey        *event)
+{
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+  GtkIMContext *context;
+  gunichar ch;
+  
+  context = GTK_IM_CONTEXT (context_simple);
+  
+  /* No compose sequences found, check first if we have a partial
+   * match pending.
+   */
+  if (priv->tentative_match)
     {
-      if (keysyms[i] < seq->keysyms[i])
-       return -1;
-      else if (keysyms[i] > seq->keysyms[i])
-       return 1;
+      gint len = priv->tentative_match_len;
+      int i;
+      
+      gtk_im_context_simple_commit_char (context, priv->tentative_match);
+      priv->compose_buffer[0] = 0;
+      
+      for (i=0; i < n_compose - len - 1; i++)
+       {
+         GdkEvent *tmp_event = gdk_event_copy ((GdkEvent *)event);
+         tmp_event->key.keyval = priv->compose_buffer[len + i];
          
-      i++;
+         gtk_im_context_filter_keypress (context, (GdkEventKey *)tmp_event);
+         gdk_event_free (tmp_event);
+       }
+
+      return gtk_im_context_filter_keypress (context, event);
+    }
+  else
+    {
+      priv->compose_buffer[0] = 0;
+      if (n_compose > 1)               /* Invalid sequence */
+       {
+         beep_window (event->window);
+         return TRUE;
+       }
+  
+      ch = gdk_keyval_to_unicode (event->keyval);
+      if (ch != 0 && !g_unichar_iscntrl (ch))
+       {
+         gtk_im_context_simple_commit_char (context, ch);
+         return TRUE;
+       }
+      else
+       return FALSE;
     }
+}
 
-  return 0;
+static gboolean
+is_hex_keyval (guint keyval)
+{
+  gunichar ch = gdk_keyval_to_unicode (keyval);
+
+  return g_unichar_isxdigit (ch);
+}
+
+static guint
+canonical_hex_keyval (GdkEventKey *event)
+{
+  GdkKeymap *keymap = gdk_keymap_get_for_display (gdk_window_get_display (event->window));
+  guint keyval;
+  guint *keyvals = NULL;
+  gint n_vals = 0;
+  gint i;
+  
+  /* See if the keyval is already a hex digit */
+  if (is_hex_keyval (event->keyval))
+    return event->keyval;
+
+  /* See if this key would have generated a hex keyval in
+   * any other state, and return that hex keyval if so
+   */
+  gdk_keymap_get_entries_for_keycode (keymap,
+                                     event->hardware_keycode,
+                                     NULL,
+                                     &keyvals, &n_vals);
+
+  keyval = 0;
+  i = 0;
+  while (i < n_vals)
+    {
+      if (is_hex_keyval (keyvals[i]))
+        {
+          keyval = keyvals[i];
+          break;
+        }
+
+      ++i;
+    }
+
+  g_free (keyvals);
+  
+  if (keyval)
+    return keyval;
+  else
+    /* No way to make it a hex digit
+     */
+    return 0;
 }
 
 static gboolean
@@ -876,57 +876,379 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
                                       GdkEventKey  *event)
 {
   GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
-  GtkComposeSeq *seq;
-  
-  unicode_char_t ch;
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+  GdkDisplay *display = gdk_window_get_display (event->window);
+  GSList *tmp_list;  
   int n_compose = 0;
+  GdkModifierType hex_mod_mask;
+  gboolean have_hex_mods;
+  gboolean is_hex_start;
+  gboolean is_hex_end;
+  gboolean is_backspace;
+  gboolean is_escape;
+  guint hex_keyval;
   int i;
 
-  /* Ignore modifier key presses
-   */
-  for (i=0; i < G_N_ELEMENTS (gtk_compose_ignore); i++)
+  while (priv->compose_buffer[n_compose] != 0)
+    n_compose++;
+
+  if (event->type == GDK_KEY_RELEASE)
+    {
+      if (priv->in_hex_sequence &&
+         (event->keyval == GDK_KEY_Control_L || event->keyval == GDK_KEY_Control_R ||
+          event->keyval == GDK_KEY_Shift_L || event->keyval == GDK_KEY_Shift_R))
+       {
+         if (priv->tentative_match &&
+             g_unichar_validate (priv->tentative_match))
+           {
+             gtk_im_context_simple_commit_char (context, priv->tentative_match);
+             priv->compose_buffer[0] = 0;
+
+           }
+         else if (n_compose == 0)
+           {
+             priv->modifiers_dropped = TRUE;
+           }
+         else
+           {
+             /* invalid hex sequence */
+             beep_window (event->window);
+             
+             priv->tentative_match = 0;
+             priv->in_hex_sequence = FALSE;
+             priv->compose_buffer[0] = 0;
+             
+             g_signal_emit_by_name (context_simple, "preedit-changed");
+             g_signal_emit_by_name (context_simple, "preedit-end");
+           }
+
+         return TRUE;
+       }
+      else
+       return FALSE;
+    }
+
+  /* Ignore modifier key presses */
+  for (i = 0; i < G_N_ELEMENTS (gtk_compose_ignore); i++)
     if (event->keyval == gtk_compose_ignore[i])
       return FALSE;
-  
-  /* Then, check for compose sequences
+
+  hex_mod_mask = gdk_keymap_get_modifier_mask (gdk_keymap_get_for_display (display),
+                                               GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
+  hex_mod_mask |= GDK_SHIFT_MASK;
+
+  if (priv->in_hex_sequence && priv->modifiers_dropped)
+    have_hex_mods = TRUE;
+  else
+    have_hex_mods = (event->state & (hex_mod_mask)) == hex_mod_mask;
+  is_hex_start = event->keyval == GDK_KEY_U;
+  is_hex_end = (event->keyval == GDK_KEY_space ||
+               event->keyval == GDK_KEY_KP_Space ||
+               event->keyval == GDK_KEY_Return ||
+               event->keyval == GDK_KEY_ISO_Enter ||
+               event->keyval == GDK_KEY_KP_Enter);
+  is_backspace = event->keyval == GDK_KEY_BackSpace;
+  is_escape = event->keyval == GDK_KEY_Escape;
+  hex_keyval = canonical_hex_keyval (event);
+
+  /* If we are already in a non-hex sequence, or
+   * this keystroke is not hex modifiers + hex digit, don't filter
+   * key events with accelerator modifiers held down. We only treat
+   * Control and Alt as accel modifiers here, since Super, Hyper and
+   * Meta are often co-located with Mode_Switch, Multi_Key or
+   * ISO_Level3_Switch.
    */
-  while (context_simple->compose_buffer[n_compose] != 0)
-    n_compose++;
+  if (!have_hex_mods ||
+      (n_compose > 0 && !priv->in_hex_sequence) ||
+      (n_compose == 0 && !priv->in_hex_sequence && !is_hex_start) ||
+      (priv->in_hex_sequence && !hex_keyval &&
+       !is_hex_start && !is_hex_end && !is_escape && !is_backspace))
+    {
+      GdkDisplay *display;
+      GdkModifierType no_text_input_mask;
 
-  context_simple->compose_buffer[n_compose++] = event->keyval;
-  context_simple->compose_buffer[n_compose] = 0;
+      display = gdk_window_get_display (event->window);
 
-  seq = bsearch (context_simple->compose_buffer,
-                gtk_compose_seqs, G_N_ELEMENTS (gtk_compose_seqs),
-                sizeof (GtkComposeSeq), compare_seq);
+      no_text_input_mask =
+        gdk_keymap_get_modifier_mask (gdk_keymap_get_for_display (display),
+                                      GDK_MODIFIER_INTENT_NO_TEXT_INPUT);
 
-  if (seq)
+      if (event->state & no_text_input_mask ||
+         (priv->in_hex_sequence && priv->modifiers_dropped &&
+          (event->keyval == GDK_KEY_Return ||
+           event->keyval == GDK_KEY_ISO_Enter ||
+           event->keyval == GDK_KEY_KP_Enter)))
+       {
+         return FALSE;
+       }
+    }
+  
+  /* Handle backspace */
+  if (priv->in_hex_sequence && have_hex_mods && is_backspace)
     {
-      if (n_compose == GTK_MAX_COMPOSE_LEN ||
-         seq->keysyms[n_compose] == 0) /* complete sequence */
+      if (n_compose > 0)
        {
-         gtk_im_context_simple_commit_char (context, seq->unicode);
-         context_simple->compose_buffer[0] = 0;
+         n_compose--;
+         priv->compose_buffer[n_compose] = 0;
+          check_hex (context_simple, n_compose);
        }
+      else
+       {
+         priv->in_hex_sequence = FALSE;
+       }
+
+      g_signal_emit_by_name (context_simple, "preedit-changed");
+
+      if (!priv->in_hex_sequence)
+        g_signal_emit_by_name (context_simple, "preedit-end");
       
       return TRUE;
     }
 
-  /* No compose sequences found, try simple conversion to unicode
-   */
-  context_simple->compose_buffer[0] = 0;
-  if (n_compose > 1)           /* Invalid sequence */
+  /* Check for hex sequence restart */
+  if (priv->in_hex_sequence && have_hex_mods && is_hex_start)
     {
-      gdk_beep();
-      return TRUE;
+      if (priv->tentative_match &&
+         g_unichar_validate (priv->tentative_match))
+       {
+         gtk_im_context_simple_commit_char (context, priv->tentative_match);
+         priv->compose_buffer[0] = 0;
+       }
+      else 
+       {
+         /* invalid hex sequence */
+         if (n_compose > 0)
+           beep_window (event->window);
+         
+         priv->tentative_match = 0;
+         priv->in_hex_sequence = FALSE;
+         priv->compose_buffer[0] = 0;
+       }
     }
   
-  ch = gdk_keyval_to_unicode (event->keyval);
-  if (ch != 0)
+  /* Check for hex sequence start */
+  if (!priv->in_hex_sequence && have_hex_mods && is_hex_start)
     {
-      gtk_im_context_simple_commit_char (context, ch);
+      priv->compose_buffer[0] = 0;
+      priv->in_hex_sequence = TRUE;
+      priv->modifiers_dropped = FALSE;
+      priv->tentative_match = 0;
+
+      g_signal_emit_by_name (context_simple, "preedit-start");
+      g_signal_emit_by_name (context_simple, "preedit-changed");
+  
       return TRUE;
     }
+  
+  /* Then, check for compose sequences */
+  if (priv->in_hex_sequence)
+    {
+      if (hex_keyval)
+       priv->compose_buffer[n_compose++] = hex_keyval;
+      else if (is_escape)
+       {
+         gtk_im_context_simple_reset (context);
+         
+         return TRUE;
+       }
+      else if (!is_hex_end)
+       {
+         /* non-hex character in hex sequence */
+         beep_window (event->window);
+         
+         return TRUE;
+       }
+    }
   else
-    return FALSE;
+    priv->compose_buffer[n_compose++] = event->keyval;
+
+  priv->compose_buffer[n_compose] = 0;
+
+  if (priv->in_hex_sequence)
+    {
+      /* If the modifiers are still held down, consider the sequence again */
+      if (have_hex_mods)
+        {
+          /* space or return ends the sequence, and we eat the key */
+          if (n_compose > 0 && is_hex_end)
+            {
+             if (priv->tentative_match &&
+                 g_unichar_validate (priv->tentative_match))
+               {
+                 gtk_im_context_simple_commit_char (context, priv->tentative_match);
+                 priv->compose_buffer[0] = 0;
+               }
+             else
+               {
+                 /* invalid hex sequence */
+                 beep_window (event->window);
+
+                 priv->tentative_match = 0;
+                 priv->in_hex_sequence = FALSE;
+                 priv->compose_buffer[0] = 0;
+               }
+            }
+          else if (!check_hex (context_simple, n_compose))
+           beep_window (event->window);
+         
+         g_signal_emit_by_name (context_simple, "preedit-changed");
+
+         if (!priv->in_hex_sequence)
+           g_signal_emit_by_name (context_simple, "preedit-end");
+
+         return TRUE;
+        }
+    }
+  else
+    {
+      tmp_list = priv->tables;
+      while (tmp_list)
+        {
+          if (check_table (context_simple, tmp_list->data, n_compose))
+            return TRUE;
+          tmp_list = tmp_list->next;
+        }
+
+      GTK_NOTE (MISC, {
+         g_print ("[ ");
+         for (i = 0; i < n_compose; i++)
+           {
+             const gchar *keyval_name = gdk_keyval_name (priv->compose_buffer[i]);
+             
+             if (keyval_name != NULL)
+               g_print ("%s ", keyval_name);
+             else
+               g_print ("%04x ", priv->compose_buffer[i]);
+           }
+         g_print ("] ");
+       });
+
+#ifdef GDK_WINDOWING_WIN32
+      if (check_win32_special_cases (context_simple, n_compose))
+       return TRUE;
+#endif
+
+#ifdef GDK_WINDOWING_QUARTZ
+      if (check_quartz_special_cases (context_simple, n_compose))
+        return TRUE;
+#endif
+
+      if (check_compact_table (context_simple, &gtk_compose_table_compact, n_compose))
+        return TRUE;
+  
+      if (check_algorithmically (context_simple, n_compose))
+       return TRUE;
+    }
+  
+  /* The current compose_buffer doesn't match anything */
+  return no_sequence_matches (context_simple, n_compose, event);
+}
+
+static void
+gtk_im_context_simple_reset (GtkIMContext *context)
+{
+  GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+
+  priv->compose_buffer[0] = 0;
+
+  if (priv->tentative_match || priv->in_hex_sequence)
+    {
+      priv->in_hex_sequence = FALSE;
+      priv->tentative_match = 0;
+      priv->tentative_match_len = 0;
+      g_signal_emit_by_name (context_simple, "preedit-changed");
+      g_signal_emit_by_name (context_simple, "preedit-end");
+    }
+}
+
+static void     
+gtk_im_context_simple_get_preedit_string (GtkIMContext   *context,
+                                         gchar         **str,
+                                         PangoAttrList **attrs,
+                                         gint           *cursor_pos)
+{
+  GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+  char outbuf[37]; /* up to 6 hex digits */
+  int len = 0;
+
+  if (priv->in_hex_sequence)
+    {
+      int hexchars = 0;
+         
+      outbuf[0] = 'u';
+      len = 1;
+
+      while (priv->compose_buffer[hexchars] != 0)
+       {
+         len += g_unichar_to_utf8 (gdk_keyval_to_unicode (priv->compose_buffer[hexchars]),
+                                   outbuf + len);
+         ++hexchars;
+       }
+
+      g_assert (len < 25);
+    }
+  else if (priv->tentative_match)
+    len = g_unichar_to_utf8 (priv->tentative_match, outbuf);
+      
+  outbuf[len] = '\0';      
+
+  if (str)
+    *str = g_strdup (outbuf);
+
+  if (attrs)
+    {
+      *attrs = pango_attr_list_new ();
+      
+      if (len)
+       {
+         PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
+         attr->start_index = 0;
+          attr->end_index = len;
+         pango_attr_list_insert (*attrs, attr);
+       }
+    }
+
+  if (cursor_pos)
+    *cursor_pos = len;
+}
+
+/**
+ * gtk_im_context_simple_add_table: (skip)
+ * @context_simple: A #GtkIMContextSimple
+ * @data: the table 
+ * @max_seq_len: Maximum length of a sequence in the table
+ *               (cannot be greater than #GTK_MAX_COMPOSE_LEN)
+ * @n_seqs: number of sequences in the table
+ * 
+ * Adds an additional table to search to the input context.
+ * Each row of the table consists of @max_seq_len key symbols
+ * followed by two #guint16 interpreted as the high and low
+ * words of a #gunicode value. Tables are searched starting
+ * from the last added.
+ *
+ * The table must be sorted in dictionary order on the
+ * numeric value of the key symbol fields. (Values beyond
+ * the length of the sequence should be zero.)
+ **/
+void
+gtk_im_context_simple_add_table (GtkIMContextSimple *context_simple,
+                                guint16            *data,
+                                gint                max_seq_len,
+                                gint                n_seqs)
+{
+  GtkIMContextSimplePrivate *priv = context_simple->priv;
+  GtkComposeTable *table;
+
+  g_return_if_fail (GTK_IS_IM_CONTEXT_SIMPLE (context_simple));
+  g_return_if_fail (data != NULL);
+  g_return_if_fail (max_seq_len <= GTK_MAX_COMPOSE_LEN);
+  
+  table = g_new (GtkComposeTable, 1);
+  table->data = data;
+  table->max_seq_len = max_seq_len;
+  table->n_seqs = n_seqs;
+
+  priv->tables = g_slist_prepend (priv->tables, table);
 }