Use native Windows API for converting keystrokes to characters

Instead of using the incomplete GTK-internal emulation, use the WM_CHAR
messages sent by Windows. Make the IME input method the default for all
languages on Windows.
This commit is contained in:
Philip Zander
2019-07-09 17:44:05 +02:00
committed by Philip Zander
parent dd5fd12343
commit e6f05da6ef
5 changed files with 61 additions and 113 deletions

View File

@ -33,7 +33,9 @@
#include "gdk/gdkkeysyms-compat.h"
#include "gdk/win32/gdkwin32.h"
#include "gdk/win32/gdkprivate-win32.h"
#include "gdk/gdkkeysyms.h"
#include "gdk/gdkinternals.h"
#include <pango/pango.h>
@ -59,10 +61,6 @@ typedef enum {
GTK_WIN32_IME_FOCUS_BEHAVIOR_FOLLOW,
} GtkWin32IMEFocusBehavior;
#define IS_DEAD_KEY(k) \
((k) >= GDK_dead_grave && (k) <= (GDK_dead_dasia+1))
struct _GtkIMContextIMEPrivate
{
/* When pretend_empty_preedit is set to TRUE,
@ -80,7 +78,6 @@ struct _GtkIMContextIMEPrivate
* https://gitlab.gnome.org/GNOME/gtk/commit/c255ba68fc2c918dd84da48a472e7973d3c00b03
*/
gboolean pretend_empty_preedit;
guint32 dead_key_keyval;
GtkWin32IMEFocusBehavior focus_behavior;
};
@ -318,125 +315,30 @@ gtk_im_context_ime_set_client_window (GtkIMContext *context,
g_return_if_fail (GDK_IS_WINDOW (context_ime->toplevel));
}
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,
GdkEventKey *event)
{
GtkIMContextIME *context_ime;
gboolean retval = FALSE;
guint32 c;
GdkEventPrivate *event_priv;
gchar *utf8;
g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (context), FALSE);
g_return_val_if_fail (event, FALSE);
if (event->type == GDK_KEY_RELEASE)
return FALSE;
if (event->state & GDK_CONTROL_MASK)
return FALSE;
context_ime = GTK_IM_CONTEXT_IME (context);
if (!context_ime->focus)
g_return_val_if_fail (gdk_event_is_allocated(event), FALSE);
event_priv = (GdkEventPrivate*)event;
if (event_priv->translation_len == 0)
return FALSE;
if (!GDK_IS_WINDOW (context_ime->client_window))
return FALSE;
utf8 = g_utf16_to_utf8(event_priv->translation, event_priv->translation_len, NULL, NULL, NULL);
g_signal_emit_by_name (context_ime, "commit", utf8);
g_free(utf8);
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)
{
_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;
return TRUE;
}