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;
24 IBusProperty *hangul_mode_prop;
25 IBusProperty *prop_hanja_mode;
26 IBusPropList *prop_list;
29 struct _IBusHangulEngineClass {
30 IBusEngineClass parent;
33 /* functions prototype */
34 static void ibus_hangul_engine_class_init (IBusHangulEngineClass *klass);
35 static void ibus_hangul_engine_init (IBusHangulEngine *hangul);
37 ibus_hangul_engine_constructor (GType type,
38 guint n_construct_params,
39 GObjectConstructParam *construct_params);
40 static void ibus_hangul_engine_destroy (IBusHangulEngine *hangul);
42 ibus_hangul_engine_process_key_event
47 static void ibus_hangul_engine_focus_in (IBusEngine *engine);
48 static void ibus_hangul_engine_focus_out (IBusEngine *engine);
49 static void ibus_hangul_engine_reset (IBusEngine *engine);
50 static void ibus_hangul_engine_enable (IBusEngine *engine);
51 static void ibus_hangul_engine_disable (IBusEngine *engine);
53 static void ibus_engine_set_cursor_location (IBusEngine *engine,
58 static void ibus_hangul_engine_set_capabilities
62 static void ibus_hangul_engine_page_up (IBusEngine *engine);
63 static void ibus_hangul_engine_page_down (IBusEngine *engine);
64 static void ibus_hangul_engine_cursor_up (IBusEngine *engine);
65 static void ibus_hangul_engine_cursor_down (IBusEngine *engine);
66 static void ibus_hangul_engine_property_activate
68 const gchar *prop_name,
71 static void ibus_hangul_engine_property_show
73 const gchar *prop_name);
74 static void ibus_hangul_engine_property_hide
76 const gchar *prop_name);
79 static void ibus_hangul_engine_flush (IBusHangulEngine *hangul);
80 static void ibus_hangul_engine_update_preedit_text
81 (IBusHangulEngine *hangul);
82 static void ibus_config_value_changed (IBusConfig *config,
88 static IBusEngineClass *parent_class = NULL;
89 static HanjaTable *hanja_table = NULL;
90 static IBusConfig *config = NULL;
91 static GString *hangul_keyboard;
94 ibus_hangul_engine_get_type (void)
96 static GType type = 0;
98 static const GTypeInfo type_info = {
99 sizeof (IBusHangulEngineClass),
100 (GBaseInitFunc) NULL,
101 (GBaseFinalizeFunc) NULL,
102 (GClassInitFunc) ibus_hangul_engine_class_init,
105 sizeof (IBusHangulEngine),
107 (GInstanceInitFunc) ibus_hangul_engine_init,
111 type = g_type_register_static (IBUS_TYPE_ENGINE,
121 ibus_hangul_init (IBusBus *bus)
124 GValue value = { 0, };
126 hanja_table = hanja_table_load (NULL);
128 config = ibus_bus_get_config (bus);
130 hangul_keyboard = g_string_new_len ("2", 8);
131 res = ibus_config_get_value (config, "engine/Hangul",
132 "HangulKeyboard", &value);
134 const gchar* str = g_value_get_string (&value);
135 g_string_assign (hangul_keyboard, str);
140 ibus_hangul_exit (void)
142 hanja_table_delete (hanja_table);
145 g_object_unref (config);
148 g_string_free (hangul_keyboard, TRUE);
149 hangul_keyboard = NULL;
153 ibus_hangul_engine_class_init (IBusHangulEngineClass *klass)
155 GObjectClass *object_class = G_OBJECT_CLASS (klass);
156 IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
157 IBusEngineClass *engine_class = IBUS_ENGINE_CLASS (klass);
159 parent_class = (IBusEngineClass *) g_type_class_peek_parent (klass);
161 object_class->constructor = ibus_hangul_engine_constructor;
162 ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_hangul_engine_destroy;
164 engine_class->process_key_event = ibus_hangul_engine_process_key_event;
166 engine_class->reset = ibus_hangul_engine_reset;
167 engine_class->enable = ibus_hangul_engine_enable;
168 engine_class->disable = ibus_hangul_engine_disable;
170 engine_class->focus_in = ibus_hangul_engine_focus_in;
171 engine_class->focus_out = ibus_hangul_engine_focus_out;
173 engine_class->page_up = ibus_hangul_engine_page_up;
174 engine_class->page_down = ibus_hangul_engine_page_down;
176 engine_class->cursor_up = ibus_hangul_engine_cursor_up;
177 engine_class->cursor_down = ibus_hangul_engine_cursor_down;
179 engine_class->property_activate = ibus_hangul_engine_property_activate;
183 ibus_hangul_engine_init (IBusHangulEngine *hangul)
189 hangul->context = hangul_ic_new (hangul_keyboard->str);
190 hangul->preedit = ustring_new();
191 hangul->hanja_list = NULL;
192 hangul->hangul_mode = TRUE;
193 hangul->hanja_mode = FALSE;
195 hangul->prop_list = ibus_prop_list_new ();
197 label = ibus_text_new_from_static_string ("韓");
198 tooltip = ibus_text_new_from_static_string ("Enable/Disable Hanja mode");
199 prop = ibus_property_new ("hanja_mode",
204 TRUE, TRUE, PROP_STATE_UNCHECKED, NULL);
205 g_object_unref (label);
206 g_object_unref (tooltip);
207 ibus_prop_list_append (hangul->prop_list, prop);
208 hangul->prop_hanja_mode = prop;
210 label = ibus_text_new_from_static_string ("Setup");
211 tooltip = ibus_text_new_from_static_string ("Configure hangul engine");
212 prop = ibus_property_new ("setup",
217 TRUE, TRUE, PROP_STATE_UNCHECKED, NULL);
218 g_object_unref (label);
219 g_object_unref (tooltip);
220 ibus_prop_list_append (hangul->prop_list, prop);
222 hangul->table = ibus_lookup_table_new (9, 0, TRUE, FALSE);
224 g_signal_connect (config, "value-changed",
225 G_CALLBACK(ibus_config_value_changed), hangul);
229 ibus_hangul_engine_constructor (GType type,
230 guint n_construct_params,
231 GObjectConstructParam *construct_params)
233 IBusHangulEngine *hangul;
235 hangul = (IBusHangulEngine *) G_OBJECT_CLASS (parent_class)->constructor (type,
239 return (GObject *)hangul;
244 ibus_hangul_engine_destroy (IBusHangulEngine *hangul)
246 if (hangul->prop_list) {
247 g_object_unref (hangul->prop_list);
248 hangul->prop_list = NULL;
251 if (hangul->hangul_mode_prop) {
252 g_object_unref (hangul->hangul_mode_prop);
253 hangul->hangul_mode_prop = NULL;
257 g_object_unref (hangul->table);
258 hangul->table = NULL;
261 if (hangul->context) {
262 hangul_ic_delete (hangul->context);
263 hangul->context = NULL;
266 IBUS_OBJECT_CLASS (parent_class)->destroy ((IBusObject *)hangul);
270 ibus_hangul_engine_update_preedit_text (IBusHangulEngine *hangul)
272 const ucschar *hic_preedit;
277 // ibus-hangul's preedit string is made up of ibus context's
278 // internal preedit string and libhangul's preedit string.
279 // libhangul only supports one syllable preedit string.
280 // In order to make longer preedit string, ibus-hangul maintains
281 // internal preedit string.
282 hic_preedit = hangul_ic_get_preedit_string (hangul->context);
284 preedit = ustring_dup (hangul->preedit);
285 preedit_len = ustring_length(preedit);
286 ustring_append_ucs4 (preedit, hic_preedit, -1);
288 if (ustring_length(preedit) > 0) {
289 text = ibus_text_new_from_ucs4 ((gunichar*)preedit->data);
290 // ibus-hangul's internal preedit string
291 ibus_text_append_attribute (text, IBUS_ATTR_TYPE_UNDERLINE,
292 IBUS_ATTR_UNDERLINE_SINGLE, 0, preedit_len);
293 // Preedit string from libhangul context.
294 // This is currently composing syllable.
295 ibus_text_append_attribute (text, IBUS_ATTR_TYPE_FOREGROUND,
296 0x00ffffff, preedit_len, -1);
297 ibus_text_append_attribute (text, IBUS_ATTR_TYPE_BACKGROUND,
298 0x00000000, preedit_len, -1);
299 ibus_engine_update_preedit_text ((IBusEngine *)hangul,
301 ibus_text_get_length (text),
303 g_object_unref (text);
305 text = ibus_text_new_from_static_string ("");
306 ibus_engine_update_preedit_text ((IBusEngine *)hangul, text, 0, FALSE);
307 g_object_unref (text);
310 ustring_delete(preedit);
314 ibus_hangul_engine_update_auxiliary_text (IBusHangulEngine *hangul)
320 cursor_pos = ibus_lookup_table_get_cursor_pos (hangul->table);
321 comment = hanja_list_get_nth_comment (hangul->hanja_list, cursor_pos);
323 text = ibus_text_new_from_string (comment);
324 ibus_engine_update_auxiliary_text ((IBusEngine *)hangul, text, TRUE);
325 g_object_unref (text);
329 ibus_hangul_engine_update_lookup_table (IBusHangulEngine *hangul)
331 ibus_engine_update_lookup_table ((IBusEngine *)hangul, hangul->table, TRUE);
335 ibus_hangul_engine_commit_current_candidate (IBusHangulEngine *hangul)
346 cursor_pos = ibus_lookup_table_get_cursor_pos (hangul->table);
347 key = hanja_list_get_nth_key (hangul->hanja_list, cursor_pos);
348 value = hanja_list_get_nth_value (hangul->hanja_list, cursor_pos);
350 key_len = g_utf8_strlen(key, -1);
351 preedit_len = ustring_length(hangul->preedit);
353 len = MIN(key_len, preedit_len);
354 ustring_erase (hangul->preedit, 0, len);
355 if (key_len > preedit_len)
356 hangul_ic_reset (hangul->context);
358 ibus_hangul_engine_update_preedit_text (hangul);
360 text = ibus_text_new_from_string (value);
361 ibus_engine_commit_text ((IBusEngine *)hangul, text);
362 g_object_unref (text);
366 ibus_hangul_engine_open_lookup_table (IBusHangulEngine *hangul)
369 const ucschar* hic_preedit;
372 hic_preedit = hangul_ic_get_preedit_string (hangul->context);
374 preedit = ustring_dup (hangul->preedit);
375 ustring_append_ucs4 (preedit, hic_preedit, -1);
377 utf8 = ustring_to_utf8 (preedit, -1);
379 HanjaList* list = hanja_table_match_prefix (hanja_table, utf8);
382 n = hanja_list_get_size (list);
384 ibus_lookup_table_clear (hangul->table);
385 for (i = 0; i < n; i++) {
386 const char* value = hanja_list_get_nth_value (list, i);
387 IBusText* text = ibus_text_new_from_string (value);
388 ibus_lookup_table_append_candidate (hangul->table, text);
389 g_object_unref (text);
392 hanja_list_delete (hangul->hanja_list);
393 hangul->hanja_list = list;
395 ibus_lookup_table_set_cursor_pos (hangul->table, 0);
396 ibus_hangul_engine_update_auxiliary_text (hangul);
397 ibus_hangul_engine_update_lookup_table (hangul);
402 ustring_delete (preedit);
406 ibus_hangul_engine_close_lookup_table (IBusHangulEngine *hangul)
408 ibus_engine_hide_lookup_table ((IBusEngine *)hangul);
409 ibus_engine_hide_auxiliary_text ((IBusEngine *)hangul);
410 hanja_list_delete (hangul->hanja_list);
411 hangul->hanja_list = NULL;
415 ibus_hangul_engine_toggle_lookup_table (IBusHangulEngine *hangul)
417 if (hangul->hanja_list != NULL) {
418 ibus_hangul_engine_close_lookup_table (hangul);
420 ibus_hangul_engine_open_lookup_table (hangul);
425 ibus_hangul_engine_process_candidate_key_event (IBusHangulEngine *hangul,
429 if (keyval == IBUS_Escape) {
430 ibus_hangul_engine_close_lookup_table (hangul);
432 } else if (keyval == IBUS_Return) {
433 ibus_hangul_engine_commit_current_candidate (hangul);
434 ibus_hangul_engine_close_lookup_table (hangul);
436 } else if (keyval >= IBUS_1 && keyval <= IBUS_9) {
441 page_size = ibus_lookup_table_get_page_size (hangul->table);
442 cursor_pos = ibus_lookup_table_get_cursor_pos (hangul->table);
443 page_no = cursor_pos / page_size;
445 cursor_pos = page_no * page_size + (keyval - IBUS_1);
446 ibus_lookup_table_set_cursor_pos (hangul->table, cursor_pos);
448 ibus_hangul_engine_commit_current_candidate (hangul);
449 ibus_hangul_engine_close_lookup_table (hangul);
451 } else if (keyval == IBUS_Left) {
452 ibus_lookup_table_cursor_up (hangul->table);
453 ibus_hangul_engine_update_lookup_table (hangul);
454 ibus_hangul_engine_update_auxiliary_text (hangul);
456 } else if (keyval == IBUS_Right) {
457 ibus_lookup_table_cursor_down (hangul->table);
458 ibus_hangul_engine_update_lookup_table (hangul);
459 ibus_hangul_engine_update_auxiliary_text (hangul);
461 } else if (keyval == IBUS_Up) {
462 ibus_lookup_table_page_up (hangul->table);
463 ibus_hangul_engine_update_lookup_table (hangul);
464 ibus_hangul_engine_update_auxiliary_text (hangul);
466 } else if (keyval == IBUS_Down) {
467 ibus_lookup_table_page_down (hangul->table);
468 ibus_hangul_engine_update_lookup_table (hangul);
469 ibus_hangul_engine_update_auxiliary_text (hangul);
471 } else if (keyval == IBUS_Page_Up) {
472 ibus_lookup_table_page_up (hangul->table);
473 ibus_hangul_engine_update_lookup_table (hangul);
474 ibus_hangul_engine_update_auxiliary_text (hangul);
476 } else if (keyval == IBUS_Page_Down) {
477 ibus_lookup_table_page_down (hangul->table);
478 ibus_hangul_engine_update_lookup_table (hangul);
479 ibus_hangul_engine_update_auxiliary_text (hangul);
483 if (!hangul->hanja_mode) {
484 if (keyval == IBUS_h) {
485 ibus_lookup_table_cursor_up (hangul->table);
486 ibus_hangul_engine_update_lookup_table (hangul);
487 ibus_hangul_engine_update_auxiliary_text (hangul);
489 } else if (keyval == IBUS_l) {
490 ibus_lookup_table_cursor_down (hangul->table);
491 ibus_hangul_engine_update_lookup_table (hangul);
492 ibus_hangul_engine_update_auxiliary_text (hangul);
494 } else if (keyval == IBUS_k) {
495 ibus_lookup_table_page_up (hangul->table);
496 ibus_hangul_engine_update_lookup_table (hangul);
497 ibus_hangul_engine_update_auxiliary_text (hangul);
499 } else if (keyval == IBUS_j) {
500 ibus_lookup_table_page_down (hangul->table);
501 ibus_hangul_engine_update_lookup_table (hangul);
502 ibus_hangul_engine_update_auxiliary_text (hangul);
511 ibus_hangul_engine_process_key_event (IBusEngine *engine,
516 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
521 if (modifiers & IBUS_RELEASE_MASK)
524 // if we don't ignore shift keys, shift key will make flush the preedit
525 // string. So you cannot input shift+key.
526 // Let's think about these examples:
529 if (keyval == IBUS_Shift_L || keyval == IBUS_Shift_R)
532 if (keyval == IBUS_F9 || keyval == IBUS_Hangul_Hanja) {
533 ibus_hangul_engine_toggle_lookup_table (hangul);
537 if (modifiers & (IBUS_CONTROL_MASK | IBUS_MOD1_MASK))
540 if (hangul->hanja_list != NULL) {
541 retval = ibus_hangul_engine_process_candidate_key_event (hangul,
543 if (hangul->hanja_mode) {
551 if (keyval == IBUS_BackSpace) {
552 retval = hangul_ic_backspace (hangul->context);
554 retval = hangul_ic_process (hangul->context, keyval);
557 str = hangul_ic_get_commit_string (hangul->context);
558 if (hangul->hanja_mode) {
559 const ucschar* hic_preedit;
561 hic_preedit = hangul_ic_get_preedit_string (hangul->context);
562 if (hic_preedit != NULL && hic_preedit[0] != 0) {
563 ustring_append_ucs4 (hangul->preedit, str, -1);
566 const ucschar* preedit;
568 ustring_append_ucs4 (hangul->preedit, str, -1);
570 preedit = ustring_begin (hangul->preedit);
571 text = ibus_text_new_from_ucs4 ((gunichar*)preedit);
572 ibus_engine_commit_text (engine, text);
573 g_object_unref (text);
574 ustring_clear (hangul->preedit);
577 if (str != NULL && str[0] != 0) {
578 IBusText *text = ibus_text_new_from_ucs4 (str);
579 ibus_engine_commit_text (engine, text);
580 g_object_unref (text);
584 ibus_hangul_engine_update_preedit_text (hangul);
586 if (hangul->hanja_mode) {
587 hanja_list_delete (hangul->hanja_list);
588 hangul->hanja_list = NULL;
590 ibus_hangul_engine_open_lookup_table (hangul);
592 if (hangul->hanja_list == NULL)
593 ibus_hangul_engine_close_lookup_table (hangul);
597 ibus_hangul_engine_flush (hangul);
603 ibus_hangul_engine_flush (IBusHangulEngine *hangul)
608 str = hangul_ic_flush (hangul->context);
610 if (str == NULL || str[0] == 0)
613 text = ibus_text_new_from_ucs4 (str);
615 ibus_engine_hide_preedit_text ((IBusEngine *) hangul);
616 ibus_engine_commit_text ((IBusEngine *) hangul, text);
618 g_object_unref (text);
622 ibus_hangul_engine_focus_in (IBusEngine *engine)
624 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
626 IBusText* label = NULL;
627 if (hangul->hanja_mode) {
628 label = ibus_text_new_from_static_string("漢");
630 label = ibus_text_new_from_static_string("韓");
632 ibus_property_set_label (hangul->prop_hanja_mode, label);
633 g_object_unref (label);
635 ibus_engine_register_properties (engine, hangul->prop_list);
637 if (hangul->hanja_list != NULL) {
638 ibus_hangul_engine_update_lookup_table (hangul);
639 ibus_hangul_engine_update_auxiliary_text (hangul);
642 parent_class->focus_in (engine);
646 ibus_hangul_engine_focus_out (IBusEngine *engine)
648 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
650 if (hangul->hanja_list == NULL) {
651 ibus_hangul_engine_flush (hangul);
653 ibus_engine_hide_lookup_table (engine);
654 ibus_engine_hide_auxiliary_text (engine);
657 parent_class->focus_out ((IBusEngine *) hangul);
661 ibus_hangul_engine_reset (IBusEngine *engine)
663 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
665 ibus_hangul_engine_flush (hangul);
666 if (hangul->hanja_list != NULL) {
667 ibus_hangul_engine_close_lookup_table (hangul);
669 parent_class->reset (engine);
673 ibus_hangul_engine_enable (IBusEngine *engine)
675 parent_class->enable (engine);
679 ibus_hangul_engine_disable (IBusEngine *engine)
681 ibus_hangul_engine_focus_out (engine);
682 parent_class->disable (engine);
686 ibus_hangul_engine_page_up (IBusEngine *engine)
688 parent_class->page_up (engine);
692 ibus_hangul_engine_page_down (IBusEngine *engine)
694 parent_class->page_down (engine);
698 ibus_hangul_engine_cursor_up (IBusEngine *engine)
700 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
702 if (hangul->hanja_list != NULL) {
703 ibus_lookup_table_cursor_up (hangul->table);
704 ibus_hangul_engine_update_lookup_table (hangul);
705 ibus_hangul_engine_update_auxiliary_text (hangul);
708 parent_class->cursor_up (engine);
712 ibus_hangul_engine_cursor_down (IBusEngine *engine)
714 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
716 if (hangul->hanja_list != NULL) {
717 ibus_lookup_table_cursor_down (hangul->table);
718 ibus_hangul_engine_update_lookup_table (hangul);
719 ibus_hangul_engine_update_auxiliary_text (hangul);
722 parent_class->cursor_down (engine);
726 ibus_hangul_engine_property_activate (IBusEngine *engine,
727 const gchar *prop_name,
730 if (strcmp(prop_name, "setup") == 0) {
731 GError *error = NULL;
732 gchar *argv[2] = { NULL, };
734 const char* libexecdir;
736 libexecdir = g_getenv("LIBEXECDIR");
737 if (libexecdir == NULL)
738 libexecdir = LIBEXECDIR;
740 path = g_build_filename(libexecdir, "ibus-setup-hangul", NULL);
743 g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error);
746 } else if (strcmp(prop_name, "hanja_mode") == 0) {
747 IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
750 hangul->hanja_mode = !hangul->hanja_mode;
752 if (hangul->hanja_mode) {
753 label = ibus_text_new_from_static_string("漢");
754 hangul->prop_hanja_mode->state = PROP_STATE_CHECKED;
756 label = ibus_text_new_from_static_string("韓");
757 hangul->prop_hanja_mode->state = PROP_STATE_UNCHECKED;
760 ibus_property_set_label (hangul->prop_hanja_mode, label);
761 ibus_engine_update_property (engine, hangul->prop_hanja_mode);
762 g_object_unref(label);
767 ibus_config_value_changed (IBusConfig *config,
768 const gchar *section,
773 IBusHangulEngine *hangul = (IBusHangulEngine *) user_data;
775 if (strcmp(section, "engine/Hangul") == 0) {
776 if (strcmp(name, "HangulKeyboard") == 0) {
777 const gchar *str = g_value_get_string (value);
778 g_string_assign (hangul_keyboard, str);
779 hangul_ic_select_keyboard (hangul->context, hangul_keyboard->str);