diff --git a/modules/input/gtkimcontextime.c b/modules/input/gtkimcontextime.c index aa7f9a886c..0de1b53dae 100644 --- a/modules/input/gtkimcontextime.c +++ b/modules/input/gtkimcontextime.c @@ -31,6 +31,7 @@ #include "imm-extra.h" +#include #include "gdk/win32/gdkwin32.h" #include "gdk/gdkkeysyms.h" @@ -49,6 +50,9 @@ /* #define BUFSIZE 4096 */ +#define IS_DEAD_KEY(k) \ + ((k) >= GDK_dead_grave && (k) <= (GDK_dead_dasia+1)) + #define FREE_PREEDIT_BUFFER(ctx) \ { \ g_free((ctx)->priv->comp_str); \ @@ -70,6 +74,8 @@ struct _GtkIMContextIMEPrivate DWORD comp_str_len; LPVOID read_str; DWORD read_str_len; + + guint32 dead_key_keyval; }; @@ -298,6 +304,64 @@ gtk_im_context_ime_set_client_window (GtkIMContext *context, context_ime->client_window = client_window; } +static gunichar +_gtk_im_context_ime_dead_key_unichar (guint keyval, + gboolean spacing) +{ + switch (keyval) + { +#define CASE(keysym, unicode, spacing_unicode) \ + case GDK_dead_##keysym: return (spacing) ? spacing_unicode : unicode; + + CASE (grave, 0x0300, 0x0060); + CASE (acute, 0x0301, 0x00b4); + CASE (circumflex, 0x0302, 0x005e); + CASE (tilde, 0x0303, 0x007e); /* Also used with perispomeni, 0x342. */ + CASE (macron, 0x0304, 0x00af); + CASE (breve, 0x0306, 0x02d8); + CASE (abovedot, 0x0307, 0x02d9); + CASE (diaeresis, 0x0308, 0x00a8); + CASE (hook, 0x0309, 0); + CASE (abovering, 0x030A, 0x02da); + CASE (doubleacute, 0x030B, 0x2dd); + CASE (caron, 0x030C, 0x02c7); + CASE (abovecomma, 0x0313, 0); /* Equivalent to psili */ + CASE (abovereversedcomma, 0x0314, 0); /* Equivalent to dasia */ + CASE (horn, 0x031B, 0); /* Legacy use for psili, 0x313 (or 0x343). */ + CASE (belowdot, 0x0323, 0); + CASE (cedilla, 0x0327, 0x00b8); + CASE (ogonek, 0x0328, 0); /* Legacy use for dasia, 0x314.*/ + CASE (iota, 0x0345, 0); + +#undef CASE + default: + return 0; + } +} + +static void +_gtk_im_context_ime_commit_unichar (GtkIMContextIME *context_ime, + gunichar c) +{ + gchar utf8[10]; + int len; + + if (context_ime->priv->dead_key_keyval != 0) + { + gunichar combining; + + combining = + _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval, + FALSE); + g_unichar_compose (c, combining, &c); + } + + len = g_unichar_to_utf8 (c, utf8); + utf8[len] = 0; + + g_signal_emit_by_name (context_ime, "commit", utf8); + context_ime->priv->dead_key_keyval = 0; +} static gboolean gtk_im_context_ime_filter_keypress (GtkIMContext *context, @@ -324,16 +388,39 @@ gtk_im_context_ime_filter_keypress (GtkIMContext *context, if (!GDK_IS_WINDOW (context_ime->client_window)) return FALSE; + if (event->keyval == GDK_space && + context_ime->priv->dead_key_keyval != 0) + { + c = _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval, TRUE); + context_ime->priv->dead_key_keyval = 0; + _gtk_im_context_ime_commit_unichar (context_ime, c); + return TRUE; + } + c = gdk_keyval_to_unicode (event->keyval); + if (c) { - guchar utf8[10]; - int len = g_unichar_to_utf8 (c, utf8); - utf8[len] = 0; - - g_signal_emit_by_name (context_ime, "commit", utf8); + _gtk_im_context_ime_commit_unichar (context_ime, c); retval = TRUE; } + else if (IS_DEAD_KEY (event->keyval)) + { + gunichar dead_key; + + dead_key = _gtk_im_context_ime_dead_key_unichar (event->keyval, FALSE); + + /* Emulate double input of dead keys */ + if (dead_key && event->keyval == context_ime->priv->dead_key_keyval) + { + c = _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval, TRUE); + context_ime->priv->dead_key_keyval = 0; + _gtk_im_context_ime_commit_unichar (context_ime, c); + _gtk_im_context_ime_commit_unichar (context_ime, c); + } + else + context_ime->priv->dead_key_keyval = event->keyval; + } return retval; }