From cfeb9e820ef18174fc3fa74d425bc8f62da54531 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 8 Jul 2021 18:29:22 +0200 Subject: [PATCH] chore(linux): Implement Linux side of caps-lock action processing --- linux/ibus-keyman/configure.ac | 5 + linux/ibus-keyman/src/Makefile.am | 4 + linux/ibus-keyman/src/engine.c | 263 +++++++++++++++++------------- 3 files changed, 157 insertions(+), 115 deletions(-) diff --git a/linux/ibus-keyman/configure.ac b/linux/ibus-keyman/configure.ac index cc0d79ca6f..9556a87146 100644 --- a/linux/ibus-keyman/configure.ac +++ b/linux/ibus-keyman/configure.ac @@ -58,6 +58,11 @@ PKG_CHECK_MODULES(GTK, [ gtk+-3.0 >= 2.4 ]) +# Check X11 +PKG_CHECK_MODULES(X11, [ + x11 >= 1.6 +]) + # check atkspi 2.0 #PKG_CHECK_MODULES(ATSPI, [ # atspi-2 >= 2.0 diff --git a/linux/ibus-keyman/src/Makefile.am b/linux/ibus-keyman/src/Makefile.am index b1bbe6ca64..476f1d4000 100644 --- a/linux/ibus-keyman/src/Makefile.am +++ b/linux/ibus-keyman/src/Makefile.am @@ -22,6 +22,7 @@ AM_CFLAGS = \ @IBUS_CFLAGS@ \ @GTK_CFLAGS@ \ @JSON_GLIB_CFLAGS@ \ + @X11_CFLAGS@ \ @KEYMAN_PROC_CFLAGS@ \ -DPKGDATADIR=\"$(pkgdatadir)\" \ $(NULL) @@ -29,6 +30,7 @@ AM_CFLAGS = \ AM_LDFLAGS = \ @IBUS_LIBS@ \ @GTK_LIBS@ \ + @X11_LIBS@ \ @JSON_GLIB_LIBS@ \ @KEYMAN_PROC_LIBS@ \ $(NULL) @@ -73,6 +75,7 @@ ibus_engine_keyman_SOURCES = \ ibus_engine_keyman_CFLAGS = \ @IBUS_CFLAGS@ \ @GTK_CFLAGS@ \ + @X11_CFLAGS@ \ @JSON_GLIB_CFLAGS@ \ @KEYMAN_PROC_CFLAGS@ \ -DPKGDATADIR=\"$(pkgdatadir)\" \ @@ -81,6 +84,7 @@ ibus_engine_keyman_CFLAGS = \ ibus_engine_keyman_LDFLAGS = \ @GTK_LIBS@ \ @IBUS_LIBS@ \ + @X11_LIBS@ \ @JSON_GLIB_LIBS@ \ @KEYMAN_PROC_LIBS@ \ $(NULL) diff --git a/linux/ibus-keyman/src/engine.c b/linux/ibus-keyman/src/engine.c index 57c1e58afb..3b02cf705e 100644 --- a/linux/ibus-keyman/src/engine.c +++ b/linux/ibus-keyman/src/engine.c @@ -27,6 +27,12 @@ #include #include + +#ifdef GDK_WINDOWING_X11 +#include +#include +#endif + #include #include "keymanutil.h" @@ -41,6 +47,7 @@ #define KEYMAN_RCTRL 97 #define KEYMAN_RALT 100 #define KEYMAN_CAPS 0x3a +#define KEYMAN_CAPS_KEYSYM IBUS_KEY_Caps_Lock typedef struct _IBusKeymanEngine IBusKeymanEngine; typedef struct _IBusKeymanEngineClass IBusKeymanEngineClass; @@ -63,6 +70,9 @@ struct _IBusKeymanEngine { IBusLookupTable *table; IBusProperty *status_prop; IBusPropList *prop_list; +#ifdef GDK_WINDOWING_X11 + Display *xdisplay; +#endif }; struct _IBusKeymanEngineClass { @@ -238,32 +248,34 @@ static void reset_context(IBusEngine *engine) } static void -ibus_keyman_engine_init (IBusKeymanEngine *keyman) -{ - keyman->status_prop = ibus_property_new ("status", - PROP_TYPE_NORMAL, - NULL, - NULL, - NULL, - TRUE, - FALSE, - 0, - NULL); - g_object_ref_sink(keyman->status_prop); - keyman->prop_list = ibus_prop_list_new (); - g_object_ref_sink(keyman->prop_list); - ibus_prop_list_append (keyman->prop_list, keyman->status_prop); +ibus_keyman_engine_init(IBusKeymanEngine *keyman) { + gdk_init(NULL, NULL); + keyman->status_prop = ibus_property_new("status", PROP_TYPE_NORMAL, NULL, NULL, NULL, TRUE, FALSE, 0, NULL); + g_object_ref_sink(keyman->status_prop); + keyman->prop_list = ibus_prop_list_new(); + g_object_ref_sink(keyman->prop_list); + ibus_prop_list_append(keyman->prop_list, keyman->status_prop); - keyman->table = ibus_lookup_table_new (9, 0, TRUE, TRUE); - g_object_ref_sink(keyman->table); - keyman->state = NULL; + keyman->table = ibus_lookup_table_new(9, 0, TRUE, TRUE); + g_object_ref_sink(keyman->table); + keyman->state = NULL; +#ifdef GDK_WINDOWING_X11 + keyman->xdisplay = NULL; + if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) { + keyman->xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); + } else +#endif + { + g_error("unsupported GDK backend"); + } } static GObject* -ibus_keyman_engine_constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) -{ +ibus_keyman_engine_constructor( + GType type, + guint n_construct_params, + GObjectConstructParam *construct_params +) { IBusKeymanEngine *keyman; IBusEngine *engine; IBusText *text; @@ -584,7 +596,8 @@ static gboolean ok_for_single_backspace(const km_kbp_action_item *action_items, return TRUE; } -static gboolean process_unicode_char_action( +static gboolean +process_unicode_char_action( IBusKeymanEngine *keyman, const km_kbp_action_item *action_item ) { @@ -691,7 +704,8 @@ process_backspace_action( return TRUE; } -static gboolean process_persist_action( +static gboolean +process_persist_action( IBusKeymanEngine *keyman, const km_kbp_action_item *action_item ) { @@ -735,6 +749,23 @@ static gboolean process_invalidate_context_action(IBusEngine *engine) { return TRUE; } +static gboolean +process_capslock_action( + IBusKeymanEngine *keyman, + const km_kbp_action_item *action_item +) { + g_message("**** %s caps-lock", action_item->capsLock ? "Enable" : "Disable"); + +#ifdef GDK_WINDOWING_X11 + if (keyman->xdisplay) { + XkbLockModifiers(keyman->xdisplay, XkbUseCoreKbd, LockMask, action_item->capsLock ? LockMask : 0); + + XSync(keyman->xdisplay, False); + } +#endif + return TRUE; +} + static gboolean process_end_action(IBusKeymanEngine *keyman) { keyman->firstsurrogate = 0; if (keyman->char_buffer != NULL) { @@ -750,7 +781,8 @@ static gboolean process_end_action(IBusKeymanEngine *keyman) { return TRUE; } -static gboolean process_actions( +static gboolean +process_actions( IBusEngine *engine, const km_kbp_action_item *action_items, size_t num_action_items @@ -786,6 +818,10 @@ static gboolean process_actions( g_message("INVALIDATE_CONTEXT action %d/%d", i + 1, (int)num_action_items); continue_with_next_action = process_invalidate_context_action(engine); break; + case KM_KBP_IT_CAPSLOCK: + g_message("CAPSLOCK action %d/%d", i + 1, (int)num_action_items); + continue_with_next_action = process_capslock_action(keyman, &action_items[i]); + break; case KM_KBP_IT_END: g_message("END action %d/%d", i + 1, (int)num_action_items); continue_with_next_action = process_end_action(keyman); @@ -800,103 +836,100 @@ static gboolean process_actions( } static gboolean -ibus_keyman_engine_process_key_event (IBusEngine *engine, - guint keyval, - guint keycode, - guint state) -{ - IBusKeymanEngine *keyman = (IBusKeymanEngine *) engine; +ibus_keyman_engine_process_key_event( + IBusEngine *engine, + guint keyval, + guint keycode, + guint state +) { + IBusKeymanEngine *keyman = (IBusKeymanEngine *)engine; - g_message("DAR: ibus_keyman_engine_process_key_event - keyval=%02i, keycode=%02i, state=%02x", keyval, keycode, state); + gboolean isKeyDown = !(state & IBUS_RELEASE_MASK); - gboolean isKeyDown = !!(state & IBUS_RELEASE_MASK); + g_message("-----------------------------------------------------------------------------------------------------------------"); + g_message( + "DAR: ibus_keyman_engine_process_key_event - keyval=0x%02x keycode=0x%02x, state=0x%02x, isKeyDown=%d", keyval, keycode, + state, isKeyDown); - // REVIEW: why don't we handle these keys? - switch (keycode) { - case KEYMAN_LCTRL: - keyman->lctrl_pressed = isKeyDown; - break; - case KEYMAN_RCTRL: - keyman->rctrl_pressed = isKeyDown; - break; - case KEYMAN_LALT: - keyman->lalt_pressed = isKeyDown; - break; - case KEYMAN_RALT: - keyman->ralt_pressed = isKeyDown; - break; + // REVIEW: why don't we handle these keys? + switch (keycode) { + case KEYMAN_LCTRL: + keyman->lctrl_pressed = isKeyDown; + break; + case KEYMAN_RCTRL: + keyman->rctrl_pressed = isKeyDown; + break; + case KEYMAN_LALT: + keyman->lalt_pressed = isKeyDown; + break; + case KEYMAN_RALT: + keyman->ralt_pressed = isKeyDown; + break; + } + + if (keycode < 0 || keycode > 255) { + g_warning("keycode %d out of range", keycode); + return FALSE; + } + + if (keycode_to_vk[keycode] == 0) { // key we don't handle + return FALSE; + } + + // keyman modifiers are different from X11/ibus + uint16_t km_mod_state = 0; + if (state & IBUS_SHIFT_MASK) { + km_mod_state |= KM_KBP_MODIFIER_SHIFT; + } + if (state & IBUS_MOD5_MASK) { + km_mod_state |= KM_KBP_MODIFIER_RALT; + g_message("modstate KM_KBP_MODIFIER_RALT from IBUS_MOD5_MASK"); + } + if (state & IBUS_MOD1_MASK) { + if (keyman->ralt_pressed) { + km_mod_state |= KM_KBP_MODIFIER_RALT; + g_message("modstate KM_KBP_MODIFIER_RALT from ralt_pressed"); } + if (keyman->lalt_pressed) { + km_mod_state |= KM_KBP_MODIFIER_LALT; + g_message("modstate KM_KBP_MODIFIER_LALT from lalt_pressed"); + } + } + if (state & IBUS_CONTROL_MASK) { + if (keyman->rctrl_pressed) { + km_mod_state |= KM_KBP_MODIFIER_RCTRL; + g_message("modstate KM_KBP_MODIFIER_RCTRL from rctrl_pressed"); + } + if (keyman->lctrl_pressed) { + km_mod_state |= KM_KBP_MODIFIER_LCTRL; + g_message("modstate KM_KBP_MODIFIER_LCTRL from lctrl_pressed"); + } + } + if (state & IBUS_LOCK_MASK) { + km_mod_state |= KM_KBP_MODIFIER_CAPS; + } + g_message("before process key event"); + km_kbp_context *context = km_kbp_state_context(keyman->state); + g_free(get_current_context_text(context)); + g_message("DAR: ibus_keyman_engine_process_key_event - km_mod_state=0x%x", km_mod_state); + km_kbp_status event_status = km_kbp_process_event(keyman->state, keycode_to_vk[keycode], km_mod_state, isKeyDown); + context = km_kbp_state_context(keyman->state); + g_message("after process key event"); + g_free(get_current_context_text(context)); - if (keycode < 0 || keycode > 255) { - g_warning("keycode %d out of range", keycode); - return FALSE; - } + // km_kbp_state_action_items to get action items + size_t num_action_items; + g_free(keyman->char_buffer); + keyman->char_buffer = NULL; + const km_kbp_action_item *action_items = km_kbp_state_action_items(keyman->state, &num_action_items); - if (keycode_to_vk[keycode] == 0) { // key we don't handle - return FALSE; - } + if (!process_actions(engine, action_items, num_action_items)) + return FALSE; - // keyman modifiers are different from X11/ibus - uint16_t km_mod_state = 0; - if (state & IBUS_SHIFT_MASK) - { - km_mod_state |= KM_KBP_MODIFIER_SHIFT; - } - if (state & IBUS_MOD5_MASK) - { - km_mod_state |= KM_KBP_MODIFIER_RALT; - g_message("modstate KM_KBP_MODIFIER_RALT from IBUS_MOD5_MASK"); - } - if (state & IBUS_MOD1_MASK) - { - if (keyman->ralt_pressed) { - km_mod_state |= KM_KBP_MODIFIER_RALT; - g_message("modstate KM_KBP_MODIFIER_RALT from ralt_pressed"); - } - if (keyman->lalt_pressed) { - km_mod_state |= KM_KBP_MODIFIER_LALT; - g_message("modstate KM_KBP_MODIFIER_LALT from lalt_pressed"); - } - } - if (state & IBUS_CONTROL_MASK) - { - if (keyman->rctrl_pressed) { - km_mod_state |= KM_KBP_MODIFIER_RCTRL; - g_message("modstate KM_KBP_MODIFIER_RCTRL from rctrl_pressed"); - } - if (keyman->lctrl_pressed) { - km_mod_state |= KM_KBP_MODIFIER_LCTRL; - g_message("modstate KM_KBP_MODIFIER_LCTRL from lctrl_pressed"); - } - } - if (state & IBUS_LOCK_MASK) - { - km_mod_state |= KM_KBP_MODIFIER_CAPS; - } - g_message("before process key event"); - km_kbp_context *context = km_kbp_state_context(keyman->state); - g_free(get_current_context_text(context)); - g_message("DAR: ibus_keyman_engine_process_key_event - km_mod_state=%x", km_mod_state); - km_kbp_status event_status = - km_kbp_process_event(keyman->state, keycode_to_vk[keycode], km_mod_state, isKeyDown); - context = km_kbp_state_context(keyman->state); - g_message("after process key event"); - g_free(get_current_context_text(context)); - - // km_kbp_state_action_items to get action items - size_t num_action_items; - g_free(keyman->char_buffer); - keyman->char_buffer = NULL; - const km_kbp_action_item *action_items = km_kbp_state_action_items(keyman->state, - &num_action_items); - - if (!process_actions(engine, action_items, num_action_items)) - return FALSE; - - context = km_kbp_state_context(keyman->state); - g_message("after processing all actions"); - g_free(get_current_context_text(context)); - return TRUE; + context = km_kbp_state_context(keyman->state); + g_message("after processing all actions"); + g_free(get_current_context_text(context)); + return TRUE; } static void