#include <ibus.h>
#include <hangul.h>
#include <string.h>
+
#include "engine.h"
+#include "ustring.h"
typedef struct _IBusHangulEngine IBusHangulEngine;
typedef struct _IBusHangulEngineClass IBusHangulEngineClass;
/* members */
HangulInputContext *context;
+ UString* preedit;
gboolean hangul_mode;
+ gboolean hanja_mode;
HanjaList* hanja_list;
IBusLookupTable *table;
IBusProperty *hangul_mode_prop;
+ IBusProperty *prop_hanja_mode;
IBusPropList *prop_list;
};
IBusText* tooltip;
hangul->context = hangul_ic_new (hangul_keyboard->str);
+ hangul->preedit = ustring_new();
hangul->hanja_list = NULL;
hangul->hangul_mode = TRUE;
- label = ibus_text_new_from_string("Setup");
- tooltip = ibus_text_new_from_string("Configure hangul engine");
+ hangul->hanja_mode = FALSE;
+
+ hangul->prop_list = ibus_prop_list_new ();
+
+ label = ibus_text_new_from_static_string ("韓");
+ tooltip = ibus_text_new_from_static_string ("Enable/Disable Hanja mode");
+ prop = ibus_property_new ("hanja_mode",
+ PROP_TYPE_NORMAL,
+ label,
+ NULL,
+ tooltip,
+ TRUE, TRUE, PROP_STATE_UNCHECKED, NULL);
+ g_object_unref (label);
+ g_object_unref (tooltip);
+ ibus_prop_list_append (hangul->prop_list, prop);
+ hangul->prop_hanja_mode = prop;
+
+ label = ibus_text_new_from_static_string ("Setup");
+ tooltip = ibus_text_new_from_static_string ("Configure hangul engine");
prop = ibus_property_new ("setup",
PROP_TYPE_NORMAL,
label,
"gtk-preferences",
tooltip,
- TRUE, TRUE, 0, NULL);
+ TRUE, TRUE, PROP_STATE_UNCHECKED, NULL);
g_object_unref (label);
g_object_unref (tooltip);
-
- hangul->prop_list = ibus_prop_list_new ();
- ibus_prop_list_append (hangul->prop_list, prop);
+ ibus_prop_list_append (hangul->prop_list, prop);
hangul->table = ibus_lookup_table_new (9, 0, TRUE, FALSE);
static void
ibus_hangul_engine_update_preedit_text (IBusHangulEngine *hangul)
{
- const gunichar *str;
+ const ucschar *hic_preedit;
IBusText *text;
-
- str = hangul_ic_get_preedit_string (hangul->context);
-
- if (str != NULL && str[0] != 0) {
- text = ibus_text_new_from_ucs4 (str);
- ibus_text_append_attribute (text, IBUS_ATTR_TYPE_FOREGROUND, 0x00ffffff, 0, -1);
- ibus_text_append_attribute (text, IBUS_ATTR_TYPE_BACKGROUND, 0x00000000, 0, -1);
+ UString *preedit;
+ gint preedit_len;
+
+ // ibus-hangul's preedit string is made up of ibus context's
+ // internal preedit string and libhangul's preedit string.
+ // libhangul only supports one syllable preedit string.
+ // In order to make longer preedit string, ibus-hangul maintains
+ // internal preedit string.
+ hic_preedit = hangul_ic_get_preedit_string (hangul->context);
+
+ preedit = ustring_dup (hangul->preedit);
+ preedit_len = ustring_length(preedit);
+ ustring_append_ucs4 (preedit, hic_preedit, -1);
+
+ if (ustring_length(preedit) > 0) {
+ text = ibus_text_new_from_ucs4 ((gunichar*)preedit->data);
+ // ibus-hangul's internal preedit string
+ ibus_text_append_attribute (text, IBUS_ATTR_TYPE_UNDERLINE,
+ IBUS_ATTR_UNDERLINE_SINGLE, 0, preedit_len);
+ // Preedit string from libhangul context.
+ // This is currently composing syllable.
+ ibus_text_append_attribute (text, IBUS_ATTR_TYPE_FOREGROUND,
+ 0x00ffffff, preedit_len, -1);
+ ibus_text_append_attribute (text, IBUS_ATTR_TYPE_BACKGROUND,
+ 0x00000000, preedit_len, -1);
ibus_engine_update_preedit_text ((IBusEngine *)hangul,
text,
ibus_text_get_length (text),
TRUE);
g_object_unref (text);
- }
- else {
+ } else {
text = ibus_text_new_from_static_string ("");
ibus_engine_update_preedit_text ((IBusEngine *)hangul, text, 0, FALSE);
g_object_unref (text);
}
+
+ ustring_delete(preedit);
}
static void
ibus_hangul_engine_commit_current_candidate (IBusHangulEngine *hangul)
{
guint cursor_pos;
+ const char* key;
const char* value;
- IBusText* text;
+ int key_len;
+ int preedit_len;
+ int len;
- hangul_ic_reset (hangul->context);
- ibus_hangul_engine_update_preedit_text (hangul);
+ IBusText* text;
cursor_pos = ibus_lookup_table_get_cursor_pos (hangul->table);
+ key = hanja_list_get_nth_key (hangul->hanja_list, cursor_pos);
value = hanja_list_get_nth_value (hangul->hanja_list, cursor_pos);
+ key_len = g_utf8_strlen(key, -1);
+ preedit_len = ustring_length(hangul->preedit);
+
+ len = MIN(key_len, preedit_len);
+ ustring_erase (hangul->preedit, 0, len);
+ if (key_len > preedit_len)
+ hangul_ic_reset (hangul->context);
+
+ ibus_hangul_engine_update_preedit_text (hangul);
+
text = ibus_text_new_from_string (value);
ibus_engine_commit_text ((IBusEngine *)hangul, text);
g_object_unref (text);
ibus_hangul_engine_open_lookup_table (IBusHangulEngine *hangul)
{
char* utf8;
- const gunichar* str;
+ const ucschar* hic_preedit;
+ UString* preedit;
+
+ hic_preedit = hangul_ic_get_preedit_string (hangul->context);
- str = hangul_ic_get_preedit_string (hangul->context);
- utf8 = g_ucs4_to_utf8 (str, -1, NULL, NULL, NULL);
+ preedit = ustring_dup (hangul->preedit);
+ ustring_append_ucs4 (preedit, hic_preedit, -1);
+
+ utf8 = ustring_to_utf8 (preedit, -1);
if (utf8 != NULL) {
- HanjaList* list = hanja_table_match_suffix (hanja_table, utf8);
+ HanjaList* list = hanja_table_match_prefix (hanja_table, utf8);
if (list != NULL) {
int i, n;
n = hanja_list_get_size (list);
}
g_free (utf8);
}
+
+ ustring_delete (preedit);
}
static void
{
if (keyval == IBUS_Escape) {
ibus_hangul_engine_close_lookup_table (hangul);
+ return TRUE;
} else if (keyval == IBUS_Return) {
ibus_hangul_engine_commit_current_candidate (hangul);
ibus_hangul_engine_close_lookup_table (hangul);
+ return TRUE;
} else if (keyval >= IBUS_1 && keyval <= IBUS_9) {
guint page_no;
guint page_size;
ibus_hangul_engine_commit_current_candidate (hangul);
ibus_hangul_engine_close_lookup_table (hangul);
+ return TRUE;
} else if (keyval == IBUS_Left) {
ibus_lookup_table_cursor_up (hangul->table);
ibus_hangul_engine_update_lookup_table (hangul);
ibus_hangul_engine_update_auxiliary_text (hangul);
+ return TRUE;
} else if (keyval == IBUS_Right) {
ibus_lookup_table_cursor_down (hangul->table);
ibus_hangul_engine_update_lookup_table (hangul);
ibus_hangul_engine_update_auxiliary_text (hangul);
+ return TRUE;
} else if (keyval == IBUS_Up) {
ibus_lookup_table_page_up (hangul->table);
ibus_hangul_engine_update_lookup_table (hangul);
ibus_hangul_engine_update_auxiliary_text (hangul);
+ return TRUE;
} else if (keyval == IBUS_Down) {
ibus_lookup_table_page_down (hangul->table);
ibus_hangul_engine_update_lookup_table (hangul);
ibus_hangul_engine_update_auxiliary_text (hangul);
+ return TRUE;
} else if (keyval == IBUS_Page_Up) {
ibus_lookup_table_page_up (hangul->table);
ibus_hangul_engine_update_lookup_table (hangul);
ibus_hangul_engine_update_auxiliary_text (hangul);
+ return TRUE;
} else if (keyval == IBUS_Page_Down) {
ibus_lookup_table_page_down (hangul->table);
ibus_hangul_engine_update_lookup_table (hangul);
ibus_hangul_engine_update_auxiliary_text (hangul);
- } else if (keyval == IBUS_h) {
- ibus_lookup_table_cursor_up (hangul->table);
- ibus_hangul_engine_update_lookup_table (hangul);
- ibus_hangul_engine_update_auxiliary_text (hangul);
- } else if (keyval == IBUS_l) {
- ibus_lookup_table_cursor_down (hangul->table);
- ibus_hangul_engine_update_lookup_table (hangul);
- ibus_hangul_engine_update_auxiliary_text (hangul);
- } else if (keyval == IBUS_k) {
- ibus_lookup_table_page_up (hangul->table);
- ibus_hangul_engine_update_lookup_table (hangul);
- ibus_hangul_engine_update_auxiliary_text (hangul);
- } else if (keyval == IBUS_j) {
- ibus_lookup_table_page_down (hangul->table);
- ibus_hangul_engine_update_lookup_table (hangul);
- ibus_hangul_engine_update_auxiliary_text (hangul);
+ return TRUE;
+ }
+
+ if (!hangul->hanja_mode) {
+ if (keyval == IBUS_h) {
+ ibus_lookup_table_cursor_up (hangul->table);
+ ibus_hangul_engine_update_lookup_table (hangul);
+ ibus_hangul_engine_update_auxiliary_text (hangul);
+ return TRUE;
+ } else if (keyval == IBUS_l) {
+ ibus_lookup_table_cursor_down (hangul->table);
+ ibus_hangul_engine_update_lookup_table (hangul);
+ ibus_hangul_engine_update_auxiliary_text (hangul);
+ return TRUE;
+ } else if (keyval == IBUS_k) {
+ ibus_lookup_table_page_up (hangul->table);
+ ibus_hangul_engine_update_lookup_table (hangul);
+ ibus_hangul_engine_update_auxiliary_text (hangul);
+ return TRUE;
+ } else if (keyval == IBUS_j) {
+ ibus_lookup_table_page_down (hangul->table);
+ ibus_hangul_engine_update_lookup_table (hangul);
+ ibus_hangul_engine_update_auxiliary_text (hangul);
+ return TRUE;
+ }
}
- return TRUE;
+ return FALSE;
}
static gboolean
IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
gboolean retval;
- const gunichar *str;
+ const ucschar *str;
if (modifiers & IBUS_RELEASE_MASK)
return FALSE;
return FALSE;
if (hangul->hanja_list != NULL) {
- return ibus_hangul_engine_process_candidate_key_event (hangul,
- keyval, modifiers);
+ retval = ibus_hangul_engine_process_candidate_key_event (hangul,
+ keyval, modifiers);
+ if (hangul->hanja_mode) {
+ if (retval)
+ return TRUE;
+ } else {
+ return TRUE;
+ }
}
if (keyval == IBUS_BackSpace) {
}
str = hangul_ic_get_commit_string (hangul->context);
- if (str != NULL && str[0] != 0) {
- IBusText *text = ibus_text_new_from_ucs4 (str);
- ibus_engine_commit_text ((IBusEngine *)hangul, text);
- g_object_unref (text);
+ if (hangul->hanja_mode) {
+ const ucschar* hic_preedit;
+
+ hic_preedit = hangul_ic_get_preedit_string (hangul->context);
+ if (hic_preedit != NULL && hic_preedit[0] != 0) {
+ ustring_append_ucs4 (hangul->preedit, str, -1);
+ } else {
+ IBusText *text;
+ const ucschar* preedit;
+
+ ustring_append_ucs4 (hangul->preedit, str, -1);
+
+ preedit = ustring_begin (hangul->preedit);
+ text = ibus_text_new_from_ucs4 ((gunichar*)preedit);
+ ibus_engine_commit_text (engine, text);
+ g_object_unref (text);
+ ustring_clear (hangul->preedit);
+ }
+ } else {
+ if (str != NULL && str[0] != 0) {
+ IBusText *text = ibus_text_new_from_ucs4 (str);
+ ibus_engine_commit_text (engine, text);
+ g_object_unref (text);
+ }
}
ibus_hangul_engine_update_preedit_text (hangul);
+ if (hangul->hanja_mode) {
+ hanja_list_delete (hangul->hanja_list);
+ hangul->hanja_list = NULL;
+
+ ibus_hangul_engine_open_lookup_table (hangul);
+
+ if (hangul->hanja_list == NULL)
+ ibus_hangul_engine_close_lookup_table (hangul);
+ }
+
if (!retval)
ibus_hangul_engine_flush (hangul);
{
IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
+ IBusText* label = NULL;
+ if (hangul->hanja_mode) {
+ label = ibus_text_new_from_static_string("漢");
+ } else {
+ label = ibus_text_new_from_static_string("韓");
+ }
+ ibus_property_set_label (hangul->prop_hanja_mode, label);
+ g_object_unref (label);
+
ibus_engine_register_properties (engine, hangul->prop_list);
if (hangul->hanja_list != NULL) {
g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error);
g_free(path);
+ } else if (strcmp(prop_name, "hanja_mode") == 0) {
+ IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
+ IBusText *label;
+
+ hangul->hanja_mode = !hangul->hanja_mode;
+
+ if (hangul->hanja_mode) {
+ label = ibus_text_new_from_static_string("漢");
+ hangul->prop_hanja_mode->state = PROP_STATE_CHECKED;
+ } else {
+ label = ibus_text_new_from_static_string("韓");
+ hangul->prop_hanja_mode->state = PROP_STATE_UNCHECKED;
+ }
+
+ ibus_property_set_label (hangul->prop_hanja_mode, label);
+ ibus_engine_update_property (engine, hangul->prop_hanja_mode);
+ g_object_unref(label);
}
}
--- /dev/null
+/* ibus-hangul - korean input method engine for IBus
+ * This file is from Korean XIM Nabi.
+ */
+
+/* Nabi - X Input Method server for hangul
+ * Copyright (C) 2008 Choe Hwanjin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include "ustring.h"
+
+UString*
+ustring_new()
+{
+ return g_array_new(TRUE, TRUE, sizeof(ucschar));
+}
+
+UString*
+ustring_dup(const UString* str)
+{
+ UString* dup;
+ dup = ustring_new();
+ ustring_append(dup, str);
+ return dup;
+}
+
+void
+ustring_delete(UString* str)
+{
+ g_array_free(str, TRUE);
+}
+
+void
+ustring_clear(UString* str)
+{
+ if (str->len > 0)
+ g_array_remove_range(str, 0, str->len);
+}
+
+UString*
+ustring_erase(UString* str, guint pos, guint len)
+{
+ return g_array_remove_range(str, pos, len);
+}
+
+ucschar*
+ustring_begin(UString* str)
+{
+ return (ucschar*)str->data;
+}
+
+ucschar*
+ustring_end(UString* str)
+{
+ return &g_array_index(str, ucschar, str->len);
+}
+
+guint
+ustring_length(const UString* str)
+{
+ return str->len;
+}
+
+UString*
+ustring_append(UString* str, const UString* s)
+{
+ return g_array_append_vals(str, s->data, s->len);
+}
+
+UString*
+ustring_append_ucs4(UString* str, const ucschar* s, gint len)
+{
+ if (len < 0) {
+ const ucschar*p = s;
+ while (*p != 0)
+ p++;
+ len = p - s;
+ }
+
+ return g_array_append_vals(str, s, len);
+}
+
+UString*
+ustring_append_utf8(UString* str, const char* utf8)
+{
+ while (*utf8 != '\0') {
+ ucschar c = g_utf8_get_char(utf8);
+ g_array_append_vals(str, &c, 1);
+ utf8 = g_utf8_next_char(utf8);
+ }
+ return str;
+}
+
+gchar*
+ustring_to_utf8(const UString* str, guint len)
+{
+ if (len < 0)
+ len = str->len;
+ return g_ucs4_to_utf8((const gunichar*)str->data, len, NULL, NULL, NULL);
+}