Skip to content

Commit

Permalink
bus: Handle IME switcher in BusIBusImpl
Browse files Browse the repository at this point in the history
IME Switcher is now managed with the activate input context only in
Wayland since the global hotkey is not available and handling the
shortcut keys is moved to ibus-daemon from ibus-ui-gtk3.

"Since: 1.5.00" is added to C header files to avoid Vala build
failures until IBus 1.5.29 will be released.

BUG=#2408
  • Loading branch information
fujiwarat committed Jul 27, 2023
1 parent 8923456 commit 42be272
Show file tree
Hide file tree
Showing 14 changed files with 682 additions and 22 deletions.
3 changes: 2 additions & 1 deletion bindings/vala/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# ibus - The Input Bus
#
# Copyright (c) 2007-2016 Peng Huang <shawn.p.huang@gmail.com>
# Copyright (c) 2017-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
# Copyright (c) 2017-2023 Takao Fujiwara <takao.fujiwara1@gmail.com>
# Copyright (c) 2007-2017 Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
Expand Down Expand Up @@ -87,6 +87,7 @@ EXTRA_DIST = \
ibus-emoji-dialog-1.0.deps \
config.vapi \
gdk-wayland.vapi \
glibmacro.vapi \
xi.vapi \
$(NULL)

Expand Down
5 changes: 5 additions & 0 deletions bindings/vala/glibmacro.vapi
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "glib.h")]
namespace GLibMacro
{
public const string G_STRFUNC;
}
167 changes: 167 additions & 0 deletions bus/ibusimpl.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct _BusIBusImpl {
gchar *global_engine_name;
gchar *global_previous_engine_name;
GVariant *extension_register_keys;
IBusProcessKeyEventData *ime_switcher_keys;
};

