From e8e6c6715aea95e7d3a1bcd393e730de489335c1 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Tue, 14 Dec 2021 20:06:42 +0100 Subject: [PATCH 1/2] Add prefilter flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change adds a new `IBUS_PREFILTER_MASK` flag which the engine can set on the state. This allows engines to prefilter events and use that to control the order of the output even if some syntethic key events get interspersed between the input. A scenario where this is necessary is in ibus-engine-keyman for applications that don't support surrounding text like Chrome/Chromium and gnome-terminal. For example with the _IPA (SIL)_ keyboard, the users presses the 'n' key which produces 'n' output. Then the user presses ';'. The expected result is that the 'n' gets replaced by 'ŋ'. For applications that don't support surrounding text the engine has to forward a Backspace key event, followed by committing the new text 'ŋ'. However, since the key event gets processed asynchronously, it can happen that the new text gets committed before the Backspace key is processed, leading to the deletion of 'ŋ' instead of 'n'. The `IBUS_PREFILTER_MASK` flag allows to solve this problem: when the engine receives a key press, it calls `ibus_engine_forward_key_event()` for the same key with the `IBUS_PREFILTER_MASK` flag set. Only when it receives a key press with the `IBUS_PREFILTER_MASK` already set it will process the key. When it generates the Backspace key event it will forward it to ibus with the `IBUS_PREFILTER_MASK` flag already set. When it comes back to the engine it will be in the correct order. Since `IBUS_PREFILTER_MASK` is a flag that will only ever get set by the engine it shouldn't break any existing engines. --- client/gtk2/ibusimcontext.c | 13 ++++++++----- src/ibustypes.h | 8 +++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c index bc14df003..421791f4d 100644 --- a/client/gtk2/ibusimcontext.c +++ b/client/gtk2/ibusimcontext.c @@ -420,10 +420,11 @@ _process_key_event_done (GObject *object, gdk_event_get_device (event), gdk_event_get_time (event), gdk_key_event_get_keycode (event), - gdk_event_get_modifier_state (event) | IBUS_IGNORED_MASK, + (gdk_event_get_modifier_state (event) | IBUS_IGNORED_MASK) & ~IBUS_PREFILTER_MASK, 0); #else ((GdkEventKey *)event)->state |= IBUS_IGNORED_MASK; + ((GdkEventKey *)event)->state &= ~IBUS_PREFILTER_MASK; gdk_event_put (event); #endif } @@ -646,8 +647,10 @@ _key_snooper_cb (GtkWidget *widget, if (G_UNLIKELY (event->state & IBUS_HANDLED_MASK)) return TRUE; - if (G_UNLIKELY (event->state & IBUS_IGNORED_MASK)) - return FALSE; + if (!(event->state & IBUS_PREFILTER_MASK)) { + if (G_UNLIKELY(event->state & IBUS_IGNORED_MASK)) + return FALSE; + } do { if (_fake_context != ibuscontext) @@ -1142,7 +1145,7 @@ ibus_im_context_filter_keypress (GtkIMContext *context, GdkModifierType state = gdk_event_get_modifier_state (event); if (state & IBUS_HANDLED_MASK) return TRUE; - if (state & IBUS_IGNORED_MASK) + if (state & IBUS_IGNORED_MASK && !(state & IBUS_PREFILTER_MASK)) return ibus_im_context_commit_event (ibusimcontext, event); } #else @@ -1152,7 +1155,7 @@ ibus_im_context_filter_keypress (GtkIMContext *context, /* Do not call gtk_im_context_filter_keypress() because * gtk_im_context_simple_filter_keypress() binds Ctrl-Shift-u */ - if (event->state & IBUS_IGNORED_MASK) + if (event->state & IBUS_IGNORED_MASK && !(event->state & IBUS_PREFILTER_MASK)) return ibus_im_context_commit_event (ibusimcontext, event); /* XXX it is a workaround for some applications do not set client diff --git a/src/ibustypes.h b/src/ibustypes.h index a8eee3192..825df31cb 100644 --- a/src/ibustypes.h +++ b/src/ibustypes.h @@ -53,6 +53,7 @@ * @IBUS_BUTTON3_MASK: Mouse button 3 (right) is activated. * @IBUS_BUTTON4_MASK: Mouse button 4 (scroll up) is activated. * @IBUS_BUTTON5_MASK: Mouse button 5 (scroll down) is activated. + * @IBUS_PREFILTER_MASK: Prefilter mask indicates the event has been prefiltered by the engine. * @IBUS_HANDLED_MASK: Handled mask indicates the event has been handled by ibus. * @IBUS_FORWARD_MASK: Forward mask indicates the event has been forward from ibus. * @IBUS_IGNORED_MASK: It is an alias of IBUS_FORWARD_MASK. @@ -63,7 +64,7 @@ * @IBUS_MODIFIER_MASK: Modifier mask for the all the masks above. * * Handles key modifier such as control, shift and alt and release event. - * Note that nits 15 - 25 are currently unused, while bit 29 is used internally. + * Note that bits 15 - 22 are currently unused, while bit 29 is used internally. */ typedef enum { @@ -82,10 +83,11 @@ typedef enum IBUS_BUTTON5_MASK = 1 << 12, /* The next few modifiers are used by XKB, so we skip to the end. - * Bits 15 - 23 are currently unused. Bit 29 is used internally. + * Bits 15 - 22 are currently unused. Bit 29 is used internally. */ /* ibus mask */ + IBUS_PREFILTER_MASK= 1 << 23, IBUS_HANDLED_MASK = 1 << 24, IBUS_FORWARD_MASK = 1 << 25, IBUS_IGNORED_MASK = IBUS_FORWARD_MASK, @@ -96,7 +98,7 @@ typedef enum IBUS_RELEASE_MASK = 1 << 30, - IBUS_MODIFIER_MASK = 0x5f001fff + IBUS_MODIFIER_MASK = 0x5f801fff } IBusModifierType; /** From 1d9fc3145d177f151e4d3a0ed2d0de4515221482 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 18 Aug 2022 20:00:17 +0200 Subject: [PATCH 2/2] src: Add IBUS_CAP_PREFILTER to IBusCapabilite This allows engines to detect whether they are dealing with an ibus version that was compiled with prefilter support. --- client/gtk2/ibusimcontext.c | 5 +++++ configure.ac | 13 +++++++++++++ src/ibustypes.h | 2 ++ 3 files changed, 20 insertions(+) diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c index 421791f4d..c01a7c2ac 100644 --- a/client/gtk2/ibusimcontext.c +++ b/client/gtk2/ibusimcontext.c @@ -987,6 +987,11 @@ ibus_im_context_init (GObject *obj) #else ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS; #endif + +#ifdef ENABLE_PREFILTER + ibusimcontext->caps |= IBUS_CAP_PREFILTER; +#endif + if (_use_sync_mode != 1) ibusimcontext->caps |= IBUS_CAP_SYNC_PROCESS_KEY; diff --git a/configure.ac b/configure.ac index 764eba685..8a6bbb516 100644 --- a/configure.ac +++ b/configure.ac @@ -608,6 +608,18 @@ else enable_surrounding_text="no (disabled, use --enable-surrounding-text to enable)" fi +# --disable-prefilter option +AC_ARG_ENABLE(prefilter, + AS_HELP_STRING([--disable-prefilter], + [Disable prefilter support]), + [enable_prefilter=$enableval], + [enable_prefilter=yes] +) +if test x"$enable_prefilter" = x"yes"; then + AC_DEFINE(ENABLE_PREFILTER, TRUE, [Enable prefilter support]) + enable_prefilter="yes (enabled, use --disable-prefilter to disable)" +fi + # --disable-ui AC_ARG_ENABLE(ui, AS_HELP_STRING([--disable-ui], @@ -886,6 +898,7 @@ Build options: No snooper regexes "$NO_SNOOPER_APPS" Panel icon "$IBUS_ICON_KEYBOARD" Enable surrounding-text $enable_surrounding_text + Enable prefilter $enable_prefilter Enable libnotify $enable_libnotify Enable Emoji dict $enable_emoji_dict Unicode Emoji directory $UNICODE_EMOJI_DIR diff --git a/src/ibustypes.h b/src/ibustypes.h index 825df31cb..056d9046a 100644 --- a/src/ibustypes.h +++ b/src/ibustypes.h @@ -114,6 +114,7 @@ typedef enum * @IBUS_CAP_SYNC_PROCESS_KEY: Asynchronous process key events are not * supported and the ibus_engine_forward_key_event() should not be * used for the return value of #IBusEngine::process_key_event(). + * @IBUS_CAP_PREFILTER: ibus is compiled with prefilter support. * * Capability flags of UI. */ @@ -126,6 +127,7 @@ typedef enum { IBUS_CAP_SURROUNDING_TEXT = 1 << 5, IBUS_CAP_OSK = 1 << 6, IBUS_CAP_SYNC_PROCESS_KEY = 1 << 7, + IBUS_CAP_PREFILTER = 1 << 8, } IBusCapabilite; /**