Commit cfad43b8 authored by Suyuan Chang's avatar Suyuan Chang

macOS: Fix bug that entry cannot press and hold a key to input accented character.

There're two issues in GdkQuartzView's NSTextInputClient implementation
causes this bug.

1. The -(NSRange)selectedRange should not return [NSNotFound, 0] if
   there's no selection. The accented character window will not show
   if returned NSRange's location is NSNotFound. Instead of that, the
   NSRange's location should be the caret position in the text input

2. The accented character window will invoke
   -(void)insertText:replacementRange: with non-empty replacement
   range, to replace non-accented character with accented character
   after user select it from accented character window. This case is
   not implemented in original code. Here I use another gobject data
   to pass the information to input module and convert it into
   'delete-surrounding' event.

Besides these, there's another bug cause gtk_im_context_filter_keypress()
return wrong value while user press and hold a key. When user press
and hold a key, the accented character window will consume the
repeating key down event. Is this case, gtk_im_context_filter_keypress()
should return TRUE, indicate the key press is filtered by input
method module. But it will return FALSE because
gtk_im_context_filter_keypress() assume that every key press event
will generate some text from input method module.

Fixes #1618
parent 4af1fa87
......@@ -31,7 +31,7 @@
if ((self = [super initWithFrame: frameRect]))
markedRange = NSMakeRange (NSNotFound, 0);
selectedRange = NSMakeRange (NSNotFound, 0);
selectedRange = NSMakeRange (0, 0);
return self;
......@@ -57,6 +57,16 @@
-(void) keyDown: (NSEvent *) theEvent
/* NOTE: When user press Cmd+A, interpretKeyEvents: will call noop:
method. When user press and hold A to show the accented char window,
it consumed repeating key down events for key 'A' do NOT call
any other method. We use this behavior to determine if this key
down event is filtered by interpretKeyEvents.
g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
GDK_NOTE (EVENTS, g_message ("keyDown"));
[self interpretKeyEvents: [NSArray arrayWithObject: theEvent]];
......@@ -124,7 +134,8 @@
GDK_NOTE (EVENTS, g_message ("unmarkText"));
markedRange = selectedRange = NSMakeRange (NSNotFound, 0);
selectedRange = NSMakeRange (0, 0);
markedRange = NSMakeRange (NSNotFound, 0);
g_object_set_data_full (G_OBJECT (gdk_window), TIC_MARKED_TEXT, NULL, g_free);
......@@ -209,8 +220,15 @@
str = [string UTF8String];
selectedRange = NSMakeRange ([string length], 0);
if (replacementRange.length > 0)
g_object_set_data (G_OBJECT (gdk_window), TIC_INSERT_TEXT_REPLACE_LEN,
GINT_TO_POINTER (replacementRange.length));
g_object_set_data_full (G_OBJECT (gdk_window), TIC_INSERT_TEXT, g_strdup (str), g_free);
GDK_NOTE (EVENTS, g_message ("insertText: set %s (%p, nsview %p): %s",
TIC_INSERT_TEXT, gdk_window, self,
......@@ -537,6 +555,8 @@
-(void)noop: (id)sender
GDK_NOTE (EVENTS, g_message ("noop"));
g_object_set_data (G_OBJECT (gdk_window), GIC_FILTER_KEY,
/* --------------------------------------------------------------- */
......@@ -24,6 +24,7 @@
#define TIC_SELECTED_POS "tic-selected-pos"
#define TIC_SELECTED_LEN "tic-selected-len"
#define TIC_INSERT_TEXT "tic-insert-text"
#define TIC_INSERT_TEXT_REPLACE_LEN "tic-insert-text-replace-len"
#define TIC_IN_KEY_DOWN "tic-in-key-down"
/* GtkIMContext */
......@@ -129,8 +129,11 @@ output_result (GtkIMContext *context,
GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
gboolean retval = FALSE;
int fixed_str_replace_len;
gchar *fixed_str, *marked_str;
fixed_str_replace_len = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (win),
fixed_str = g_strdup (g_object_get_data (G_OBJECT (win), TIC_INSERT_TEXT));
marked_str = g_strdup (g_object_get_data (G_OBJECT (win), TIC_MARKED_TEXT));
if (fixed_str)
......@@ -139,6 +142,13 @@ output_result (GtkIMContext *context,
g_free (qc->preedit_str);
qc->preedit_str = NULL;
g_object_set_data (G_OBJECT (win), TIC_INSERT_TEXT, NULL);
if (fixed_str_replace_len)
gboolean retval;
g_object_set_data (G_OBJECT (win), TIC_INSERT_TEXT_REPLACE_LEN, 0);
g_signal_emit_by_name (context, "delete-surrounding",
-fixed_str_replace_len, fixed_str_replace_len, &retval);
g_signal_emit_by_name (context, "commit", fixed_str);
g_signal_emit_by_name (context, "preedit_changed");
......@@ -168,6 +178,11 @@ output_result (GtkIMContext *context,
if (!fixed_str && !marked_str)
unsigned int filtered =
GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (win),
if (filtered)
retval = TRUE;
if (qc->preedit_str && strlen (qc->preedit_str) > 0)
retval = TRUE;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment