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
   buffer.

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
This commit is contained in:
Suyuan Chang 2019-01-24 23:10:34 -08:00
parent 4af1fa872a
commit cfad43b80d
3 changed files with 38 additions and 2 deletions

View File

@ -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,
GUINT_TO_POINTER (GIC_FILTER_FILTERED));
GDK_NOTE (EVENTS, g_message ("keyDown"));
[self interpretKeyEvents: [NSArray arrayWithObject: theEvent]];
}
@ -124,7 +134,8 @@
-(void)unmarkText
{
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 @@
else
{
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,
GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
}
/* --------------------------------------------------------------- */

View File

@ -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 */

View File

@ -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),
TIC_INSERT_TEXT_REPLACE_LEN));
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),
GIC_FILTER_KEY));
if (filtered)
retval = TRUE;
if (qc->preedit_str && strlen (qc->preedit_str) > 0)
retval = TRUE;
}