struct _BusIBusImplClass {
Expand Down Expand Up @@ -196,6 +197,15 @@ static const gchar introspection_xml[] =
" name='org.freedesktop.DBus.Property.EmitsChangedSignal'\n"
" value='true' />\n"
" </property>\n"
" <property name='GlobalShortcutKeys' type='(ya(uuu))' access='write'>\n"
" <annotation\n"
" name='org.freedesktop.DBus.Property.EmitsChangedSignal'\n"
" value='true' />\n"
" <annotation name='org.gtk.GDBus.Since'\n"
" value='1.5.29' />\n"
" <annotation name='org.gtk.GDBus.DocString'\n"
" value='Stability: Unstable' />\n"
" </property>\n"
" <property name='EmbedPreeditText' type='b' access='readwrite'>\n"
" <annotation\n"
" name='org.freedesktop.DBus.Property.EmitsChangedSignal'\n"
Expand Down Expand Up @@ -227,6 +237,15 @@ static const gchar introspection_xml[] =
" <signal name='GlobalEngineChanged'>\n"
" <arg type='s' name='engine_name' />\n"
" </signal>\n"
" <signal name='GlobalShortcutKeyResponded'>\n"
" <arg type='y' name='type' />\n"
" <arg type='b' name='pressed' />\n"
" <arg type='b' name='backward' />\n"
" <annotation name='org.gtk.GDBus.Since'\n"
" value='1.5.29' />\n"
" <annotation name='org.gtk.GDBus.DocString'\n"
" value='Stability: Unstable' />\n"
" </signal>\n"
" <property name='ActiveEngines' type='av' access='read' />\n"
" <method name='GetAddress'>\n"
" <arg direction='out' type='s' name='address' />\n"
Expand Down Expand Up @@ -1922,6 +1941,56 @@ _ibus_set_embed_preedit_text (BusIBusImpl *ibus,
return TRUE;
}

/**
* _ibus_set_global_shortcut_keys:
*
* Implement the "GlobalShortcutKeys" method call of the
* org.freedesktop.IBus interface.
*/
static gboolean
_ibus_set_global_shortcut_keys (BusIBusImpl *ibus,
GDBusConnection *connection,
GVariant *value,
GError **error)
{
guchar gtype;
GVariantIter *iter = NULL;
gsize size, i;
guint keyval, keycode, state;
IBusProcessKeyEventData *keys;

g_variant_get_child (value, 0, "y", &gtype);
g_variant_get_child (value, 1, "a(uuu)", &iter);
size = g_variant_iter_n_children (iter);
g_return_val_if_fail (size > 0, FALSE);
keys = g_slice_alloc (sizeof (IBusProcessKeyEventData) * (size + 1));
i = 0;
while (g_variant_iter_loop (iter, "(uuu)", &keyval, &keycode, &state)) {
keys[i].keyval = keyval;
keys[i].keycode = keycode;
keys[i].state = state;
i++;
}
g_variant_iter_free (iter);
if (!i) {
g_slice_free1 (sizeof (IBusProcessKeyEventData) * (size + 1), keys);
return FALSE;
}
keys[i].keyval = keys[i].keycode = keys[i].state = 0;
switch (gtype) {
case IBUS_BUS_GLOBAL_BINDING_TYPE_IME_SWITCHER:
if (ibus->ime_switcher_keys) {
for (i = 0; ibus->ime_switcher_keys[i].keyval; ++i) {}
g_slice_free1 (sizeof (IBusProcessKeyEventData) * (i + 1),
ibus->ime_switcher_keys);
}
ibus->ime_switcher_keys = keys;
break;
default:;
}
return TRUE;
}

/**
* bus_ibus_impl_service_method_call:
*
Expand Down Expand Up @@ -2068,6 +2137,7 @@ bus_ibus_impl_service_set_property (IBusService *service,
} methods [] = {
{ "PreloadEngines", _ibus_set_preload_engines },
{ "EmbedPreeditText", _ibus_set_embed_preedit_text },
{ "GlobalShortcutKeys", _ibus_set_global_shortcut_keys },
};

if (error)
Expand Down Expand Up @@ -2416,3 +2486,100 @@ bus_ibus_impl_get_engine_active_surrounding_text_table (BusIBusImpl *ibus)

return ibus->engine_active_surrounding_text_table;
}

static guint
keyval_to_modifier(guint keyval)
{
switch(keyval) {
case IBUS_KEY_Control_L:
case IBUS_KEY_Control_R:
return IBUS_CONTROL_MASK;
case IBUS_KEY_Shift_L:
case IBUS_KEY_Shift_R:
return IBUS_SHIFT_MASK;
case IBUS_KEY_Caps_Lock:
return IBUS_LOCK_MASK;
case IBUS_KEY_Alt_L:
case IBUS_KEY_Alt_R:
return IBUS_MOD1_MASK;
case IBUS_KEY_Meta_L:
case IBUS_KEY_Meta_R:
return IBUS_META_MASK;
case IBUS_KEY_Super_L:
case IBUS_KEY_Super_R:
return IBUS_MOD4_MASK;
case IBUS_KEY_Hyper_L:
case IBUS_KEY_Hyper_R:
return IBUS_HYPER_MASK;
default:;
}
return 0;
}

gboolean
bus_ibus_impl_process_key_event (BusIBusImpl *ibus,
guint keyval,
guint keycode,
guint state)
{
int i;
guint bind_keyval = 0;
guint bind_state = 0;
static guint binding_state = 0;
gboolean is_pressed = (state & IBUS_RELEASE_MASK) == 0;
gboolean is_backward = FALSE;
gboolean hit = FALSE;
IBusBusGlobalBindingType type = IBUS_BUS_GLOBAL_BINDING_TYPE_ANY;

g_assert (BUS_IS_IBUS_IMPL (ibus));
if (!ibus->ime_switcher_keys)
return FALSE;
state &= ~IBUS_RELEASE_MASK;
for (i = 0; ibus->ime_switcher_keys[i].keyval; ++i) {
bind_keyval = ibus->ime_switcher_keys[i].keyval;
bind_state = ibus->ime_switcher_keys[i].state;
is_backward = ibus->ime_switcher_keys[i].keycode != 0;
if (keyval == bind_keyval && state == bind_state) {
if (state != 0) {
/* If Super-space is pressed */
if (is_pressed)
binding_state = bind_state;
/* If Super is pressed but space is released */
else if (!is_pressed && binding_state)
break;
}
hit = TRUE;
type = IBUS_BUS_GLOBAL_BINDING_TYPE_IME_SWITCHER;
break;
} else if (binding_state && !is_pressed) {
guint released_modifier = keyval_to_modifier(keyval);
binding_state &= state;
binding_state &= ~released_modifier;
/* If both Super and space is released */
if (!binding_state) {
hit = TRUE;
type = IBUS_BUS_GLOBAL_BINDING_TYPE_IME_SWITCHER;
}
break;
}
}
if (hit) {
g_assert (bind_keyval);
GVariant *variant = g_variant_new (
"(ybb)",
type,
is_pressed,
is_backward);
/* TODO: dbus-monitor can observe the key release D-Bus signal is sent
* immediately but IBusPanelService sometimes gets the signal
* with a delay because the D-Bus receives seems depend on
* the GMainLoop. The delay is resolved with another key press
* as the workaround.
* I also tried g_idle_add() for bus_ibus_impl_emit_signal() and
* a D-Bus method from BusPanelProxy instead of this D-Bus signal
* but this problem couldn't be resolved.
*/
bus_ibus_impl_emit_signal (ibus, "GlobalShortcutKeyResponded", variant);
}
return hit;
}
8 changes: 7 additions & 1 deletion bus/ibusimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* vim:set et sts=4: */
/* bus - The Input Bus
* Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
* Copyright (C) 2022 Takao Fujiwara <takao.fujiwara1@gmail.com>
* Copyright (C) 2022-2023 Takao Fujiwara <takao.fujiwara1@gmail.com>
* Copyright (C) 2008-2022 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
Expand Down Expand Up @@ -100,5 +100,11 @@ GHashTable *bus_ibus_impl_get_engine_focus_id_table
(BusIBusImpl *ibus);
GHashTable *bus_ibus_impl_get_engine_active_surrounding_text_table
(BusIBusImpl *ibus);
gboolean bus_ibus_impl_process_key_event (BusIBusImpl *ibus,
guint keyval,
guint
keycode,
guint state);

G_END_DECLS
#endif
28 changes: 27 additions & 1 deletion bus/inputcontext.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,18 @@ _ic_process_key_event (BusInputContext *context,
if (context->use_post_process_key_event)
context->processing_key_event = TRUE;
g_variant_get (parameters, "(uuu)", &keyval, &keycode, &modifiers);
if (bus_ibus_impl_process_key_event (bus_ibus_impl_get_default (),
keyval,
keycode,
modifiers)) {
/* If the shortcut key hits, it should return TRUE.
* Otherwise a space would be inserted into the active input-context
* by pressing Super-space.
*/
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(b)", TRUE));
return;
}
if (G_UNLIKELY (!context->has_focus)) {
/* workaround: set focus if context does not have focus */
BusInputContext *focused_context =
Expand Down Expand Up @@ -3249,7 +3261,21 @@ bus_input_context_set_emoji_extension (BusInputContext *context,
g_object_ref (context->emoji_extension);
if (!context->connection)
return;
bus_input_context_show_preedit_text (context, TRUE);
/* Use bus_input_context_update_preedit_text() instead of
* bus_input_context_show_preedit_text() because the Wayland
* input-method protocol requires preedit when Escape key
* on Emojier causes another focus-in event.
*/
if (!context->preedit_visible) {
g_object_ref (context->preedit_text);
bus_input_context_update_preedit_text (context,
context->preedit_text,
context->preedit_cursor_pos,
TRUE,
context->preedit_mode,
TRUE);
g_object_unref (context->preedit_text);
}
bus_panel_proxy_set_cursor_location (context->emoji_extension,
context->x,
context->y,
Expand Down
1 change: 1 addition & 0 deletions bus/marshalers.list
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ VOID:STRING
VOID:STRING,INT
VOID:UINT,UINT
VOID:UINT,UINT,UINT
VOID:UINT,BOOLEAN,BOOLEAN
VOID:VARIANT
VOID:VOID
Loading

0 comments on commit 42be272

Please sign in to comment.