[gtk/gtk-3-24: 1/2] macOS: Fix bug that entry cannot press and hold a key to input accented character.



commit cfad43b80d15328f2e82ccc677ce634bd32a5560
Author: Suyuan Chang <suyuan chang gmail com>
Date:   Thu Jan 24 23:10:34 2019 -0800

    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

 gdk/quartz/GdkQuartzView.c | 24 ++++++++++++++++++++++--
 gdk/quartz/GdkQuartzView.h |  1 +
 modules/input/imquartz.c   | 15 +++++++++++++++
 3 files changed, 38 insertions(+), 2 deletions(-)
---
diff --git a/gdk/quartz/GdkQuartzView.c b/gdk/quartz/GdkQuartzView.c
index 684832f7a7..8d8502701d 100644
--- a/gdk/quartz/GdkQuartzView.c
+++ b/gdk/quartz/GdkQuartzView.c
@@ -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));
 }
 
 /* --------------------------------------------------------------- */
diff --git a/gdk/quartz/GdkQuartzView.h b/gdk/quartz/GdkQuartzView.h
index 732c677ee5..da06a8bdce 100644
--- a/gdk/quartz/GdkQuartzView.h
+++ b/gdk/quartz/GdkQuartzView.h
@@ -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 */
diff --git a/modules/input/imquartz.c b/modules/input/imquartz.c
index b7428fcf92..17758493c3 100644
--- a/modules/input/imquartz.c
+++ b/modules/input/imquartz.c
@@ -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;
     }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]