1 /* vim:set et sts=4: */
10 typedef struct _IBusHangulEngine IBusHangulEngine;
11 typedef struct _IBusHangulEngineClass IBusHangulEngineClass;
13 struct _IBusHangulEngine {
17 HangulInputContext *context;
21 HanjaList* hanja_list;
23 IBusLookupTable *table;
25 IBusProperty *hangul_mode_prop;
26 IBusProperty *prop_hanja_mode;
27 IBusPropList *prop_list;
30 struct _IBusHangulEngineClass {
31 IBusEngineClass parent;
34 /* functions prototype */
35 static void ibus_hangul_engine_class_init (IBusHangulEngineClass *klass);
36 static void ibus_hangul_engine_init (IBusHangulEngine *hangul);
38 ibus_hangul_engine_constructor (GType type,
39 guint n_construct_params,
40 GObjectConstructParam *construct_params);
41 static void ibus_hangul_engine_destroy (IBusHangulEngine *hangul);
43 ibus_hangul_engine_process_key_event
48 static void ibus_hangul_engine_focus_in (IBusEngine *engine);
49 static void ibus_hangul_engine_focus_out (IBusEngine *engine);
50 static void ibus_hangul_engine_reset (IBusEngine *engine);
51 static void ibus_hangul_engine_enable (IBusEngine *engine);
52 static void ibus_hangul_engine_disable (IBusEngine *engine);
54 static void ibus_engine_set_cursor_location (IBusEngine *engine,
59 static void ibus_hangul_engine_set_capabilities
63 static void ibus_hangul_engine_page_up (IBusEngine *engine);
64 static void ibus_hangul_engine_page_down (IBusEngine *engine);
65 static void ibus_hangul_engine_cursor_up (IBusEngine *engine);
66 static void ibus_hangul_engine_cursor_down (IBusEngine *engine);
67 static void ibus_hangul_engine_property_activate
69 const gchar *prop_name,
72 static void ibus_hangul_engine_property_show
74 const gchar *prop_name);
75 static void ibus_hangul_engine_property_hide
77 const gchar *prop_name);
80 static void ibus_hangul_engine_flush (IBusHangulEngine *hangul);
81 static void ibus_hangul_engine_update_preedit_text
82 (IBusHangulEngine *hangul);
84 static void ibus_hangul_engine_update_lookup_table
85 (IBusHangulEngine *hangul);
86 static void ibus_config_value_changed (IBusConfig *config,
92 static void lookup_table_set_visible (IBusLookupTable *table,
94 static gboolean lookup_table_is_visible (IBusLookupTable *table);
96 static IBusEngineClass *parent_class = NULL;
97 static HanjaTable *hanja_table = NULL;
98 static IBusConfig *config = NULL;
99 static GString *hangul_keyboard;
102 ibus_hangul_engine_get_type (void)
104 static GType type = 0;
106 static const GTypeInfo type_info = {
107 sizeof (IBusHangulEngineClass),
108 (GBaseInitFunc) NULL,
109 (GBaseFinalizeFunc) NULL,
110 (GClassInitFunc) ibus_hangul_engine_class_init,
113 sizeof (IBusHangulEngine),
115 (GInstanceInitFunc) ibus_hangul_engine_init,
119 type = g_type_register_static (IBUS_TYPE_ENGINE,
129 ibus_hangul_init (IBusBus *bus)
132 GValue value = { 0, };
134 hanja_table = hanja_table_load (NULL);
136 config = ibus_bus_get_config (bus);
138 hangul_keyboard = g_string_new_len ("2", 8);
139 res = ibus_config_get_value (config, "engine/Hangul",
140 "HangulKeyboard", &value);
142 const gchar* str = g_value_get_string (&value);
143 g_string_assign (hangul_keyboard, str);
148 ibus_hangul_exit (void)
150 hanja_table_delete (hanja_table);
153 g_object_unref (config);
156 g_string_free (hangul_keyboard, TRUE);
157 hangul_keyboard = NULL;
161 ibus_hangul_engine_class_init (IBusHangulEngineClass *klass)
163 GObjectClass *object_class = G_OBJECT_CLASS (klass);
164 IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
165 IBusEngineClass *engine_class = IBUS_ENGINE_CLASS (klass);
167 parent_class = (IBusEngineClass *) g_type_class_peek_parent (klass);
169 object_class->constructor = ibus_hangul_engine_constructor;
170 ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_hangul_engine_destroy;
172 engine_class->process_key_event = ibus_hangul_engine_process_key_event;
174 engine_class->reset = ibus_hangul_engine_reset;
175 engine_class->enable = ibus_hangul_engine_enable;
176 engine_class->disable = ibus_hangul_engine_disable;
178 engine_class->focus_in = ibus_hangul_engine_focus_in;
179 engine_class->focus_out = ibus_hangul_engine_focus_out;
181 engine_class->page_up = ibus_hangul_engine_page_up;
182 engine_class->page_down = ibus_hangul_engine_page_down;
184 engine_class->cursor_up = ibus_hangul_engine_cursor_up;
185 engine_class->cursor_down = ibus_hangul_engine_cursor_down;
187 engine_class->property_activate = ibus_hangul_engine_property_activate;
191 ibus_hangul_engine_init (IBusHangulEngine *hangul)
197 hangul->context = hangul_ic_new (hangul_keyboard->str);
198 hangul->preedit = ustring_new();
199 hangul->hanja_list = NULL;
200 hangul->hangul_mode = TRUE;
201 hangul->hanja_mode = FALSE;
203 hangul->prop_list = ibus_prop_list_new ();
205 label = ibus_text_new_from_static_string ("韓");
206 tooltip = ibus_text_new_from_static_string ("Enable/Disable Hanja mode");
207 prop = ibus_property_new ("hanja_mode",
212 TRUE, TRUE, PROP_STATE_UNCHECKED, NULL);
213 g_object_unref (label);
214 g_object_unref (tooltip);
215 ibus_prop_list_append (hangul->prop_list, prop);
216 hangul->prop_hanja_mode = prop;
218 label = ibus_text_new_from_static_string ("Setup");
219 tooltip = ibus_text_new_from_static_string ("Configure hangul engine");
220 prop = ibus_property_new ("setup",
225 TRUE, TRUE, PROP_STATE_UNCHECKED, NULL);
226 g_object_unref (label);
227 g_object_unref (tooltip);
228 ibus_prop_list_append (hangul->prop_list, prop);
230 hangul->table = ibus_lookup_table_new (9, 0, TRUE, FALSE);
232 g_signal_connect (config, "value-changed",
233 G_CALLBACK(ibus_config_value_changed), hangul);
237 ibus_hangul_engine_constructor (GType type,
238 guint n_construct_params,
239 GObjectConstructParam *construct_params)
241 IBusHangulEngine *hangul;
243 hangul = (IBusHangulEngine *) G_OBJECT_CLASS (parent_class)->constructor (type,
247 return (GObject *)hangul;
252 ibus_hangul_engine_destroy (IBusHangulEngine *hangul)
254 if (hangul->prop_list) {
255 g_object_unref (hangul->prop_list);
256 hangul->prop_list = NULL;
259 if (hangul->hangul_mode_prop) {
260 g_object_unref (hangul->hangul_mode_prop);
261 hangul->hangul_mode_prop = NULL;
265 g_object_unref (hangul->table);
266 hangul->table = NULL;
269 if (hangul->context) {
270 hangul_ic_delete (hangul->context);
271 hangul->context = NULL;
274 IBUS_OBJECT_CLASS (parent_class)->destroy ((IBusObject *)hangul);
278 ibus_hangul_engine_update_preedit_text (IBusHangulEngine *hangul)
280 const ucschar *hic_preedit;
285 // ibus-hangul's preedit string is made up of ibus context's
286 // internal preedit string and libhangul's preedit string.
287 // libhangul only supports one syllable preedit string.
288 // In order to make longer preedit string, ibus-hangul maintains
289 // internal preedit string.
290 hic_preedit = hangul_ic_get_preedit_string (hangul->context);
292 preedit = ustring_dup (hangul->preedit);
293 preedit_len = ustring_length(preedit);
294 ustring_append_ucs4 (preedit, hic_preedit, -1);
296 if (ustring_length(preedit) > 0) {
297 text = ibus_text_new_from_ucs4 ((gunichar*)preedit->data);
298 // ibus-hangul's internal preedit string
299 ibus_text_append_attribute (text, IBUS_ATTR_TYPE_UNDERLINE,
300 IBUS_ATTR_UNDERLINE_SINGLE, 0, preedit_len);
301 // Preedit string from libhangul context.
302 // This is currently composing syllable.
303 ibus_text_append_attribute (text, IBUS_ATTR_TYPE_FOREGROUND,
304 0x00ffffff, preedit_len, -1);
305 ibus_text_append_attribute (text, IBUS_ATTR_TYPE_BACKGROUND,
306 0x00000000, preedit_len, -1);
307 ibus_engine_update_preedit_text ((IBusEngine *)hangul,
309 ibus_text_get_length (text),
311 g_object_unref (text);
313 text = ibus_text_new_from_static_string ("");
314 ibus_engine_update_preedit_text ((IBusEngine *)hangul, text, 0, FALSE);
315 g_object_unref (text);
318 ustring_delete(preedit);
322 ibus_hangul_engine_update_lookup_table_ui (IBusHangulEngine *hangul)
329 cursor_pos = ibus_lookup_table_get_cursor_pos (hangul->table);
330 comment = hanja_list_get_nth_comment (hangul->hanja_list, cursor_pos);
332 text = ibus_text_new_from_string (comment);
333 ibus_engine_update_auxiliary_text ((IBusEngine *)hangul, text, TRUE);
334 g_object_unref (text);
336 // update lookup table
337 ibus_engine_update_lookup_table ((IBusEngine *)hangul, hangul->table, TRUE);
341 ibus_hangul_engine_commit_current_candidate (IBusHangulEngine *hangul)
352 cursor_pos = ibus_lookup_table_get_cursor_pos (hangul->table);
353 key = hanja_list_get_nth_key (hangul->hanja_list, cursor_pos);
354 value = hanja_list_get_nth_value (hangul->hanja_list, cursor_pos);
356 key_len = g_utf8_strlen(key, -1);
357 preedit_len = ustring_length(hangul->preedit);
359 len = MIN(key_len, preedit_len);
360 ustring_erase (hangul->preedit, 0, len);
361 if (key_len > preedit_len)
362 hangul_ic_reset (hangul->context);
364 ibus_hangul_engine_update_preedit_text (hangul);
366 text = ibus_text_new_from_string (value);
367 ibus_engine_commit_text ((IBusEngine *)hangul, text);
368 g_object_unref (text);
372 ibus_hangul_engine_update_hanja_list (IBusHangulEngine *hangul)
375 const ucschar* hic_preedit;
378 if (hangul->hanja_list != NULL) {
379 hanja_list_delete (hangul->hanja_list);
380 hangul->hanja_list = NULL;
383 hic_preedit = hangul_ic_get_preedit_string (hangul->context);
385 preedit = ustring_dup (hangul->preedit);
386 ustring_append_ucs4 (preedit, hic_preedit, -1);
387 if (ustring_length(preedit) > 0) {
388 utf8 = ustring_to_utf8 (preedit, -1);
390 hangul->hanja_list = hanja_table_match_prefix (hanja_table, utf8);
395 ustring_delete (preedit);
400 ibus_hangul_engine_apply_hanja_list (IBusHangulEngine *hangul)
402 HanjaList* list = hangul->hanja_list;
405 n = hanja_list_get_size (list);
407 ibus_lookup_table_clear (hangul->table);
408 for (i = 0; i < n; i++) {
409 const char* value = hanja_list_get_nth_value (list, i);
410 IBusText* text = ibus_text_new_from_string (value);
411 ibus_lookup_table_append_candidate (hangul->table, text);
412 g_object_unref (text);
415 ibus_lookup_table_set_cursor_pos (hangul->table, 0);
416 ibus_hangul_engine_update_lookup_table_ui (hangul);
417 lookup_table_set_visible (hangul->table, TRUE);
422 ibus_hangul_engine_hide_lookup_table (IBusHangulEngine *hangul)
425 is_visible = lookup_table_is_visible (hangul->table);
427 // Sending hide lookup table message when the lookup table
428 // is not visible results wrong behavior. So I have to check
429 // whether the table is visible or not before to hide.
431 ibus_engine_hide_lookup_table ((IBusEngine *)hangul);
432 ibus_engine_hide_auxiliary_text ((IBusEngine *)hangul);
433 lookup_table_set_visible (hangul->table, FALSE);
436 if (hangul->hanja_list != NULL) {
437 hanja_list_delete (hangul->hanja_list);
438 hangul->hanja_list = NULL;
443 ibus_hangul_engine_update_lookup_table (IBusHangulEngine *hangul)
445 ibus_hangul_engine_update_hanja_list (hangul);
447 if (hangul->hanja_list != NULL) {
448 ibus_hangul_engine_apply_hanja_list (hangul);
450 ibus_hangul_engine_hide_lookup_table (hangul);
455 ibus_hangul_engine_process_candidate_key_event (IBusHangulEngine *hangul,
459 if (keyval == IBUS_Escape) {
460 ibus_hangul_engine_hide_lookup_table (hangul);
462 } else if (keyval == IBUS_Return) {
463 ibus_hangul_engine_commit_current_candidate (hangul);
465 if (hangul->hanja_mode) {
466 ibus_hangul_engine_update_lookup_table (hangul);
468 ibus_hangul_engine_hide_lookup_table (hangul);
471 } else if (keyval >= IBUS_1 && keyval <= IBUS_9) {
476 page_size = ibus_lookup_table_get_page_size (hangul->table);
477 cursor_pos = ibus_lookup_table_get_cursor_pos (hangul->table);
478 page_no = cursor_pos / page_size;
480 cursor_pos = page_no * page_size + (keyval - IBUS_1);
481 ibus_lookup_table_set_cursor_pos (hangul->table, cursor_pos);
483 ibus_hangul_engine_commit_current_candidate (hangul);
485 if (hangul->hanja_mode) {
486 ibus_hangul_engine_update_lookup_table (hangul);
488 ibus_hangul_engine_hide_lookup_table (hangul);
491 } else if (keyval == IBUS_Left) {
492 ibus_lookup_table_cursor_up (hangul->table);
493 ibus_hangul_engine_update_lookup_table_ui (hangul);
495 } else if (keyval == IBUS_Right) {
496 ibus_lookup_table_cursor_down (hangul->table);
497 ibus_hangul_engine_update_lookup_table_ui (hangul);
499 } else if (keyval == IBUS_Up) {
500 ibus_lookup_table_page_up (hangul->table);
501 ibus_hangul_engine_update_lookup_table_ui (hangul);
503 } else if (keyval == IBUS_Down) {
504 ibus_lookup_table_page_down (hangul->table);
505 ibus_hangul_engine_update_lookup_table_ui (hangul);
507 } else if (keyval == IBUS_Page_Up) {
508 ibus_lookup_table_page_up (hangul->table);
509 ibus_hangul_engine_update_lookup_table_ui (hangul);
511 } else if (keyval == IBUS_Page_Down) {
512 ibus_lookup_table_page_down (hangul->table);
513 ibus_hangul_engine_update_lookup_table_ui (hangul);
517 if (!hangul->hanja_mode) {
518 if (keyval == IBUS_h) {
519 ibus_lookup_table_cursor_up (hangul->table);
520 ibus_hangul_engine_update_lookup_table_ui (hangul);
522 } else if (keyval == IBUS_l) {
523 ibus_lookup_table_cursor_down (hangul->table);
524 ibus_hangul_engine_update_lookup_table_ui (hangul);
526 } else if (keyval == IBUS_k) {
527 ibus_lookup_table_page_up (hangul->table);
528 ibus_hangul_engine_update_lookup_table_ui (hangul);
530 } else if (keyval == IBUS_j) {
531 ibus_lookup_table_page_down (hangul->table);
532 ibus_hangul_engine_update_lookup_table_ui (hangul);
541 ibus_hangul_engine_process_key_event (IBusEngine *engine,
546 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
551 if (modifiers & IBUS_RELEASE_MASK)
554 // if we don't ignore shift keys, shift key will make flush the preedit
555 // string. So you cannot input shift+key.
556 // Let's think about these examples:
559 if (keyval == IBUS_Shift_L || keyval == IBUS_Shift_R)
562 if (keyval == IBUS_F9 || keyval == IBUS_Hangul_Hanja) {
563 if (hangul->hanja_list == NULL) {
564 ibus_hangul_engine_update_lookup_table (hangul);
566 ibus_hangul_engine_hide_lookup_table (hangul);
571 if (modifiers & (IBUS_CONTROL_MASK | IBUS_MOD1_MASK))
574 if (hangul->hanja_list != NULL) {
575 retval = ibus_hangul_engine_process_candidate_key_event (hangul,
577 if (hangul->hanja_mode) {
585 if (keyval == IBUS_BackSpace) {
586 retval = hangul_ic_backspace (hangul->context);
588 retval = hangul_ic_process (hangul->context, keyval);
591 str = hangul_ic_get_commit_string (hangul->context);
592 if (hangul->hanja_mode) {
593 const ucschar* hic_preedit;
595 hic_preedit = hangul_ic_get_preedit_string (hangul->context);
596 if (hic_preedit != NULL && hic_preedit[0] != 0) {
597 ustring_append_ucs4 (hangul->preedit, str, -1);
600 const ucschar* preedit;
602 ustring_append_ucs4 (hangul->preedit, str, -1);
603 if (ustring_length (hangul->preedit) > 0) {
604 preedit = ustring_begin (hangul->preedit);
605 text = ibus_text_new_from_ucs4 ((gunichar*)preedit);
606 ibus_engine_commit_text (engine, text);
607 g_object_unref (text);
609 ustring_clear (hangul->preedit);
612 if (str != NULL && str[0] != 0) {
613 IBusText *text = ibus_text_new_from_ucs4 (str);
614 ibus_engine_commit_text (engine, text);
615 g_object_unref (text);
619 ibus_hangul_engine_update_preedit_text (hangul);
621 if (hangul->hanja_mode) {
622 ibus_hangul_engine_update_lookup_table (hangul);
626 ibus_hangul_engine_flush (hangul);
632 ibus_hangul_engine_flush (IBusHangulEngine *hangul)
637 str = hangul_ic_flush (hangul->context);
639 if (str == NULL || str[0] == 0)
642 text = ibus_text_new_from_ucs4 (str);
644 ibus_engine_hide_preedit_text ((IBusEngine *) hangul);
645 ibus_engine_commit_text ((IBusEngine *) hangul, text);
647 g_object_unref (text);
651 ibus_hangul_engine_focus_in (IBusEngine *engine)
653 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
655 IBusText* label = NULL;
656 if (hangul->hanja_mode) {
657 label = ibus_text_new_from_static_string("漢");
659 label = ibus_text_new_from_static_string("韓");
661 ibus_property_set_label (hangul->prop_hanja_mode, label);
662 g_object_unref (label);
664 ibus_engine_register_properties (engine, hangul->prop_list);
666 if (hangul->hanja_list != NULL) {
667 ibus_hangul_engine_update_lookup_table_ui (hangul);
670 parent_class->focus_in (engine);
674 ibus_hangul_engine_focus_out (IBusEngine *engine)
676 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
678 if (hangul->hanja_list == NULL) {
679 ibus_hangul_engine_flush (hangul);
681 ibus_engine_hide_lookup_table (engine);
682 ibus_engine_hide_auxiliary_text (engine);
685 parent_class->focus_out ((IBusEngine *) hangul);
689 ibus_hangul_engine_reset (IBusEngine *engine)
691 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
693 ibus_hangul_engine_flush (hangul);
694 if (hangul->hanja_list != NULL) {
695 ibus_hangul_engine_hide_lookup_table (hangul);
697 parent_class->reset (engine);
701 ibus_hangul_engine_enable (IBusEngine *engine)
703 parent_class->enable (engine);
707 ibus_hangul_engine_disable (IBusEngine *engine)
709 ibus_hangul_engine_focus_out (engine);
710 parent_class->disable (engine);
714 ibus_hangul_engine_page_up (IBusEngine *engine)
716 parent_class->page_up (engine);
720 ibus_hangul_engine_page_down (IBusEngine *engine)
722 parent_class->page_down (engine);
726 ibus_hangul_engine_cursor_up (IBusEngine *engine)
728 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
730 if (hangul->hanja_list != NULL) {
731 ibus_lookup_table_cursor_up (hangul->table);
732 ibus_hangul_engine_update_lookup_table_ui (hangul);
735 parent_class->cursor_up (engine);
739 ibus_hangul_engine_cursor_down (IBusEngine *engine)
741 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
743 if (hangul->hanja_list != NULL) {
744 ibus_lookup_table_cursor_down (hangul->table);
745 ibus_hangul_engine_update_lookup_table_ui (hangul);
748 parent_class->cursor_down (engine);
752 ibus_hangul_engine_property_activate (IBusEngine *engine,
753 const gchar *prop_name,
756 if (strcmp(prop_name, "setup") == 0) {
757 GError *error = NULL;
758 gchar *argv[2] = { NULL, };
760 const char* libexecdir;
762 libexecdir = g_getenv("LIBEXECDIR");
763 if (libexecdir == NULL)
764 libexecdir = LIBEXECDIR;
766 path = g_build_filename(libexecdir, "ibus-setup-hangul", NULL);
769 g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error);
772 } else if (strcmp(prop_name, "hanja_mode") == 0) {
773 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
776 hangul->hanja_mode = !hangul->hanja_mode;
778 if (hangul->hanja_mode) {
779 label = ibus_text_new_from_static_string("漢");
780 hangul->prop_hanja_mode->state = PROP_STATE_CHECKED;
782 label = ibus_text_new_from_static_string("韓");
783 hangul->prop_hanja_mode->state = PROP_STATE_UNCHECKED;
786 ibus_property_set_label (hangul->prop_hanja_mode, label);
787 ibus_engine_update_property (engine, hangul->prop_hanja_mode);
788 g_object_unref(label);
793 ibus_config_value_changed (IBusConfig *config,
794 const gchar *section,
799 IBusHangulEngine *hangul = (IBusHangulEngine *) user_data;
801 if (strcmp(section, "engine/Hangul") == 0) {
802 if (strcmp(name, "HangulKeyboard") == 0) {
803 const gchar *str = g_value_get_string (value);
804 g_string_assign (hangul_keyboard, str);
805 hangul_ic_select_keyboard (hangul->context, hangul_keyboard->str);
811 lookup_table_set_visible (IBusLookupTable *table, gboolean flag)
813 g_object_set_data (G_OBJECT(table), "visible", GUINT_TO_POINTER(flag));
817 lookup_table_is_visible (IBusLookupTable *table)
819 gpointer res = g_object_get_data (G_OBJECT(table), "visible");
820 return GPOINTER_TO_UINT(res);