From 98ae1c6dbd279e17ef3c20493a37c959f1b1e61f Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Fri, 30 Mar 2012 12:36:08 +0900 Subject: [PATCH 4/4] Add virtual keyboard support. --- configure.ac | 17 +++ src/Makefile.am | 5 + src/default.xml.in.in | 111 +++++++++++++++++++ src/engine.c | 289 +++++++++++++++++++++++++++++++++++++++++++++++++ src/m17nutil.c | 10 ++- src/m17nutil.h | 3 + 6 files changed, 434 insertions(+), 1 deletions(-) diff --git a/configure.ac b/configure.ac index be9728d..3daf917 100644 --- a/configure.ac +++ b/configure.ac @@ -88,6 +88,23 @@ fi AM_CONDITIONAL([HAVE_GTK],[test x$with_gtk != xno]) +dnl check eekboard for virtual keyboard +AC_MSG_CHECKING([whether you enable eekboard]) +AC_ARG_ENABLE(eekboard, + AS_HELP_STRING([--enable-eekboard=no/yes], + [Enable eekboard default=yes]), + enable_eekboard=$enableval, + enable_eekboard=yes) + +if test x$enable_eekboard = xyes; then + PKG_CHECK_MODULES([EEKBOARD], [eekboard-0.90], , enable_xtest=no) + if test x$enable_eekboard = xyes; then + AC_DEFINE([HAVE_EEKBOARD], [1], [Define if eekboard is found]) + fi +fi +AM_CONDITIONAL(ENABLE_EEKBOARD, [test x$enable_eekboard = xyes]) +AC_MSG_RESULT($enable_eekboard) + # check if minput_list, which is available in m17n-lib 1.6.2+ (CVS) save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" diff --git a/src/Makefile.am b/src/Makefile.am index 39d6523..93e7dfd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -65,10 +65,15 @@ ibus_engine_m17n_SOURCES = \ engine.c \ engine.h \ $(NULL) +ibus_engine_m17n_CFLAGS = \ + @EEKBOARD_CFLAGS@ \ + $(AM_CFLAGS) \ + $(NULL) ibus_engine_m17n_LDADD = \ libm17ncommon.la \ @IBUS_LIBS@ \ @M17N_LIBS@ \ + @EEKBOARD_LIBS@ \ $(NULL) if HAVE_GTK diff --git a/src/default.xml.in.in b/src/default.xml.in.in index fda4f30..cbc29af 100644 --- a/src/default.xml.in.in +++ b/src/default.xml.in.in @@ -11,6 +11,7 @@ 0 FALSE + us @@ -440,4 +441,114 @@ m17n:zh:tonepy* + + + + m17n:ar:kbd + ar,us + + + m17n:be:kbd + be,us + + + m17n:fa:kbd + fa,us + + + m17n:he:kbd + he,us + + + m17n:kk:kbd + kk,us + + + m17n:ks:kbd + ks,us + + + m17n:my:kbd + my,us + + + m17n:ru:kbd + ru,us + + + m17n:ua:kbd + ua,us + + + m17n:ug:kbd + ug,us + + + m17n:be:kbd + be,us + + + m17n:th:* + th,us + + + m17n:zh:bopomofo + zh-bopomofo,us + + + m17n:as:inscript + as-inscript,us + + + m17n:bn:inscript + bn-inscript,us + + + m17n:gu:inscript + gu-inscript,us + + + m17n:hi:inscript + hi-inscript,us + + + m17n:kn:inscript + kn-inscript,us + + + m17n:ks:inscript + kn-inscript,us + + + m17n:mai:inscript + mai-inscript,us + + + m17n:ml:inscript + ml-inscript,us + + + m17n:mr:inscript + mr-inscript,us + + + m17n:or:inscript + or-inscript,us + + + m17n:pa:inscript + pa-inscript,us + + + m17n:sd:inscript + sd-inscript,us + + + m17n:ta:inscript + ta-inscript,us + + + m17n:te:inscript + te-inscript,us + diff --git a/src/engine.c b/src/engine.c index efbce66..cd18e76 100644 --- a/src/engine.c +++ b/src/engine.c @@ -7,6 +7,9 @@ #include #include #include "m17nutil.h" +#ifdef HAVE_EEKBOARD +#include +#endif /* HAVE_EEKBOARD */ #include "engine.h" typedef struct _IBusM17NEngine IBusM17NEngine; @@ -18,10 +21,12 @@ struct _IBusM17NEngine { /* members */ MInputContext *context; IBusLookupTable *table; + IBusProperty *status_prop; #ifdef HAVE_SETUP IBusProperty *setup_prop; #endif /* HAVE_SETUP */ + IBusProperty *virtkbd_prop; IBusPropList *prop_list; }; @@ -34,9 +39,16 @@ struct _IBusM17NEngineClass { guint preedit_background; gint preedit_underline; gint lookup_table_orientation; + gchar *virtual_keyboard; gchar *title; MInputMethod *im; + +#ifdef HAVE_EEKBOARD + EekboardContext *econtext; + GSList *keyboards; + GSList *keyboards_head; +#endif /* HAVE_EEKBOARD */ }; /* functions prototype */ @@ -100,13 +112,184 @@ static IBusEngineClass *parent_class = NULL; static IBusConfig *config = NULL; +#ifdef HAVE_EEKBOARD +static EekboardClient *eekboard = NULL; + +static void +client_destroyed_cb (EekboardClient *client, + gpointer user_data) +{ + if (eekboard) { + g_object_unref (eekboard); + eekboard = NULL; + } +} + +static void +context_destroyed_cb (EekboardContext *context, + IBusM17NEngineClass *klass) +{ + if (klass->econtext) { + g_object_unref (klass->econtext); + klass->econtext = NULL; + } +} + +static EekboardContext * +create_context (IBusM17NEngineClass *klass) +{ + EekboardContext *context = eekboard_client_create_context (eekboard, + "ibus-m17n", + NULL); + g_signal_connect (context, "destroyed", + G_CALLBACK (context_destroyed_cb), klass); + + g_slist_free (klass->keyboards); + klass->keyboards = NULL; + + gchar **keyboards = g_strsplit (klass->virtual_keyboard, ",", -1); + gchar **p; + + for (p = keyboards; *p; p++) { + guint keyboard = eekboard_context_add_keyboard (context, + g_strstrip (*p), + NULL); + klass->keyboards = g_slist_prepend (klass->keyboards, + GUINT_TO_POINTER (keyboard)); + } + g_strfreev (keyboards); + + klass->keyboards = g_slist_reverse (klass->keyboards); + klass->keyboards_head = klass->keyboards; + + eekboard_context_set_keyboard (context, + GPOINTER_TO_UINT (klass->keyboards_head->data), + NULL); + return context; +} + +static void +key_activated_cb (EekboardContext *context, + guint keycode, + EekSymbol *symbol, + guint modifiers, + IBusM17NEngine *m17n) +{ + IBusM17NEngineClass *klass = (IBusM17NEngineClass *) G_OBJECT_GET_CLASS (m17n); + IBusEngine *engine = IBUS_ENGINE (m17n); + + if (EEK_IS_TEXT (symbol)) { + const gchar *string; + IBusText *text; + + string = eek_text_get_text (EEK_TEXT (symbol)); + text = ibus_text_new_from_static_string (string); + ibus_engine_commit_text (engine, text); + } else if (EEK_IS_KEYSYM (symbol)) { + guint keyval = eek_keysym_get_xkeysym (EEK_KEYSYM (symbol)); + ibus_engine_forward_key_event (engine, + keyval, + 0, + modifiers); + ibus_engine_forward_key_event (engine, + keyval, + 0, + modifiers | IBUS_RELEASE_MASK); + } else if (g_strcmp0 (eek_symbol_get_name (symbol), + "cycle-keyboard") == 0) { + klass->keyboards_head = g_slist_next (klass->keyboards_head); + if (klass->keyboards_head == NULL) + klass->keyboards_head = klass->keyboards; + eekboard_context_set_keyboard (klass->econtext, + GPOINTER_TO_UINT (klass->keyboards_head->data), + NULL); + } +} + +static void +init_eekboard () +{ + GDBusConnection *connection; + GError *error; + + error = NULL; + connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + if (connection == NULL) { + g_printerr ("Can't connect to the session bus: %s\n", + error->message); + g_error_free (error); + return; + } + + eek_init (); + + eekboard = eekboard_client_new (connection, NULL); + g_object_unref (connection); + + g_signal_connect (eekboard, "destroyed", + G_CALLBACK (client_destroyed_cb), NULL); +} +#endif /* HAVE_EEKBOARD */ + +static GType ibus_m17n_virtual_keyboard_implementation_type = 0; + +typedef enum { + IBUS_M17N_VIRTUAL_KEYBOARD_IMPLEMENTATION_EEKBOARD, + IBUS_M17N_VIRTUAL_KEYBOARD_IMPLEMENTATION_IOK +} IBusM17NVirtualKeyboardImplementation; + +#ifdef HAVE_EEKBOARD +static IBusM17NVirtualKeyboardImplementation virtual_keyboard_implementation = + IBUS_M17N_VIRTUAL_KEYBOARD_IMPLEMENTATION_EEKBOARD; +#else +static IBusM17NVirtualKeyboardImplementation virtual_keyboard_implementation = + IBUS_M17N_VIRTUAL_KEYBOARD_IMPLEMENTATION_IOK; +#endif + void ibus_m17n_init (IBusBus *bus) { + static const GEnumValue evalues[] = { + { IBUS_M17N_VIRTUAL_KEYBOARD_IMPLEMENTATION_EEKBOARD, + "IBUS_M17N_VIRTUAL_KEYBOARD_IMPLEMENTATION_EEKBOARD", + "eekboard" }, + { IBUS_M17N_VIRTUAL_KEYBOARD_IMPLEMENTATION_IOK, + "IBUS_M17N_VIRTUAL_KEYBOARD_IMPLEMENTATION_IOK", + "iok" } + }; + + GVariant *values; + config = ibus_bus_get_config (bus); if (config) g_object_ref_sink (config); ibus_m17n_init_common (); + + ibus_m17n_virtual_keyboard_implementation_type = + g_enum_register_static ("IBusM17NVirtualKeyboardImplementation", + evalues); + values = ibus_config_get_values (config, "engine/M17N"); + if (values != NULL) { + GVariant *value = + g_variant_lookup_value (values, + "virtual_keyboard_implementation", + G_VARIANT_TYPE_STRING); + if (value != NULL) { + GEnumClass *eclass = G_ENUM_CLASS (g_type_class_peek (ibus_m17n_virtual_keyboard_implementation_type)); + GEnumValue *evalue = g_enum_get_value_by_nick (eclass, g_variant_get_string (value, NULL)); + if (evalue != NULL) { + virtual_keyboard_implementation = evalue->value; + } + } + } + + if (virtual_keyboard_implementation == IBUS_M17N_VIRTUAL_KEYBOARD_IMPLEMENTATION_EEKBOARD) { +#ifdef HAVE_EEKBOARD + init_eekboard (); +#else + g_warning ("eekboard is not supported"); +#endif /* HAVE_EEKBOARD */ + } } static gboolean @@ -264,6 +447,7 @@ ibus_m17n_engine_class_init (IBusM17NEngineClass *klass) INVALID_COLOR; klass->preedit_underline = IBUS_ATTR_UNDERLINE_NONE; klass->lookup_table_orientation = IBUS_ORIENTATION_SYSTEM; + klass->virtual_keyboard = engine_config->virtual_keyboard; ibus_m17n_engine_config_free (engine_config); @@ -313,6 +497,11 @@ ibus_m17n_engine_class_init (IBusM17NEngineClass *klass) klass); klass->im = NULL; + +#if HAVE_EEKBOARD + if (eekboard) + klass->econtext = create_context (klass); +#endif /* HAVE_EEKBOARD */ } static void @@ -350,6 +539,7 @@ ibus_m17n_engine_init (IBusM17NEngine *m17n) { IBusText* label; IBusText* tooltip; + IBusM17NEngineClass *klass = (IBusM17NEngineClass *) G_OBJECT_GET_CLASS (m17n); m17n->prop_list = ibus_prop_list_new (); g_object_ref_sink (m17n->prop_list); @@ -382,6 +572,36 @@ ibus_m17n_engine_init (IBusM17NEngine *m17n) ibus_prop_list_append (m17n->prop_list, m17n->setup_prop); #endif /* HAVE_SETUP */ + label = ibus_text_new_from_string ("Screen Keyboard"); + tooltip = ibus_text_new_from_string ("Show screen keyboard"); + m17n->virtkbd_prop = ibus_property_new ("virtual-keyboard", + PROP_TYPE_NORMAL, + label, + "input-keyboard", + tooltip, + TRUE, + FALSE, + PROP_STATE_UNCHECKED, + NULL); + g_object_ref_sink (m17n->virtkbd_prop); + ibus_prop_list_append (m17n->prop_list, m17n->virtkbd_prop); + +#ifdef HAVE_EEKBOARD + if (eekboard != NULL) + ibus_property_set_visible (m17n->virtkbd_prop, TRUE); + else +#endif /* HAVE_EEKBOARD */ + { + gchar *lang = NULL, *name = NULL; + if (ibus_m17n_scan_class_name (G_OBJECT_CLASS_NAME (klass), + &lang, + &name) && + g_str_has_prefix (name, "inscript")) + ibus_property_set_visible (m17n->virtkbd_prop, TRUE); + g_free (lang); + g_free (name); + } + m17n->table = ibus_lookup_table_new (9, 0, TRUE, TRUE); g_object_ref_sink (m17n->table); m17n->context = NULL; @@ -467,6 +687,11 @@ ibus_m17n_engine_destroy (IBusM17NEngine *m17n) } #endif /* HAVE_SETUP */ + if (m17n->virtkbd_prop) { + g_object_unref (m17n->virtkbd_prop); + m17n->virtkbd_prop = NULL; + } + if (m17n->table) { g_object_unref (m17n->table); m17n->table = NULL; @@ -708,6 +933,14 @@ ibus_m17n_engine_enable (IBusEngine *engine) /* Issue a dummy ibus_engine_get_surrounding_text() call to tell input context that we will use surrounding-text. */ ibus_engine_get_surrounding_text (engine, NULL, NULL, NULL); + +#ifdef HAVE_EEKBOARD + if (eekboard) { + IBusM17NEngineClass *klass = (IBusM17NEngineClass *) G_OBJECT_GET_CLASS (m17n); + if (klass->econtext) + eekboard_client_push_context (eekboard, klass->econtext, NULL); + } +#endif /* HAVE_EEKBOARD */ } static void @@ -717,6 +950,14 @@ ibus_m17n_engine_disable (IBusEngine *engine) ibus_m17n_engine_focus_out (engine); parent_class->disable (engine); + +#ifdef HAVE_EEKBOARD + if (eekboard) { + IBusM17NEngineClass *klass = (IBusM17NEngineClass *) G_OBJECT_GET_CLASS (m17n); + if (klass->econtext) + eekboard_client_pop_context (eekboard, NULL); + } +#endif /* HAVE_EEKBOARD */ } static void @@ -764,6 +1005,7 @@ ibus_m17n_engine_property_activate (IBusEngine *engine, guint prop_state) { IBusM17NEngine *m17n = (IBusM17NEngine *) engine; + IBusM17NEngineClass *klass = (IBusM17NEngineClass *) G_OBJECT_GET_CLASS (m17n); #ifdef HAVE_SETUP if (g_strcmp0 (prop_name, "setup") == 0) { @@ -779,6 +1021,53 @@ ibus_m17n_engine_property_activate (IBusEngine *engine, } #endif /* HAVE_SETUP */ + if (g_strcmp0 (prop_name, "virtual-keyboard") == 0) { +#ifdef HAVE_EEKBOARD + if (eekboard) { + if (klass->econtext == NULL) { + klass->econtext = create_context (klass); + eekboard_client_push_context (eekboard, klass->econtext, NULL); + } + g_signal_handlers_disconnect_by_func (klass->econtext, + G_CALLBACK (key_activated_cb), + m17n); + g_signal_connect (klass->econtext, "key-activated", + G_CALLBACK (key_activated_cb), m17n); + eekboard_context_show_keyboard (klass->econtext, NULL); + } else +#endif /* HAVE_EEKBOARD */ + { + gchar *lang = NULL, *name = NULL; + + if (ibus_m17n_scan_class_name (G_OBJECT_CLASS_NAME (klass), + &lang, + &name) && + g_str_has_prefix (name, "inscript")) { + gchar *argv[4]; + GError *error; + + argv[0] = "iok"; + argv[1] = "-n"; + argv[2] = lang; + argv[3] = NULL; + error = NULL; + if (!g_spawn_async (NULL, + argv, + NULL, + G_SPAWN_SEARCH_PATH, + NULL, + NULL, + NULL, + &error)) { + g_warning ("can't spawn iok: %s", error->message); + g_error_free (error); + } + } + g_free (lang); + g_free (name); + } + } + parent_class->property_activate (engine, prop_name, prop_state); } diff --git a/src/m17nutil.c b/src/m17nutil.c index 0b46531..adf7044 100644 --- a/src/m17nutil.c +++ b/src/m17nutil.c @@ -18,7 +18,8 @@ typedef enum { ENGINE_CONFIG_SYMBOL_MASK = 1 << 1, ENGINE_CONFIG_LONGNAME_MASK = 1 << 2, ENGINE_CONFIG_LAYOUT_MASK = 1 << 3, - ENGINE_CONFIG_PREEDIT_HIGHLIGHT_MASK = 1 << 4 + ENGINE_CONFIG_PREEDIT_HIGHLIGHT_MASK = 1 << 4, + ENGINE_CONFIG_VIRTUAL_KEYBOARD_MASK = 1 << 5 } EngineConfigMask; struct _EngineConfigNode { @@ -276,6 +277,8 @@ ibus_m17n_get_engine_config (const gchar *engine_name) config->longname = cnode->config.longname; if (cnode->mask & ENGINE_CONFIG_PREEDIT_HIGHLIGHT_MASK) config->preedit_highlight = cnode->config.preedit_highlight; + if (cnode->mask & ENGINE_CONFIG_VIRTUAL_KEYBOARD_MASK) + config->virtual_keyboard = cnode->config.virtual_keyboard; if (cnode->mask & ENGINE_CONFIG_LAYOUT_MASK) config->layout = cnode->config.layout; } @@ -333,6 +336,11 @@ ibus_m17n_engine_config_parse_xml_node (EngineConfigNode *cnode, cnode->mask |= ENGINE_CONFIG_PREEDIT_HIGHLIGHT_MASK; continue; } + if (g_strcmp0 (sub_node->name , "virtual-keyboard") == 0) { + cnode->config.virtual_keyboard = g_strdup (sub_node->text); + cnode->mask |= ENGINE_CONFIG_VIRTUAL_KEYBOARD_MASK; + continue; + } g_warning (" element contains invalid element <%s>", sub_node->name); } diff --git a/src/m17nutil.h b/src/m17nutil.h index 93faad4..3c2944a 100644 --- a/src/m17nutil.h +++ b/src/m17nutil.h @@ -25,6 +25,9 @@ struct _IBusM17NEngineConfig { /* whether to highlight preedit */ gboolean preedit_highlight; + + /* virtual keyboard type */ + gchar *virtual_keyboard; }; typedef struct _IBusM17NEngineConfig IBusM17NEngineConfig; -- 1.7.7.6