1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  *  Copyright (C) 2004 - 2005 Hiroyuki Ikezoe <poincare@ikezoe.net>
4  *  Copyright (C) 2004 - 2005 Takuro Ashie <ashie@homa.ne.jp>
5  *  Copyright (C) 2012 CSSlayer
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2, or (at your option)
10  *  any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 /*
23  * The original code is scim_uim_imengine.cpp in scim-uim-0.1.3.
24  * Copyright (C) 2004 James Su <suzhe@tsinghua.org.cn>
25  */
26 
27 #ifdef HAVE_CONFIG_H
28   #include <config.h>
29 #endif
30 
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <sys/types.h>
34 #include <errno.h>
35 
36 #include "factory.h"
37 #include "imengine.h"
38 #include "utils.h"
39 
40 #include <fcitx/context.h>
41 #include <fcitx-config/xdg.h>
42 #include <fcitx-config/fcitx-config.h>
43 #include <fcitx-utils/log.h>
44 #include <fcitx/module/clipboard/fcitx-clipboard.h>
45 
46 #define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
47 
48 #define UTF8_BRACKET_CORNER_BEGIN "\xE3\x80\x8C"
49 #define UTF8_BRACKET_CORNER_END   "\xE3\x80\x8D"
50 #define UTF8_BRACKET_WIDE_BEGIN   "\xEF\xBC\xBB"
51 #define UTF8_BRACKET_WIDE_END     "\xEF\xBC\xBD"
52 #define UTF8_MIDDLE_DOT           "\xE3\x83\xBB"
53 #define UTF8_SLASH_WIDE           "\xEF\xBC\x8F"
54 
55 #define ACTION_CONFIG_CIRCLE_INPUT_MODE_KEY       "CircleInputModeKey"
56 #define ACTION_CONFIG_CIRCLE_KANA_MODE_KEY        "CircleKanaModeKey"
57 #define ACTION_CONFIG_CIRCLE_LATIN_HIRAGANA_MODE_KEY  "CircleLatinHiraganaModeKey"
58 #define ACTION_CONFIG_CIRCLE_TYPING_METHOD_KEY    "CircleTypingMethodKey"
59 #define ACTION_CONFIG_LATIN_MODE_KEY              "LatinModeKey"
60 #define ACTION_CONFIG_WIDE_LATIN_MODE_KEY         "WideLatinModeKey"
61 #define ACTION_CONFIG_HIRAGANA_MODE_KEY           "HiraganaModeKey"
62 #define ACTION_CONFIG_KATAKANA_MODE_KEY           "KatakanaModeKey"
63 #define ACTION_CONFIG_HALF_KATAKANA_MODE_KEY      "HalfKatakanaModeKey"
64 #define ACTION_CONFIG_CANCEL_PSEUDO_ASCII_MODE_KEY  "CancelPseudoAsciiModeKey"
65 
66 #define ACTION_CONFIG_INSERT_SPACE_KEY            "InsertSpaceKey"
67 #define ACTION_CONFIG_INSERT_ALT_SPACE_KEY        "InsertAltSpaceKey"
68 #define ACTION_CONFIG_INSERT_HALF_SPACE_KEY       "InsertHalfSpaceKey"
69 #define ACTION_CONFIG_INSERT_WIDE_SPACE_KEY       "InsertWideSpaceKey"
70 #define ACTION_CONFIG_BACKSPACE_KEY               "BackSpaceKey"
71 #define ACTION_CONFIG_DELETE_KEY                  "DeleteKey"
72 #define ACTION_CONFIG_COMMIT_KEY                  "CommitKey"
73 #define ACTION_CONFIG_COMMIT_REVERSE_LEARN_KEY    "CommitReverseLearnKey"
74 #define ACTION_CONFIG_CONVERT_KEY                 "ConvertKey"
75 #define ACTION_CONFIG_PREDICT_KEY                 "PredictKey"
76 #define ACTION_CONFIG_CANCEL_KEY                  "CancelKey"
77 #define ACTION_CONFIG_CANCEL_ALL_KEY              "CancelAllKey"
78 
79 #define ACTION_CONFIG_MOVE_CARET_FIRST_KEY        "MoveCaretFirstKey"
80 #define ACTION_CONFIG_MOVE_CARET_LAST_KEY         "MoveCaretLastKey"
81 #define ACTION_CONFIG_MOVE_CARET_FORWARD_KEY      "MoveCaretForwardKey"
82 #define ACTION_CONFIG_MOVE_CARET_BACKWARD_KEY     "MoveCaretBackwardKey"
83 
84 #define ACTION_CONFIG_SELECT_FIRST_SEGMENT_KEY    "SelectFirstSegmentKey"
85 #define ACTION_CONFIG_SELECT_LAST_SEGMENT_KEY     "SelectLastSegmentKey"
86 #define ACTION_CONFIG_SELECT_NEXT_SEGMENT_KEY     "SelectNextSegmentKey"
87 #define ACTION_CONFIG_SELECT_PREV_SEGMENT_KEY     "SelectPrevSegmentKey"
88 #define ACTION_CONFIG_SHRINK_SEGMENT_KEY          "ShrinkSegmentKey"
89 #define ACTION_CONFIG_EXPAND_SEGMENT_KEY          "ExpandSegmentKey"
90 #define ACTION_CONFIG_COMMIT_FIRST_SEGMENT_KEY    "CommitFirstSegmentKey"
91 #define ACTION_CONFIG_COMMIT_SELECTED_SEGMENT_KEY "CommitSelectedSegmentKey"
92 #define ACTION_CONFIG_COMMIT_FIRST_SEGMENT_REVERSE_LEARN_KEY    "CommitFirstSegmentReverseLearnKey"
93 #define ACTION_CONFIG_COMMIT_SELECTED_SEGMENT_REVERSE_LEARN_KEY "CommitSelectedSegmentReverseLearnKey"
94 
95 #define ACTION_CONFIG_SELECT_FIRST_CANDIDATE_KEY  "SelectFirstCandidateKey"
96 #define ACTION_CONFIG_SELECT_LAST_CANDIDATE_KEY   "SelectLastCandidateKey"
97 #define ACTION_CONFIG_SELECT_NEXT_CANDIDATE_KEY   "SelectNextCandidateKey"
98 #define ACTION_CONFIG_SELECT_PREV_CANDIDATE_KEY   "SelectPrevCandidateKey"
99 #define ACTION_CONFIG_SELECT_NEXT_CANDIDATE_ALTER_KEY   "SelectNextCandidateKeyAlter"
100 #define ACTION_CONFIG_SELECT_PREV_CANDIDATE_ALTER_KEY   "SelectPrevCandidateKeyAlter"
101 #define ACTION_CONFIG_CANDIDATES_PAGE_UP_KEY      "CandidatesPageUpKey"
102 #define ACTION_CONFIG_CANDIDATES_PAGE_DOWN_KEY    "CandidatesPageDownKey"
103 #define ACTION_CONFIG_SELECT_CANDIDATE_1_KEY      "SelectCandidates1Key"
104 #define ACTION_CONFIG_SELECT_CANDIDATE_2_KEY      "SelectCandidates2Key"
105 #define ACTION_CONFIG_SELECT_CANDIDATE_3_KEY      "SelectCandidates3Key"
106 #define ACTION_CONFIG_SELECT_CANDIDATE_4_KEY      "SelectCandidates4Key"
107 #define ACTION_CONFIG_SELECT_CANDIDATE_5_KEY      "SelectCandidates5Key"
108 #define ACTION_CONFIG_SELECT_CANDIDATE_6_KEY      "SelectCandidates6Key"
109 #define ACTION_CONFIG_SELECT_CANDIDATE_7_KEY      "SelectCandidates7Key"
110 #define ACTION_CONFIG_SELECT_CANDIDATE_8_KEY      "SelectCandidates8Key"
111 #define ACTION_CONFIG_SELECT_CANDIDATE_9_KEY      "SelectCandidates9Key"
112 #define ACTION_CONFIG_SELECT_CANDIDATE_10_KEY     "SelectCandidates10Key"
113 
114 #define ACTION_CONFIG_CONV_CHAR_TYPE_FORWARD_KEY  "ConvertCharTypeForwardKey"
115 #define ACTION_CONFIG_CONV_CHAR_TYPE_BACKWARD_KEY "ConvertCharTypeBackwardKey"
116 #define ACTION_CONFIG_CONV_TO_HIRAGANA_KEY        "ConvertToHiraganaKey"
117 #define ACTION_CONFIG_CONV_TO_KATAKANA_KEY        "ConvertToKatakanaKey"
118 #define ACTION_CONFIG_CONV_TO_HALF_KEY            "ConvertToHalfKey"
119 #define ACTION_CONFIG_CONV_TO_HALF_KATAKANA_KEY   "ConvertToHalfKatakanaKey"
120 #define ACTION_CONFIG_CONV_TO_WIDE_LATIN_KEY      "ConvertToWideLatinKey"
121 #define ACTION_CONFIG_CONV_TO_LATIN_KEY           "ConvertToLatinKey"
122 
123 #define ACTION_CONFIG_RECONVERT_KEY               "ReconvertKey"
124 
125 #define ACTION_CONFIG_DICT_ADMIN_KEY              "DictAdminKey"
126 #define ACTION_CONFIG_ADD_WORD_KEY                "AddWordKey"
127 
128 #define N_(x) (x)
129 
AnthyInstance(FcitxInstance * instance)130 AnthyInstance::AnthyInstance (FcitxInstance* instance) :
131       m_owner(instance),
132       m_preedit                (*this),
133       m_preedit_string_visible (false),
134       m_input                  (FcitxInstanceGetInputState(m_owner)),
135       m_lookup_table           (FcitxInputStateGetCandidateList(m_input)),
136       m_lookup_table_visible   (false),
137       m_n_conv_key_pressed     (0),
138       m_prev_input_mode        (FCITX_ANTHY_MODE_HIRAGANA),
139       m_last_key               (),
140       m_aux_up                 (FcitxInputStateGetAuxUp(m_input)),
141       m_aux_down               (FcitxInputStateGetAuxDown(m_input)),
142       m_cursor_pos             (0),
143       m_client_preedit_msg     (FcitxInputStateGetClientPreedit(m_input)),
144       m_preedit_msg            (FcitxInputStateGetPreedit(m_input)),
145       m_profile                (FcitxInstanceGetProfile(m_owner)),
146       m_status_installed       (false),
147       m_ui_update              (false)
148 {
149     memset(&m_config, 0, sizeof(FcitxAnthyConfig));
150 
151 }
152 
~AnthyInstance()153 AnthyInstance::~AnthyInstance ()
154 {
155     FcitxConfigFree(&m_config.gconfig);
156     if (m_status_installed) {
157 #define FINALIZE_MENU(VARNAME) \
158         FcitxUIUnRegisterMenu(m_owner, &VARNAME); \
159         fcitx_utils_free(VARNAME.name); \
160         fcitx_utils_free(VARNAME.candStatusBind); \
161         FcitxMenuFinalize(&VARNAME);
162 
163         FINALIZE_MENU(m_input_mode_menu);
164         FINALIZE_MENU(m_typing_method_menu);
165         FINALIZE_MENU(m_conversion_mode_menu);
166         FINALIZE_MENU(m_period_style_menu);
167         FINALIZE_MENU(m_symbol_style_menu);
168     }
169 
170     if (m_config.m_custom_romaji_table) {
171         delete m_config.m_custom_romaji_table;
172         m_config.m_custom_romaji_table = NULL;
173     }
174 
175     if (m_config.m_custom_kana_table) {
176         delete m_config.m_custom_kana_table;
177         m_config.m_custom_kana_table = NULL;
178     }
179 
180     if (m_config.m_custom_nicola_table) {
181         delete m_config.m_custom_nicola_table;
182         m_config.m_custom_nicola_table = NULL;
183     }
184 }
185 
186 // FIXME!
187 bool
is_nicola_thumb_shift_key(const KeyEvent & key)188 AnthyInstance::is_nicola_thumb_shift_key (const KeyEvent &key)
189 {
190     if (get_typing_method () != FCITX_ANTHY_TYPING_METHOD_NICOLA)
191         return false;
192 
193     if (util_match_key_event (m_config.m_left_thumb_keys, key, 0xFFFF) ||
194         util_match_key_event (m_config.m_right_thumb_keys, key, 0xFFFF))
195     {
196         return true;
197     }
198 
199     return false;
200 }
201 
202 bool
process_key_event_input(const KeyEvent & key)203 AnthyInstance::process_key_event_input (const KeyEvent &key)
204 {
205     // prediction while typing
206     if (m_config.m_predict_on_input && key.is_release &&
207         m_preedit.is_preediting () && !m_preedit.is_converting ())
208     {
209         m_preedit.predict ();
210         m_preedit.get_candidates (m_lookup_table);
211     }
212 
213     if (!m_preedit.can_process_key_event (key)) {
214         return false;
215     }
216 
217     if (m_preedit.is_converting ()) {
218         if (is_realtime_conversion ()) {
219             action_revert ();
220         } else if (!is_nicola_thumb_shift_key (key)) {
221             action_commit (m_config.m_learn_on_auto_commit);
222         }
223     }
224 
225     bool need_commit = m_preedit.process_key_event (key);
226 
227     if (need_commit) {
228         if (is_realtime_conversion () &&
229             get_input_mode () != FCITX_ANTHY_MODE_LATIN &&
230             get_input_mode () != FCITX_ANTHY_MODE_WIDE_LATIN)
231         {
232             m_preedit.convert (FCITX_ANTHY_CANDIDATE_DEFAULT,
233                                is_single_segment ());
234         }
235         action_commit (m_config.m_learn_on_auto_commit);
236     } else {
237         if (is_realtime_conversion ()) {
238             m_preedit.convert (FCITX_ANTHY_CANDIDATE_DEFAULT,
239                                is_single_segment ());
240             m_preedit.select_segment (-1);
241         }
242         //show_preedit_string ();
243         m_preedit_string_visible = true;
244         set_preedition ();
245     }
246 
247     return true;
248 }
249 
250 bool
process_key_event_lookup_keybind(const KeyEvent & key)251 AnthyInstance::process_key_event_lookup_keybind (const KeyEvent& key)
252 {
253     std::map<std::string, Action>::iterator it;
254 
255     if (key.is_release)
256         return false;
257 
258     m_last_key = key;
259 
260     /* try to find a "insert a blank" action to be not stolen a blank key
261      * when entering the pseudo ascii mode.
262      */
263     if (get_pseudo_ascii_mode () != 0 &&
264         m_config.m_romaji_pseudo_ascii_blank_behavior &&
265         m_preedit.is_pseudo_ascii_mode ()) {
266         it = m_actions.find("INSERT_SPACE");
267         if (it != m_actions.end()) {
268             it->second.perform (this, key);
269             return true;
270         }
271     }
272 
273     for (it  = m_actions.begin();
274          it != m_actions.end();
275          it++)
276     {
277         if (it->second.perform (this, key)) {
278             m_last_key = KeyEvent ();
279             return true;
280         }
281     }
282 
283     int choose = FcitxHotkeyCheckChooseKey(key.sym, key.state & (FcitxKeyState_Ctrl_Alt_Shift | FcitxKeyState_Super), DIGIT_STR_CHOOSE);
284     if (choose >= 0) {
285         INPUT_RETURN_VALUE retVal = FcitxCandidateWordChooseByIndex(m_lookup_table, choose);
286         if (retVal != IRV_TO_PROCESS) {
287             m_last_key = KeyEvent ();
288             return true;
289         }
290     }
291 
292     m_last_key = KeyEvent ();
293 
294     return false;
295 }
296 
297 bool
process_key_event_latin_mode(const KeyEvent & key)298 AnthyInstance::process_key_event_latin_mode (const KeyEvent &key)
299 {
300     if (key.is_release)
301         return false;
302 
303     if (util_key_is_keypad (key)) {
304         std::string str;
305         std::string wide;
306         util_keypad_to_string (str, key);
307         if (m_config.m_ten_key_type == FCITX_ANTHY_TEN_KEY_TYPE_WIDE)
308             util_convert_to_wide (wide, str);
309         else
310             wide = str;
311         if (wide.length () > 0) {
312             commit_string (wide);
313             return true;
314         } else {
315             return false;
316         }
317     } else {
318         // for Multi/Dead key
319         return false;
320     }
321 }
322 
323 bool
process_key_event_wide_latin_mode(const KeyEvent & key)324 AnthyInstance::process_key_event_wide_latin_mode (const KeyEvent &key)
325 {
326     if (key.is_release)
327         return false;
328 
329     std::string str;
330     std::string wide;
331     util_keypad_to_string (str, key);
332     if (util_key_is_keypad (key) && m_config.m_ten_key_type == FCITX_ANTHY_TEN_KEY_TYPE_HALF)
333         wide = str;
334     else
335         util_convert_to_wide (wide, str);
336     if (wide.length () > 0) {
337         commit_string (wide);
338         return true;
339     }
340 
341     return false;
342 }
343 
344 bool
process_key_event(const KeyEvent & key)345 AnthyInstance::process_key_event (const KeyEvent& key)
346 {
347     // FIXME!
348     // for NICOLA thumb shift key
349     if (get_typing_method () == FCITX_ANTHY_TYPING_METHOD_NICOLA &&
350         is_nicola_thumb_shift_key (key))
351     {
352         if (process_key_event_input (key))
353             return true;
354     }
355 
356     // lookup user defined key bindings
357     if (process_key_event_lookup_keybind (key))
358         return true;
359 
360     if (FcitxHotkeyIsHotKeyDigit(key.sym, key.state)
361         && FcitxCandidateWordGetListSize(m_lookup_table) > 0
362     ) {
363         return false;
364     }
365 
366     // for Latin mode
367     if (m_preedit.get_input_mode () == FCITX_ANTHY_MODE_LATIN)
368         return process_key_event_latin_mode (key);
369 
370     // for wide Latin mode
371     if (m_preedit.get_input_mode () == FCITX_ANTHY_MODE_WIDE_LATIN)
372         return process_key_event_wide_latin_mode (key);
373 
374     // for other mode
375     if (get_typing_method () != FCITX_ANTHY_TYPING_METHOD_NICOLA ||
376         !is_nicola_thumb_shift_key (key))
377     {
378         if (process_key_event_input (key))
379             return true;
380     }
381 
382     if (m_preedit.is_preediting ())
383         return true;
384     else
385         return false;
386 }
387 
388 void
move_preedit_caret(unsigned int pos)389 AnthyInstance::move_preedit_caret (unsigned int pos)
390 {
391     m_preedit.set_caret_pos_by_char (pos);
392     // TODO
393 }
394 
395 void
select_candidate_no_direct(unsigned int item)396 AnthyInstance::select_candidate_no_direct (unsigned int item)
397 {
398     if (m_preedit.is_predicting () && !m_preedit.is_converting ())
399         action_predict ();
400 
401     // update lookup table
402     m_cursor_pos = item;
403 
404     // update preedit
405     m_preedit.select_candidate (m_cursor_pos);
406     set_preedition ();
407 
408     set_lookup_table();
409     FcitxCandidateWordSetFocus(m_lookup_table, m_cursor_pos);
410 
411     // update aux string
412     if (m_config.m_show_candidates_label)
413         set_aux_string ();
414 }
415 
416 void
select_candidate(unsigned int item)417 AnthyInstance::select_candidate (unsigned int item)
418 {
419     select_candidate_no_direct (item);
420 
421     unset_lookup_table ();
422     action_select_next_segment();
423 }
424 
425 void
update_lookup_table_page_size(unsigned int page_size)426 AnthyInstance::update_lookup_table_page_size (unsigned int page_size)
427 {
428     FcitxCandidateWordSetPageSize(m_lookup_table, page_size);
429 }
430 
431 void
reset_im()432 AnthyInstance::reset_im ()
433 {
434     FcitxInstanceCleanInputWindow(m_owner);
435 
436     m_preedit.clear ();
437     unset_lookup_table ();
438 
439     m_preedit_string_visible = false;
440     set_preedition ();
441 }
442 
443 void
init()444 AnthyInstance::init ()
445 {
446     boolean flag = true;
447     FcitxInstanceSetContext(m_owner, CONTEXT_IM_KEYBOARD_LAYOUT, "jp");
448     FcitxInstanceSetContext(m_owner, CONTEXT_DISABLE_AUTOENG, &flag);
449     FcitxInstanceSetContext(m_owner, CONTEXT_DISABLE_QUICKPHRASE, &flag);
450     FcitxInstanceSetContext(m_owner, CONTEXT_DISABLE_FULLWIDTH, &flag);
451     FcitxInstanceSetContext(m_owner, CONTEXT_DISABLE_AUTO_FIRST_CANDIDATE_HIGHTLIGHT, &flag);
452     FcitxInstanceCleanInputWindow(m_owner);
453     if (m_preedit_string_visible) {
454         set_preedition ();
455     }
456 
457     if (m_lookup_table_visible && is_selecting_candidates ()) {
458         if (m_config.m_show_candidates_label &&
459             FcitxCandidateWordGetListSize(m_lookup_table))
460         {
461             set_aux_string ();
462         }
463         set_lookup_table ();
464     }
465 
466     install_properties ();
467 }
468 
469 bool
support_client_preedit(void)470 AnthyInstance::support_client_preedit(void)
471 {
472     FcitxInputContext* ic = FcitxInstanceGetCurrentIC(m_owner);
473     if (ic && ((ic->contextCaps & CAPACITY_PREEDIT) == 0 || !m_profile->bUsePreedit))
474         return false;
475     else
476         return true;
477 }
478 
479 
480 void
set_preedition(void)481 AnthyInstance::set_preedition (void)
482 {
483     FcitxMessagesSetMessageCount(m_preedit_msg, 0);
484     FcitxMessagesSetMessageCount(m_client_preedit_msg, 0);
485     m_preedit.update_preedit();
486     if (!support_client_preedit())
487         FcitxInputStateSetShowCursor(m_input, true);
488     FcitxInputStateSetCursorPos(m_input, m_preedit.get_caret_pos());
489     FcitxInputStateSetClientCursorPos(m_input, m_preedit.get_caret_pos());
490     m_ui_update = true;
491 }
492 
493 void
update_ui(void)494 AnthyInstance::update_ui (void)
495 {
496     if (m_ui_update) {
497         m_ui_update = false;
498         FcitxUIUpdateInputWindow(m_owner);
499     }
500 }
501 
502 void
set_aux_string(void)503 AnthyInstance::set_aux_string (void)
504 {
505     if (!FcitxCandidateWordGetListSize(m_lookup_table))
506         return;
507 
508     char buf[256];
509     sprintf (buf, _("(%d / %d)"), m_cursor_pos + 1,
510              FcitxCandidateWordGetListSize(m_lookup_table));
511     update_aux_string (buf);
512 }
513 
514 int
set_lookup_table(void)515 AnthyInstance::set_lookup_table (void)
516 {
517     FcitxCandidateWordSetChoose(m_lookup_table, DIGIT_STR_CHOOSE);
518     FcitxCandidateWordSetPageSize(m_lookup_table, m_config.m_page_size);
519 
520     // if (!is_selecting_candidates ()) {
521     if (is_realtime_conversion () &&
522         m_preedit.get_selected_segment () < 0)
523     {
524         // select latest segment
525         int n = m_preedit.get_nr_segments ();
526         if (n < 1)
527             return 0;
528         m_preedit.select_segment (n - 1);
529     }
530 
531     // prepare candidates
532     m_preedit.get_candidates (m_lookup_table);
533 
534     if (FcitxCandidateWordPageCount(m_lookup_table) == 0)
535         return 0;
536 
537     // update preedit
538     m_preedit.select_candidate (m_cursor_pos);
539     set_preedition ();
540 
541     bool beyond_threshold =
542         m_config.m_n_triggers_to_show_cand_win > 0 &&
543         (int) m_n_conv_key_pressed >= m_config.m_n_triggers_to_show_cand_win;
544 
545     int len = FcitxCandidateWordGetListSize(m_lookup_table);
546 
547     if (!m_lookup_table_visible &&
548         (m_preedit.is_predicting () || beyond_threshold))
549     {
550         m_lookup_table_visible = true;
551         m_n_conv_key_pressed = 0;
552 
553         if (m_config.m_show_candidates_label) {
554             set_aux_string ();
555         }
556     } else if (!m_lookup_table_visible) {
557         FcitxCandidateWordReset(m_lookup_table);
558     }
559 
560     m_ui_update = true;
561 
562     return len;
563 }
564 
565 void
unset_lookup_table(void)566 AnthyInstance::unset_lookup_table (void)
567 {
568     FcitxCandidateWordReset(m_lookup_table);
569     m_lookup_table_visible = false;
570     m_n_conv_key_pressed = 0;
571     m_cursor_pos = 0;
572 
573     FcitxMessagesSetMessageCount(m_aux_up, 0);
574 }
575 
576 AnthyStatus input_mode_status[] = {
577     {"",  "\xe3\x81\x82", N_("Hiragana") },
578     {"", "\xe3\x82\xa2", N_("Katakana") },
579     {"", "\xef\xbd\xb1", N_("Half width katakana") },
580     {"", "A", N_("Direct input") },
581     {"", "\xef\xbc\xa1", N_("Wide latin") },
582 };
583 
584 AnthyStatus typing_method_status[] = {
585     {"", N_("Romaji"), N_("Romaji") },
586     {"", N_("Kana"), N_("Kana") },
587     {"", N_("Nicola"), N_("Thumb shift") },
588 };
589 
590 AnthyStatus conversion_mode_status[] = {
591     {"", "\xE9\x80\xA3", N_("Multi segment") },
592     {"", "\xE5\x8D\x98", N_("Single segment") },
593     {"", "\xE9\x80\x90", N_("Convert as you type (Multi segment)") },
594     {"", "\xE9\x80\x90", N_("Convert as you type (Single segment)") },
595 };
596 
597 AnthyStatus period_style_status[] = {
598     {"anthy-period-wide-latin", "\xEF\xBC\x8C\xEF\xBC\x8E", "\xEF\xBC\x8C\xEF\xBC\x8E" },
599     {"anthy-period-latin", ",.", ",." },
600     {"anthy-period-japanese", "\xE3\x80\x81\xE3\x80\x82", "\xE3\x80\x81\xE3\x80\x82" },
601     {"anthy-period-wide-japanese", "\xEF\xBC\x8C\xE3\x80\x82", "\xEF\xBC\x8C\xE3\x80\x82" },
602 };
603 
604 AnthyStatus symbol_style_status[] = {
605     {"anthy-symbol", UTF8_BRACKET_CORNER_BEGIN
606                         UTF8_BRACKET_CORNER_END
607                         UTF8_MIDDLE_DOT,
608                         UTF8_BRACKET_CORNER_BEGIN
609                         UTF8_BRACKET_CORNER_END
610                         UTF8_MIDDLE_DOT },
611     {"anthy-symbol", UTF8_BRACKET_CORNER_BEGIN
612                         UTF8_BRACKET_CORNER_END
613                         UTF8_SLASH_WIDE,
614                         UTF8_BRACKET_CORNER_BEGIN
615                         UTF8_BRACKET_CORNER_END
616                         UTF8_SLASH_WIDE },
617     {"anthy-symbol", UTF8_BRACKET_WIDE_BEGIN
618                         UTF8_BRACKET_WIDE_END
619                         UTF8_MIDDLE_DOT,
620                         UTF8_BRACKET_WIDE_BEGIN
621                         UTF8_BRACKET_WIDE_END
622                         UTF8_MIDDLE_DOT
623     },
624     {"anthy-symbol", UTF8_BRACKET_WIDE_BEGIN
625                         UTF8_BRACKET_WIDE_END
626                         UTF8_SLASH_WIDE,
627                         UTF8_BRACKET_WIDE_BEGIN
628                         UTF8_BRACKET_WIDE_END
629                         UTF8_SLASH_WIDE
630     },
631 };
632 
633 const char*
GetInputModeIconName(void * arg)634 GetInputModeIconName(void* arg)
635 {
636     AnthyInstance* anthy = (AnthyInstance*) arg;
637     return anthy->get_input_mode_icon();
638 }
639 
640 const char*
GetTypingMethodIconName(void * arg)641 GetTypingMethodIconName(void* arg)
642 {
643     AnthyInstance* anthy = (AnthyInstance*) arg;
644     return anthy->get_typing_method_icon();
645 }
646 
647 const char*
GetConversionModeIconName(void * arg)648 GetConversionModeIconName(void* arg)
649 {
650     AnthyInstance* anthy = (AnthyInstance*) arg;
651     return anthy->get_conversion_mode_icon();
652 }
653 
654 const char*
GetPeriodStyleIconName(void * arg)655 GetPeriodStyleIconName(void* arg)
656 {
657     AnthyInstance* anthy = (AnthyInstance*) arg;
658     return anthy->get_period_style_icon();
659 }
660 
661 const char*
GetSymbolStyleIconName(void * arg)662 GetSymbolStyleIconName(void* arg)
663 {
664     AnthyInstance* anthy = (AnthyInstance*) arg;
665     return anthy->get_symbol_style_icon();
666 }
667 
get_input_mode_icon()668 const char* AnthyInstance::get_input_mode_icon()
669 {
670     return input_mode_status[m_config.m_input_mode].icon;
671 }
672 
get_typing_method_icon()673 const char* AnthyInstance::get_typing_method_icon()
674 {
675     return typing_method_status[m_config.m_typing_method].icon;
676 }
677 
get_conversion_mode_icon()678 const char* AnthyInstance::get_conversion_mode_icon()
679 {
680     return conversion_mode_status[m_config.m_conversion_mode].icon;
681 }
682 
get_period_style_icon()683 const char* AnthyInstance::get_period_style_icon()
684 {
685     return period_style_status[m_config.m_period_comma_style].icon;
686 }
687 
get_symbol_style_icon()688 const char* AnthyInstance::get_symbol_style_icon()
689 {
690     return symbol_style_status[m_config.m_symbol_style].icon;
691 }
692 
get_input_mode_name()693 const char * AnthyInstance::get_input_mode_name()
694 {
695     return _(input_mode_status[m_config.m_input_mode].description);
696 }
697 
698 
699 #define DEFINE_MENU_ACTION(NAME, TYPE, FUNC) \
700     void Update##NAME##Menu(struct _FcitxUIMenu *menu) \
701     { \
702         AnthyInstance* anthy = (AnthyInstance*) menu->priv; \
703         menu->mark = anthy->get_##FUNC(); \
704     } \
705     boolean NAME##MenuAction(struct _FcitxUIMenu *menu, int index) \
706     { \
707         AnthyInstance* anthy = (AnthyInstance*) menu->priv; \
708         anthy->set_##FUNC((TYPE) index); \
709         anthy->save_config(); \
710         return true; \
711     }
712 
DEFINE_MENU_ACTION(InputMode,InputMode,input_mode)713 DEFINE_MENU_ACTION(InputMode, InputMode, input_mode)
714 DEFINE_MENU_ACTION(TypingMethod, TypingMethod, typing_method)
715 DEFINE_MENU_ACTION(ConversionMode, ConversionMode, conversion_mode)
716 DEFINE_MENU_ACTION(PeriodStyle, PeriodCommaStyle, period_style)
717 DEFINE_MENU_ACTION(SymbolStyle, SymbolStyle, symbol_style)
718 
719 void AnthyInstance::set_period_style(PeriodCommaStyle period)
720 {
721     m_config.m_period_comma_style = period;
722     FcitxUISetStatusString(m_owner,
723                             "anthy-period-style",
724                             _(period_style_status[period].label),
725                             _(period_style_status[period].description));
726 
727     switch (m_config.m_period_comma_style)
728     {
729         case FCITX_ANTHY_PERIOD_COMMA_WIDELATIN:
730             m_preedit.set_comma_style  (FCITX_ANTHY_COMMA_WIDE);
731             m_preedit.set_period_style (FCITX_ANTHY_PERIOD_WIDE);
732             break;
733         case FCITX_ANTHY_PERIOD_COMMA_LATIN:
734             m_preedit.set_comma_style  (FCITX_ANTHY_COMMA_HALF);
735             m_preedit.set_period_style (FCITX_ANTHY_PERIOD_HALF);
736             break;
737         case FCITX_ANTHY_PERIOD_COMMA_WIDELATIN_JAPANESE:
738             m_preedit.set_comma_style  (FCITX_ANTHY_COMMA_WIDE);
739             m_preedit.set_period_style (FCITX_ANTHY_PERIOD_JAPANESE);
740             break;
741         case FCITX_ANTHY_PERIOD_COMMA_JAPANESE:
742         default:
743             m_preedit.set_comma_style  (FCITX_ANTHY_COMMA_JAPANESE);
744             m_preedit.set_period_style (FCITX_ANTHY_PERIOD_JAPANESE);
745             break;
746     }
747 }
748 
set_symbol_style(SymbolStyle symbol)749 void AnthyInstance::set_symbol_style(SymbolStyle symbol)
750 {
751     m_config.m_symbol_style = symbol;
752     FcitxUISetStatusString(m_owner,
753                             "anthy-symbol-style",
754                             _(symbol_style_status[symbol].label),
755                             _(symbol_style_status[symbol].description));
756     switch (m_config.m_symbol_style)
757     {
758         case FCITX_ANTHY_SYMBOL_STYLE_WIDEBRACKET_WIDESLASH:
759             m_preedit.set_bracket_style (FCITX_ANTHY_BRACKET_JAPANESE);
760             m_preedit.set_slash_style   (FCITX_ANTHY_SLASH_WIDE);
761             break;
762         case FCITX_ANTHY_SYMBOL_STYLE_CORNERBRACKET_WIDESLASH:
763             m_preedit.set_bracket_style (FCITX_ANTHY_BRACKET_WIDE);
764             m_preedit.set_slash_style   (FCITX_ANTHY_SLASH_WIDE);
765             break;
766         case FCITX_ANTHY_SYMBOL_STYLE_CORNERBRACKET_MIDDLEDOT:
767             m_preedit.set_bracket_style (FCITX_ANTHY_BRACKET_WIDE);
768             m_preedit.set_slash_style   (FCITX_ANTHY_SLASH_JAPANESE);
769             break;
770         case FCITX_ANTHY_SYMBOL_STYLE_JAPANESE:
771         default:
772             m_preedit.set_bracket_style (FCITX_ANTHY_BRACKET_JAPANESE);
773             m_preedit.set_slash_style   (FCITX_ANTHY_SLASH_JAPANESE);
774             break;
775     }
776 }
777 
778 
779 void
install_properties(void)780 AnthyInstance::install_properties (void)
781 {
782     if (!m_status_installed) {
783         m_status_installed = true;
784 
785 #define INIT_MENU(VARNAME, NAME, I18NNAME, STATUS_NAME, STATUS_ARRAY, SIZE) \
786         FcitxUIRegisterComplexStatus(m_owner, this, \
787             STATUS_NAME, \
788             I18NNAME, \
789             I18NNAME, \
790             NULL, \
791             Get##NAME##IconName \
792         ); \
793         FcitxMenuInit(&VARNAME); \
794         VARNAME.name = strdup(I18NNAME); \
795         VARNAME.candStatusBind = strdup(STATUS_NAME); \
796         VARNAME.UpdateMenu = Update##NAME##Menu; \
797         VARNAME.MenuAction = NAME##MenuAction; \
798         VARNAME.priv = this; \
799         VARNAME.isSubMenu = false; \
800         for (int i = 0; i < SIZE; i ++) \
801             FcitxMenuAddMenuItem(&VARNAME, _(STATUS_ARRAY[i].label), MENUTYPE_SIMPLE, NULL); \
802         FcitxUIRegisterMenu(m_owner, &VARNAME); \
803         FcitxUISetStatusVisable(m_owner, STATUS_NAME, false);
804 
805         INIT_MENU(m_input_mode_menu, InputMode, _("Input Mode"), "anthy-input-mode", input_mode_status, FCITX_ANTHY_MODE_LAST);
806         INIT_MENU(m_typing_method_menu, TypingMethod, _("Typing Method"), "anthy-typing-method", typing_method_status, FCITX_ANTHY_TYPING_METHOD_LAST);
807         INIT_MENU(m_conversion_mode_menu, ConversionMode, _("Conversion Mode"), "anthy-conversion-mode", conversion_mode_status, FCITX_ANTHY_CONVERSION_MODE_LAST);
808         INIT_MENU(m_period_style_menu, PeriodStyle, _("Period Style"), "anthy-period-style", period_style_status, FCITX_ANTHY_PERIOD_COMMA_LAST);
809         INIT_MENU(m_symbol_style_menu, SymbolStyle, _("Symbol Style"), "anthy-symbol-style", symbol_style_status, FCITX_ANTHY_SYMBOL_STYLE_LAST);
810     }
811 
812     if (m_config.m_show_input_mode_label )
813 
814     set_input_mode(get_input_mode ());
815     set_conversion_mode (m_config.m_conversion_mode);
816     set_typing_method (get_typing_method ());
817     set_period_style (get_period_style());
818     set_symbol_style (get_symbol_style());
819 }
820 
821 void
set_input_mode(InputMode mode)822 AnthyInstance::set_input_mode (InputMode mode)
823 {
824     if (mode >= FCITX_ANTHY_MODE_LAST)
825         return;
826     if (mode != get_input_mode ()) {
827         m_config.m_input_mode = mode;
828         m_preedit.set_input_mode (mode);
829         set_preedition ();
830     }
831 
832     FcitxUISetStatusString(m_owner,
833                             "anthy-input-mode",
834                             _(input_mode_status[mode].label),
835                             _(input_mode_status[mode].description));
836 
837     FcitxInstanceShowCurrentIMInfo(m_owner);
838 }
839 
840 void
set_conversion_mode(ConversionMode mode)841 AnthyInstance::set_conversion_mode (ConversionMode mode)
842 {
843     if (mode >= FCITX_ANTHY_CONVERSION_MODE_LAST)
844         return;
845 
846     m_config.m_conversion_mode = mode;
847 
848     FcitxUISetStatusString(m_owner,
849                             "anthy-conversion-mode",
850                             _(conversion_mode_status[mode].label),
851                             _(conversion_mode_status[mode].description));
852 }
853 
854 void
set_typing_method(TypingMethod method)855 AnthyInstance::set_typing_method (TypingMethod method)
856 {
857     if (method != get_typing_method ()) {
858         m_preedit.set_typing_method (method);
859         m_preedit.set_pseudo_ascii_mode (get_pseudo_ascii_mode ());
860     }
861 
862     m_config.m_typing_method = method;
863 
864     FcitxUISetStatusString(m_owner,
865                             "anthy-typing-method",
866                             _(typing_method_status[method].label),
867                             _(typing_method_status[method].description));
868 }
869 
870 void
set_period_style(PeriodStyle period,CommaStyle comma)871 AnthyInstance::set_period_style (PeriodStyle period,
872                                  CommaStyle  comma)
873 {
874     std::string label;
875 
876     switch (comma) {
877     case FCITX_ANTHY_COMMA_JAPANESE:
878         label = "\xE3\x80\x81";
879         break;
880     case FCITX_ANTHY_COMMA_WIDE:
881         label = "\xEF\xBC\x8C";
882         break;
883     case FCITX_ANTHY_COMMA_HALF:
884         label = ",";
885         break;
886     default:
887         break;
888     }
889 
890     switch (period) {
891     case FCITX_ANTHY_PERIOD_JAPANESE:
892         label += "\xE3\x80\x82";
893         break;
894     case FCITX_ANTHY_PERIOD_WIDE:
895         label += "\xEF\xBC\x8E";
896         break;
897     case FCITX_ANTHY_PERIOD_HALF:
898         label += ".";
899         break;
900     default:
901         break;
902     }
903 
904     if (label.length () > 0) {
905 #if 0
906         PropertyList::iterator it = std::find (m_properties.begin (),
907                                                m_properties.end (),
908                                                SCIM_PROP_PERIOD_STYLE);
909         if (it != m_properties.end ()) {
910             it->set_label (label.c_str ());
911             update_property (*it);
912         }
913 #endif
914     }
915 
916     if (period != m_preedit.get_period_style ())
917         m_preedit.set_period_style (period);
918     if (comma != m_preedit.get_comma_style ())
919         m_preedit.set_comma_style (comma);
920 }
921 
922 void
set_symbol_style(BracketStyle bracket,SlashStyle slash)923 AnthyInstance::set_symbol_style (BracketStyle bracket,
924                                  SlashStyle   slash)
925 {
926     std::string label;
927 
928     switch (bracket) {
929     case FCITX_ANTHY_BRACKET_JAPANESE:
930         label = UTF8_BRACKET_CORNER_BEGIN UTF8_BRACKET_CORNER_END;
931         break;
932     case FCITX_ANTHY_BRACKET_WIDE:
933         label = UTF8_BRACKET_WIDE_BEGIN UTF8_BRACKET_WIDE_END;
934         break;
935     default:
936         break;
937     }
938 
939     switch (slash) {
940     case FCITX_ANTHY_SLASH_JAPANESE:
941         label += UTF8_MIDDLE_DOT;
942         break;
943     case FCITX_ANTHY_SLASH_WIDE:
944         label += UTF8_SLASH_WIDE;
945         break;
946     default:
947         break;
948     }
949 
950     if (label.length () > 0) {
951 #if 0
952         PropertyList::iterator it = std::find (m_properties.begin (),
953                                                m_properties.end (),
954                                                SCIM_PROP_SYMBOL_STYLE);
955         if (it != m_properties.end ()) {
956             it->set_label (label.c_str ());
957             update_property (*it);
958         }
959 #endif
960     }
961 
962     if (bracket != m_preedit.get_bracket_style ())
963         m_preedit.set_bracket_style (bracket);
964     if (slash != m_preedit.get_slash_style ())
965         m_preedit.set_slash_style (slash);
966 }
967 
968 bool
is_selecting_candidates(void)969 AnthyInstance::is_selecting_candidates (void)
970 {
971     if (FcitxCandidateWordGetListSize(m_lookup_table))
972         return true;
973     else
974         return false;
975 }
976 
reset(void)977 void AnthyInstance::reset(void )
978 {
979     FcitxIM* im = FcitxInstanceGetCurrentIM(m_owner);
980 #define RESET_STATUS(CONFIG_NAME, STATUS_NAME) \
981     if (m_config.CONFIG_NAME &&  im && strcmp(im->uniqueName, "anthy") == 0) \
982         FcitxUISetStatusVisable(m_owner, STATUS_NAME, true); \
983     else \
984         FcitxUISetStatusVisable(m_owner, STATUS_NAME, false);
985 
986     RESET_STATUS(m_show_input_mode_label, "anthy-input-mode")
987     RESET_STATUS(m_show_typing_method_label, "anthy-typing-method")
988     RESET_STATUS(m_show_conv_mode_label, "anthy-conversion-mode")
989     RESET_STATUS(m_show_period_style_label, "anthy-period-style")
990     RESET_STATUS(m_show_symbol_style_label, "anthy-symbol-style")
991 }
992 
993 bool
action_convert(void)994 AnthyInstance::action_convert (void)
995 {
996     if (!m_preedit.is_preediting ())
997         return false;
998 
999     if (!m_preedit.is_converting ()) {
1000         // show conversion string
1001         m_preedit.finish ();
1002         m_preedit.convert (FCITX_ANTHY_CANDIDATE_DEFAULT,
1003                            is_single_segment ());
1004         set_preedition ();
1005         m_n_conv_key_pressed++;
1006         set_lookup_table ();
1007         return true;
1008     }
1009 
1010     return false;
1011 }
1012 
1013 bool
action_predict(void)1014 AnthyInstance::action_predict (void)
1015 {
1016     if (!m_preedit.is_preediting ())
1017         return false;
1018 
1019     if (m_preedit.is_converting ())
1020         return false;
1021 
1022     if (!m_preedit.is_predicting ())
1023         m_preedit.predict ();
1024 
1025     m_preedit.select_candidate (0);
1026     set_preedition ();
1027     m_n_conv_key_pressed++;
1028     set_lookup_table ();
1029     select_candidate_no_direct (0);
1030 
1031     return true;
1032 }
1033 
1034 
1035 bool
action_revert(void)1036 AnthyInstance::action_revert (void)
1037 {
1038     if (m_preedit.is_reconverting ()) {
1039         m_preedit.revert ();
1040         commit_string (m_preedit.get_string ());
1041         reset_im ();
1042         return true;
1043     }
1044 
1045     if (!m_preedit.is_preediting ())
1046         return false;
1047 
1048     if (!m_preedit.is_converting ()) {
1049         reset_im ();
1050         return true;
1051     }
1052 
1053     if (is_selecting_candidates ()) {
1054         FcitxCandidateWordReset(m_lookup_table);
1055     }
1056 
1057     unset_lookup_table ();
1058     m_preedit.revert ();
1059     set_preedition ();
1060 
1061     return true;
1062 }
1063 
1064 bool
action_cancel_all(void)1065 AnthyInstance::action_cancel_all (void)
1066 {
1067     if (!m_preedit.is_preediting ())
1068         return false;
1069 
1070     reset_im ();
1071     return true;
1072 }
1073 
1074 bool
action_commit(bool learn,bool do_real_commit)1075 AnthyInstance::action_commit (bool learn, bool do_real_commit)
1076 {
1077     if (!m_preedit.is_preediting ())
1078         return false;
1079 
1080     if (m_preedit.is_converting ()) {
1081         if (do_real_commit)
1082             commit_string (m_preedit.get_string ());
1083         if (learn)
1084             m_preedit.commit ();
1085     } else {
1086         m_preedit.finish ();
1087         if (do_real_commit)
1088             commit_string (m_preedit.get_string ());
1089     }
1090 
1091     reset_im ();
1092 
1093     return true;
1094 }
1095 
1096 bool
action_commit_follow_preference(void)1097 AnthyInstance::action_commit_follow_preference (void)
1098 {
1099     return action_commit (m_config.m_learn_on_manual_commit);
1100 }
1101 
1102 bool
action_commit_reverse_preference(void)1103 AnthyInstance::action_commit_reverse_preference (void)
1104 {
1105     return action_commit (!m_config.m_learn_on_manual_commit);
1106 }
1107 
1108 bool
action_back(void)1109 AnthyInstance::action_back (void)
1110 {
1111     if (!m_preedit.is_preediting ())
1112         return false;
1113 
1114     if (m_preedit.is_converting ()) {
1115         action_revert ();
1116         if (!is_realtime_conversion ())
1117             return true;
1118     }
1119 
1120     m_preedit.erase ();
1121 
1122     if (m_preedit.get_length () > 0) {
1123         if (is_realtime_conversion ()) {
1124             m_preedit.convert (FCITX_ANTHY_CANDIDATE_DEFAULT,
1125                                is_single_segment ());
1126             m_preedit.select_segment (-1);
1127         }
1128         set_preedition ();
1129     } else {
1130         reset_im ();
1131     }
1132 
1133     return true;
1134 }
1135 
1136 bool
action_delete(void)1137 AnthyInstance::action_delete (void)
1138 {
1139     if (!m_preedit.is_preediting ())
1140         return false;
1141 
1142     if (m_preedit.is_converting ()) {
1143         action_revert ();
1144         if (!is_realtime_conversion ())
1145             return true;
1146     }
1147 
1148     m_preedit.erase (false);
1149 
1150     if (m_preedit.get_length () > 0) {
1151         if (is_realtime_conversion ()) {
1152             m_preedit.convert (FCITX_ANTHY_CANDIDATE_DEFAULT,
1153                                is_single_segment ());
1154             m_preedit.select_segment (-1);
1155         }
1156         set_preedition ();
1157     } else {
1158         reset_im ();
1159     }
1160 
1161     return true;
1162 }
1163 
1164 bool
action_insert_space(void)1165 AnthyInstance::action_insert_space (void)
1166 {
1167     std::string str;
1168     bool is_wide = false, retval = false;
1169 
1170     if (m_preedit.is_preediting () && !m_config.m_romaji_pseudo_ascii_blank_behavior)
1171         return false;
1172 
1173     if (m_config.m_space_type == FCITX_ANTHY_SPACE_TYPE_FOLLOWMODE) {
1174         InputMode mode = get_input_mode ();
1175         if (mode == FCITX_ANTHY_MODE_LATIN ||
1176             mode == FCITX_ANTHY_MODE_HALF_KATAKANA ||
1177             m_preedit.is_pseudo_ascii_mode ())
1178         {
1179             is_wide = false;
1180         } else {
1181             is_wide = true;
1182         }
1183     } else if (m_config.m_space_type == FCITX_ANTHY_SPACE_TYPE_WIDE) {
1184         is_wide = true;
1185     }
1186 
1187     if (is_wide) {
1188         str = "\xE3\x80\x80";
1189         retval = true;
1190     } else if (get_typing_method () == FCITX_ANTHY_TYPING_METHOD_NICOLA || // FIXME! it's a ad-hoc solution.
1191                m_preedit.is_pseudo_ascii_mode () ||
1192                (m_last_key.sym != FcitxKey_space &&
1193                 m_last_key.sym != FcitxKey_KP_Space))
1194     {
1195         str = " ";
1196         retval = true;
1197     }
1198 
1199     if (retval) {
1200         if (m_preedit.is_pseudo_ascii_mode ()) {
1201             m_preedit.append (m_last_key, str);
1202             // show_preedit_string ();
1203             m_preedit_string_visible = true;
1204             set_preedition ();
1205         } else {
1206             commit_string (str);
1207         }
1208     }
1209 
1210     return retval;
1211 }
1212 
1213 bool
action_insert_alternative_space(void)1214 AnthyInstance::action_insert_alternative_space (void)
1215 {
1216     bool is_wide = false;
1217 
1218     if (m_preedit.is_preediting ())
1219         return false;
1220 
1221     if (m_config.m_space_type == FCITX_ANTHY_SPACE_TYPE_FOLLOWMODE) {
1222         InputMode mode = get_input_mode ();
1223         if (mode == FCITX_ANTHY_MODE_LATIN ||
1224             mode == FCITX_ANTHY_MODE_HALF_KATAKANA)
1225         {
1226             is_wide = true;
1227         } else {
1228             is_wide = false;
1229         }
1230     } else if (m_config.m_space_type != FCITX_ANTHY_SPACE_TYPE_WIDE) {
1231         is_wide = true;
1232     }
1233 
1234     if (is_wide) {
1235         commit_string ("\xE3\x80\x80");
1236         return true;
1237     } else if (get_typing_method () == FCITX_ANTHY_TYPING_METHOD_NICOLA || // FIXME! it's a ad-hoc solution.
1238                (m_last_key.sym != FcitxKey_space &&
1239                 m_last_key.sym != FcitxKey_KP_Space))
1240     {
1241         commit_string (" ");
1242         return true;
1243     }
1244 
1245     return false;
1246 }
1247 
1248 bool
action_insert_half_space(void)1249 AnthyInstance::action_insert_half_space (void)
1250 {
1251     if (m_preedit.is_preediting ())
1252         return false;
1253 
1254     if (m_last_key.sym != FcitxKey_space &&
1255         m_last_key.sym != FcitxKey_KP_Space)
1256     {
1257         commit_string (" ");
1258         return true;
1259     }
1260 
1261     return false;
1262 }
1263 
1264 bool
action_insert_wide_space(void)1265 AnthyInstance::action_insert_wide_space (void)
1266 {
1267     if (m_preedit.is_preediting ())
1268         return false;
1269 
1270     commit_string ("\xE3\x80\x80");
1271 
1272     return true;
1273 }
1274 
1275 bool
action_move_caret_backward(void)1276 AnthyInstance::action_move_caret_backward (void)
1277 {
1278     if (!m_preedit.is_preediting ())
1279         return false;
1280     if (m_preedit.is_converting ())
1281         return false;
1282 
1283     m_preedit.move_caret(-1);
1284     set_preedition ();
1285 
1286     return true;
1287 }
1288 
1289 bool
action_move_caret_forward(void)1290 AnthyInstance::action_move_caret_forward (void)
1291 {
1292     if (!m_preedit.is_preediting ())
1293         return false;
1294     if (m_preedit.is_converting ())
1295         return false;
1296 
1297     m_preedit.move_caret(1);
1298     set_preedition ();
1299 
1300     return true;
1301 }
1302 
1303 bool
action_move_caret_first(void)1304 AnthyInstance::action_move_caret_first (void)
1305 {
1306     if (!m_preedit.is_preediting ())
1307         return false;
1308     if (m_preedit.is_converting ())
1309         return false;
1310 
1311     m_preedit.set_caret_pos_by_char (0);
1312     set_preedition ();
1313 
1314     return true;
1315 }
1316 
1317 bool
action_move_caret_last(void)1318 AnthyInstance::action_move_caret_last (void)
1319 {
1320     if (!m_preedit.is_preediting ())
1321         return false;
1322     if (m_preedit.is_converting ())
1323         return false;
1324 
1325     m_preedit.set_caret_pos_by_char (m_preedit.get_length_by_char ());
1326     set_preedition ();
1327 
1328     return true;
1329 }
1330 
1331 bool
action_select_prev_segment(void)1332 AnthyInstance::action_select_prev_segment (void)
1333 {
1334     if (!m_preedit.is_converting ())
1335         return false;
1336 
1337     unset_lookup_table ();
1338 
1339     int idx = m_preedit.get_selected_segment ();
1340     if (idx - 1 < 0) {
1341         int n = m_preedit.get_nr_segments ();
1342         if (n <= 0) return false;
1343         m_preedit.select_segment (n - 1);
1344     } else {
1345         m_preedit.select_segment (idx - 1);
1346     }
1347     set_preedition ();
1348 
1349     return true;
1350 }
1351 
1352 bool
action_select_next_segment(void)1353 AnthyInstance::action_select_next_segment (void)
1354 {
1355     if (!m_preedit.is_converting ())
1356         return false;
1357 
1358     unset_lookup_table ();
1359 
1360     int idx = m_preedit.get_selected_segment ();
1361     if (idx < 0) {
1362         m_preedit.select_segment(0);
1363     } else {
1364         int n = m_preedit.get_nr_segments ();
1365         if (n <= 0)
1366             return false;
1367         if (idx + 1 >= n)
1368             m_preedit.select_segment(0);
1369         else
1370             m_preedit.select_segment(idx + 1);
1371     }
1372     set_preedition ();
1373 
1374     return true;
1375 }
1376 
1377 bool
action_select_first_segment(void)1378 AnthyInstance::action_select_first_segment (void)
1379 {
1380     if (!m_preedit.is_converting ())
1381         return false;
1382 
1383     unset_lookup_table ();
1384 
1385     m_preedit.select_segment(0);
1386     set_preedition ();
1387 
1388     return true;
1389 }
1390 
1391 bool
action_select_last_segment(void)1392 AnthyInstance::action_select_last_segment (void)
1393 {
1394     if (!m_preedit.is_converting ())
1395         return false;
1396 
1397     int n = m_preedit.get_nr_segments ();
1398     if (n <= 0) return false;
1399 
1400     unset_lookup_table ();
1401 
1402     m_preedit.select_segment(n - 1);
1403     set_preedition ();
1404 
1405     return true;
1406 }
1407 
1408 bool
action_shrink_segment(void)1409 AnthyInstance::action_shrink_segment (void)
1410 {
1411     if (!m_preedit.is_converting ())
1412         return false;
1413 
1414     unset_lookup_table ();
1415 
1416     m_preedit.resize_segment (-1);
1417     set_preedition ();
1418 
1419     return true;
1420 }
1421 
1422 bool
action_expand_segment(void)1423 AnthyInstance::action_expand_segment (void)
1424 {
1425     if (!m_preedit.is_converting ())
1426         return false;
1427 
1428     unset_lookup_table ();
1429 
1430     m_preedit.resize_segment (1);
1431     set_preedition ();
1432 
1433     return true;
1434 }
1435 
1436 bool
action_commit_first_segment(void)1437 AnthyInstance::action_commit_first_segment (void)
1438 {
1439     if (!m_preedit.is_converting ()) {
1440         if (m_preedit.is_preediting ()) {
1441             return action_commit (m_config.m_learn_on_manual_commit);
1442         } else {
1443             return false;
1444         }
1445     }
1446 
1447     unset_lookup_table ();
1448 
1449     commit_string (m_preedit.get_segment_string (0));
1450     if (m_config.m_learn_on_manual_commit)
1451         m_preedit.commit (0);
1452     else
1453         m_preedit.clear (0);
1454 
1455     set_preedition ();
1456 
1457     return true;
1458 }
1459 
1460 bool
action_commit_selected_segment(void)1461 AnthyInstance::action_commit_selected_segment (void)
1462 {
1463     if (!m_preedit.is_converting ()) {
1464         if (m_preedit.is_preediting ()) {
1465             return action_commit (m_config.m_learn_on_manual_commit);
1466         } else {
1467             return false;
1468         }
1469     }
1470 
1471     unset_lookup_table ();
1472 
1473     for (int i = 0; i <= m_preedit.get_selected_segment (); i++)
1474         commit_string (m_preedit.get_segment_string (i));
1475     if (m_config.m_learn_on_manual_commit)
1476         m_preedit.commit (m_preedit.get_selected_segment ());
1477     else
1478         m_preedit.clear (m_preedit.get_selected_segment ());
1479 
1480     set_preedition ();
1481 
1482     return true;
1483 }
1484 
1485 bool
action_commit_first_segment_reverse_preference(void)1486 AnthyInstance::action_commit_first_segment_reverse_preference (void)
1487 {
1488     if (!m_preedit.is_converting ()) {
1489         if (m_preedit.is_preediting ()) {
1490             return action_commit (!m_config.m_learn_on_manual_commit);
1491         } else {
1492             return false;
1493         }
1494     }
1495 
1496     unset_lookup_table ();
1497 
1498     commit_string (m_preedit.get_segment_string (0));
1499     if (!m_config.m_learn_on_manual_commit)
1500         m_preedit.commit (0);
1501     else
1502         m_preedit.clear (0);
1503 
1504     set_preedition ();
1505 
1506     return true;
1507 }
1508 
1509 bool
action_commit_selected_segment_reverse_preference(void)1510 AnthyInstance::action_commit_selected_segment_reverse_preference (void)
1511 {
1512     if (!m_preedit.is_converting ()) {
1513         if (m_preedit.is_preediting ()) {
1514             return action_commit (!m_config.m_learn_on_manual_commit);
1515         } else {
1516             return false;
1517         }
1518     }
1519 
1520     unset_lookup_table ();
1521 
1522     for (int i = 0; i <= m_preedit.get_selected_segment (); i++)
1523         commit_string (m_preedit.get_segment_string (i));
1524     if (!m_config.m_learn_on_manual_commit)
1525         m_preedit.commit (m_preedit.get_selected_segment ());
1526     else
1527         m_preedit.clear (m_preedit.get_selected_segment ());
1528 
1529     set_preedition ();
1530 
1531     return true;
1532 }
1533 
1534 bool
action_select_next_candidate(void)1535 AnthyInstance::action_select_next_candidate (void)
1536 {
1537     if (!m_preedit.is_converting ())
1538         return false;
1539 
1540     //if (!is_selecting_candidates ())
1541     int end = set_lookup_table ();
1542 
1543     if (m_cursor_pos >= end - 1)
1544         m_cursor_pos = 0;
1545     else
1546         m_cursor_pos ++;
1547     m_n_conv_key_pressed++;
1548 
1549     select_candidate_no_direct (m_cursor_pos);
1550     return true;
1551 }
1552 
1553 bool
action_select_prev_candidate(void)1554 AnthyInstance::action_select_prev_candidate (void)
1555 {
1556     if (!m_preedit.is_converting ()) return false;
1557     //if (!is_selecting_candidates ())
1558     int end = set_lookup_table ();
1559 
1560     if (end < 0)
1561         end = 0;
1562     if (m_cursor_pos == 0)
1563         m_cursor_pos = end - 1;
1564     else
1565         m_cursor_pos --;
1566     m_n_conv_key_pressed++;
1567 
1568     FcitxCandidateWordSetFocus(m_lookup_table, m_cursor_pos);
1569 
1570     select_candidate_no_direct (m_cursor_pos);
1571 
1572     return true;
1573 }
1574 
1575 bool
action_select_first_candidate(void)1576 AnthyInstance::action_select_first_candidate (void)
1577 {
1578     if (!m_preedit.is_converting ()) return false;
1579     if (!is_selecting_candidates ()) return false;
1580 
1581     m_cursor_pos = 0;
1582     m_n_conv_key_pressed++;
1583     select_candidate_no_direct (m_cursor_pos);
1584     return true;
1585 }
1586 
1587 bool
action_select_last_candidate(void)1588 AnthyInstance::action_select_last_candidate (void)
1589 {
1590     if (!m_preedit.is_converting ()) return false;
1591     if (!is_selecting_candidates ()) return false;
1592 
1593     int end = FcitxCandidateWordGetListSize(m_lookup_table) - 1;
1594     if (end < 0)
1595         end = 0;
1596     m_cursor_pos = 0;
1597     m_n_conv_key_pressed++;
1598     select_candidate_no_direct (m_cursor_pos);
1599     return true;
1600 }
1601 
1602 bool
action_candidates_page_up(void)1603 AnthyInstance::action_candidates_page_up(void)
1604 {
1605     if (!m_preedit.is_converting ()) return false;
1606     if (!is_selecting_candidates ()) return false;
1607     if (!m_lookup_table_visible) return false;
1608 
1609     if (m_cursor_pos - m_config.m_page_size >= 0) {
1610         m_cursor_pos -= m_config.m_page_size;
1611         select_candidate_no_direct (m_cursor_pos);
1612     }
1613 
1614     return true;
1615 }
1616 
1617 bool
action_candidates_page_down(void)1618 AnthyInstance::action_candidates_page_down (void)
1619 {
1620     if (!m_preedit.is_converting ()) return false;
1621     if (!is_selecting_candidates ()) return false;
1622     if (!m_lookup_table_visible) return false;
1623 
1624     int end = FcitxCandidateWordGetListSize(m_lookup_table);
1625 
1626     if (m_cursor_pos + m_config.m_page_size < end) {
1627         m_cursor_pos += m_config.m_page_size;
1628         select_candidate_no_direct (m_cursor_pos);
1629     }
1630 
1631     return true;
1632 }
1633 
1634 bool
action_select_candidate(unsigned int i)1635 AnthyInstance::action_select_candidate (unsigned int i)
1636 {
1637     // FIXME! m_lookup_table_visible should be set as true also on predicting
1638     if (!m_lookup_table_visible && !m_preedit.is_predicting ())
1639         return false;
1640 
1641     if (m_preedit.is_predicting () && !m_preedit.is_converting () &&
1642         m_config.m_use_direct_key_on_predict)
1643     {
1644         m_preedit.get_candidates (m_lookup_table);
1645         select_candidate (i);
1646         return true;
1647     } else if (m_preedit.is_converting () && is_selecting_candidates ()) {
1648         select_candidate (i);
1649         return true;
1650     }
1651 
1652     return false;
1653 }
1654 
1655 bool
action_circle_input_mode(void)1656 AnthyInstance::action_circle_input_mode (void)
1657 {
1658     InputMode mode = get_input_mode ();
1659 
1660     mode = (InputMode) ((mode + 1) % FCITX_ANTHY_MODE_LAST);
1661 
1662     set_input_mode (mode);
1663     save_config();
1664 
1665     return true;
1666 }
1667 
1668 bool
action_circle_typing_method(void)1669 AnthyInstance::action_circle_typing_method (void)
1670 {
1671     TypingMethod method;
1672 
1673     method = get_typing_method ();
1674     method = (TypingMethod) ((method + 1) % FCITX_ANTHY_TYPING_METHOD_NICOLA);
1675 
1676     set_typing_method (method);
1677     save_config();
1678 
1679     return true;
1680 }
1681 
1682 bool
action_circle_kana_mode(void)1683 AnthyInstance::action_circle_kana_mode (void)
1684 {
1685     InputMode mode;
1686 
1687     if (get_input_mode () == FCITX_ANTHY_MODE_LATIN ||
1688         get_input_mode () == FCITX_ANTHY_MODE_WIDE_LATIN)
1689     {
1690         mode = FCITX_ANTHY_MODE_HIRAGANA;
1691     } else {
1692         switch (get_input_mode ()) {
1693         case FCITX_ANTHY_MODE_HIRAGANA:
1694             mode = FCITX_ANTHY_MODE_KATAKANA;
1695             break;
1696         case FCITX_ANTHY_MODE_KATAKANA:
1697             mode = FCITX_ANTHY_MODE_HALF_KATAKANA;
1698             break;
1699         case FCITX_ANTHY_MODE_HALF_KATAKANA:
1700         default:
1701             mode = FCITX_ANTHY_MODE_HIRAGANA;
1702             break;
1703         }
1704     }
1705 
1706     set_input_mode (mode);
1707     save_config();
1708 
1709     return true;
1710 }
1711 
1712 bool
action_circle_latin_hiragana_mode(void)1713 AnthyInstance::action_circle_latin_hiragana_mode (void)
1714 {
1715     InputMode mode = get_input_mode ();
1716 
1717     if (mode == FCITX_ANTHY_MODE_LATIN)
1718     {
1719         mode = FCITX_ANTHY_MODE_HIRAGANA;
1720     } else if (mode == FCITX_ANTHY_MODE_HIRAGANA)
1721     {
1722         mode = FCITX_ANTHY_MODE_LATIN;
1723     }
1724 
1725     set_input_mode (mode);
1726     save_config();
1727 
1728     return true;
1729 }
1730 
1731 bool
action_latin_mode(void)1732 AnthyInstance::action_latin_mode (void)
1733 {
1734     set_input_mode (FCITX_ANTHY_MODE_LATIN);
1735     save_config();
1736     return true;
1737 }
1738 
1739 bool
action_wide_latin_mode(void)1740 AnthyInstance::action_wide_latin_mode (void)
1741 {
1742     set_input_mode (FCITX_ANTHY_MODE_WIDE_LATIN);
1743     save_config();
1744     return true;
1745 }
1746 
1747 bool
action_hiragana_mode(void)1748 AnthyInstance::action_hiragana_mode (void)
1749 {
1750     set_input_mode (FCITX_ANTHY_MODE_HIRAGANA);
1751     save_config();
1752     return true;
1753 }
1754 
1755 bool
action_katakana_mode(void)1756 AnthyInstance::action_katakana_mode (void)
1757 {
1758     set_input_mode (FCITX_ANTHY_MODE_KATAKANA);
1759     save_config();
1760     return true;
1761 }
1762 
1763 bool
action_half_katakana_mode(void)1764 AnthyInstance::action_half_katakana_mode (void)
1765 {
1766     set_input_mode (FCITX_ANTHY_MODE_HALF_KATAKANA);
1767     save_config();
1768     return true;
1769 }
1770 
1771 bool
action_cancel_pseudo_ascii_mode(void)1772 AnthyInstance::action_cancel_pseudo_ascii_mode (void)
1773 {
1774     if (!m_preedit.is_preediting ())
1775         return false;
1776     if (!m_preedit.is_pseudo_ascii_mode ())
1777         return false;
1778 
1779     m_preedit.reset_pseudo_ascii_mode ();
1780 
1781     return true;
1782 }
1783 
1784 bool
convert_kana(CandidateType type)1785 AnthyInstance::convert_kana (CandidateType type)
1786 {
1787     if (!m_preedit.is_preediting ())
1788         return false;
1789 
1790     if (m_preedit.is_reconverting ())
1791         return false;
1792 
1793     unset_lookup_table ();
1794 
1795     if (m_preedit.is_converting ()) {
1796         int idx = m_preedit.get_selected_segment ();
1797         if (idx < 0) {
1798             action_revert ();
1799             m_preedit.finish ();
1800             m_preedit.convert (type, true);
1801         } else {
1802             m_preedit.select_candidate (type);
1803         }
1804     } else {
1805         m_preedit.finish ();
1806         m_preedit.convert (type, true);
1807     }
1808 
1809     set_preedition ();
1810 
1811     return true;
1812 }
1813 
1814 bool
action_convert_to_hiragana(void)1815 AnthyInstance::action_convert_to_hiragana (void)
1816 {
1817     return convert_kana (FCITX_ANTHY_CANDIDATE_HIRAGANA);
1818 }
1819 
1820 bool
action_convert_to_katakana(void)1821 AnthyInstance::action_convert_to_katakana (void)
1822 {
1823     return convert_kana (FCITX_ANTHY_CANDIDATE_KATAKANA);
1824 }
1825 
1826 bool
action_convert_to_half(void)1827 AnthyInstance::action_convert_to_half (void)
1828 {
1829     return convert_kana (FCITX_ANTHY_CANDIDATE_HALF);
1830 }
1831 
1832 bool
action_convert_to_half_katakana(void)1833 AnthyInstance::action_convert_to_half_katakana (void)
1834 {
1835     return convert_kana (FCITX_ANTHY_CANDIDATE_HALF_KATAKANA);
1836 }
1837 
1838 bool
action_convert_to_latin(void)1839 AnthyInstance::action_convert_to_latin (void)
1840 {
1841     return convert_kana (FCITX_ANTHY_CANDIDATE_LATIN);
1842 }
1843 
1844 bool
action_convert_to_wide_latin(void)1845 AnthyInstance::action_convert_to_wide_latin (void)
1846 {
1847     return convert_kana (FCITX_ANTHY_CANDIDATE_WIDE_LATIN);
1848 }
1849 
1850 bool
action_convert_char_type_forward(void)1851 AnthyInstance::action_convert_char_type_forward (void)
1852 {
1853     if (!m_preedit.is_preediting ())
1854         return false;
1855 
1856     unset_lookup_table ();
1857 
1858     if (m_preedit.is_converting ()) {
1859         int idx = m_preedit.get_selected_segment ();
1860         if (idx < 0) {
1861             action_revert ();
1862             m_preedit.finish ();
1863             m_preedit.convert (FCITX_ANTHY_CANDIDATE_HIRAGANA, true);
1864         } else {
1865             int cand = m_preedit.get_selected_candidate ();
1866             switch (cand)
1867             {
1868             case FCITX_ANTHY_CANDIDATE_HIRAGANA:
1869                 m_preedit.select_candidate (FCITX_ANTHY_CANDIDATE_KATAKANA);
1870                 break;
1871             case FCITX_ANTHY_CANDIDATE_KATAKANA:
1872                 m_preedit.select_candidate (FCITX_ANTHY_CANDIDATE_HALF_KATAKANA);
1873                 break;
1874             case FCITX_ANTHY_CANDIDATE_HALF_KATAKANA:
1875                 m_preedit.select_candidate (FCITX_ANTHY_CANDIDATE_WIDE_LATIN);
1876                 break;
1877             case FCITX_ANTHY_CANDIDATE_WIDE_LATIN:
1878                 m_preedit.select_candidate (FCITX_ANTHY_CANDIDATE_LATIN);
1879                 break;
1880             case FCITX_ANTHY_CANDIDATE_LATIN:
1881                 m_preedit.select_candidate (FCITX_ANTHY_CANDIDATE_HIRAGANA);
1882                 break;
1883             default:
1884                 m_preedit.select_candidate (FCITX_ANTHY_CANDIDATE_HIRAGANA);
1885                 break;
1886             }
1887         }
1888     } else {
1889         m_preedit.finish ();
1890         m_preedit.convert (FCITX_ANTHY_CANDIDATE_HIRAGANA, true);
1891     }
1892 
1893     set_preedition ();
1894 
1895     return true;
1896 }
1897 
1898 bool
action_convert_char_type_backward(void)1899 AnthyInstance::action_convert_char_type_backward (void)
1900 {
1901     if (!m_preedit.is_preediting ())
1902         return false;
1903 
1904     unset_lookup_table ();
1905 
1906     if (m_preedit.is_converting ()) {
1907         int idx = m_preedit.get_selected_segment ();
1908         if (idx < 0) {
1909             action_revert ();
1910             m_preedit.finish ();
1911             m_preedit.convert (FCITX_ANTHY_CANDIDATE_HIRAGANA, true);
1912         } else {
1913             int cand = m_preedit.get_selected_candidate ();
1914             switch (cand)
1915             {
1916             case FCITX_ANTHY_CANDIDATE_HIRAGANA:
1917                 m_preedit.select_candidate (FCITX_ANTHY_CANDIDATE_LATIN);
1918                 break;
1919             case FCITX_ANTHY_CANDIDATE_KATAKANA:
1920                 m_preedit.select_candidate (FCITX_ANTHY_CANDIDATE_HIRAGANA);
1921                 break;
1922             case FCITX_ANTHY_CANDIDATE_HALF_KATAKANA:
1923                 m_preedit.select_candidate (FCITX_ANTHY_CANDIDATE_KATAKANA);
1924                 break;
1925             case FCITX_ANTHY_CANDIDATE_WIDE_LATIN:
1926                 m_preedit.select_candidate (FCITX_ANTHY_CANDIDATE_HALF_KATAKANA);
1927                 break;
1928             case FCITX_ANTHY_CANDIDATE_LATIN:
1929                 m_preedit.select_candidate (FCITX_ANTHY_CANDIDATE_WIDE_LATIN);
1930                 break;
1931             default:
1932                 m_preedit.select_candidate (FCITX_ANTHY_CANDIDATE_HIRAGANA);
1933                 break;
1934             }
1935         }
1936     } else {
1937         m_preedit.finish ();
1938         m_preedit.convert (FCITX_ANTHY_CANDIDATE_HIRAGANA, true);
1939     }
1940 
1941     set_preedition ();
1942 
1943     return true;
1944 }
1945 
1946 bool
action_reconvert(void)1947 AnthyInstance::action_reconvert (void)
1948 {
1949     if (m_preedit.is_preediting ())
1950         return false;
1951 
1952     FcitxInputContext* ic = FcitxInstanceGetCurrentIC(m_owner);
1953 
1954     if (!ic || !(ic->contextCaps & CAPACITY_SURROUNDING_TEXT)) {
1955         return true;
1956     }
1957     uint cursor_pos = 0;
1958     uint anchor_pos = 0;
1959     int32_t relative_selected_length = 0;
1960 
1961     char* str = NULL;
1962     if (!FcitxInstanceGetSurroundingText(m_owner, ic, &str, &cursor_pos, &anchor_pos)) {
1963         return true;
1964     }
1965 
1966     const std::string surrounding_text(str);
1967 
1968     if (cursor_pos == anchor_pos) {
1969         const char* primary = NULL;
1970 
1971         if ((primary = FcitxClipboardGetPrimarySelection(m_owner, NULL)) != NULL) {
1972             uint new_anchor_pos = 0;
1973             const std::string primary_text(primary);
1974             if (util_surrounding_get_anchor_pos_from_selection(
1975                     surrounding_text, primary_text,
1976                     cursor_pos, &new_anchor_pos)) {
1977                 anchor_pos = new_anchor_pos;
1978             } else {
1979                 return true;
1980             }
1981         } else {
1982             // There is no selection text.
1983             return true;
1984         }
1985     }
1986 
1987     if (!util_surrounding_get_safe_delta(cursor_pos, anchor_pos,
1988                                          &relative_selected_length)) {
1989         return true;
1990     }
1991 
1992     const uint32_t selection_start = std::min(cursor_pos, anchor_pos);
1993     const uint32_t selection_length = abs(relative_selected_length);
1994     std::string text = util_utf8_string_substr(surrounding_text, selection_start, selection_length);
1995 
1996     FcitxInstanceDeleteSurroundingText(m_owner, ic,
1997                                        cursor_pos > anchor_pos ? -relative_selected_length : 0,
1998                                        selection_length);
1999 
2000     m_preedit.convert(text);
2001     set_preedition ();
2002     set_lookup_table ();
2003 
2004     return true;
2005 }
2006 
2007 bool
action_add_word(void)2008 AnthyInstance::action_add_word (void)
2009 {
2010     util_launch_program (m_config.m_add_word_command);
2011 
2012     return true;
2013 }
2014 
2015 bool
action_launch_dict_admin_tool(void)2016 AnthyInstance::action_launch_dict_admin_tool (void)
2017 {
2018     util_launch_program (m_config.m_dict_admin_command);
2019 
2020     return true;
2021 }
2022 
2023 #if 0
2024 void
2025 AnthyInstance::action_regist_word (void)
2026 {
2027 }
2028 #endif
2029 
2030 TypingMethod
get_typing_method(void)2031 AnthyInstance::get_typing_method (void)
2032 {
2033     return m_preedit.get_typing_method ();
2034 }
2035 
2036 InputMode
get_input_mode(void)2037 AnthyInstance::get_input_mode (void)
2038 {
2039     return m_preedit.get_input_mode ();
2040 }
2041 
2042 bool
is_single_segment(void)2043 AnthyInstance::is_single_segment (void)
2044 {
2045     if (m_config.m_conversion_mode == FCITX_ANTHY_CONVERSION_SINGLE_SEGMENT ||
2046         m_config.m_conversion_mode == FCITX_ANTHY_CONVERSION_SINGLE_SEGMENT_IMMEDIATE)
2047         return true;
2048     else
2049         return false;
2050 }
2051 
2052 bool
is_realtime_conversion(void)2053 AnthyInstance::is_realtime_conversion (void)
2054 {
2055     if (m_config.m_conversion_mode == FCITX_ANTHY_CONVERSION_MULTI_SEGMENT_IMMEDIATE ||
2056         m_config.m_conversion_mode == FCITX_ANTHY_CONVERSION_SINGLE_SEGMENT_IMMEDIATE)
2057         return true;
2058     else
2059         return false;
2060 }
2061 
2062 int
get_pseudo_ascii_mode(void)2063 AnthyInstance::get_pseudo_ascii_mode (void)
2064 {
2065     int retval = 0;
2066     TypingMethod m = get_typing_method ();
2067 
2068     if (m == FCITX_ANTHY_TYPING_METHOD_ROMAJI) {
2069         if (m_config.m_romaji_pseudo_ascii_mode)
2070             retval |= FCITX_ANTHY_PSEUDO_ASCII_TRIGGERED_CAPITALIZED;
2071     }
2072 
2073     return retval;
2074 }
2075 
commit_string(std::string str)2076 void AnthyInstance::commit_string(std::string str)
2077 {
2078     FcitxInputContext* ic = FcitxInstanceGetCurrentIC(m_owner);
2079     FcitxInstanceCommitString(m_owner, ic, str.c_str());
2080 }
2081 
2082 #define APPEND_ACTION(key, func)                                               \
2083 {                                                                              \
2084     FcitxHotkey* hk = NULL;                                                    \
2085     std::string name = #key;                                                   \
2086     FcitxHotkeyFree(m_config.m_key_profile.m_hk_##key);                        \
2087     if (loaded) {                                                              \
2088         std::string str = (ACTION_CONFIG_##key##_KEY);                         \
2089         std::string keystr;                                                    \
2090         style.get_string (keystr, "KeyBindings", str);                         \
2091         FcitxHotkeySetKey(keystr.c_str(), m_config.m_key_profile.m_hk_##key);  \
2092         hk = m_config.m_key_profile.m_hk_##key;                                \
2093     } else                                                                     \
2094         hk = m_config.m_key_default.m_hk_##key;                                \
2095     PMF f;                                                                     \
2096     f = &AnthyInstance::func;                                                  \
2097     m_actions[name] = Action (name, hk, f);                                    \
2098 }
2099 
2100 CONFIG_DESC_DEFINE(GetFcitxAnthyConfigDesc, "fcitx-anthy.desc")
2101 
CONFIG_BINDING_BEGIN(FcitxAnthyConfig)2102 CONFIG_BINDING_BEGIN(FcitxAnthyConfig)
2103 CONFIG_BINDING_REGISTER("General", "CandidateLayout", m_candidate_layout)
2104 CONFIG_BINDING_REGISTER("General", "InputMode", m_input_mode)
2105 CONFIG_BINDING_REGISTER("General", "TypingMethod", m_typing_method)
2106 CONFIG_BINDING_REGISTER("General", "ConversionMode", m_conversion_mode)
2107 CONFIG_BINDING_REGISTER("General", "PeriodStyle", m_period_comma_style)
2108 CONFIG_BINDING_REGISTER("General", "SymbolStyle", m_symbol_style)
2109 CONFIG_BINDING_REGISTER("General", "PageSize", m_page_size)
2110 CONFIG_BINDING_REGISTER("General", "LearnOnManualCommit", m_learn_on_manual_commit)
2111 CONFIG_BINDING_REGISTER("General", "LearnOnAutoCommit", m_learn_on_auto_commit)
2112 CONFIG_BINDING_REGISTER("General", "AllowSplit", m_romaji_allow_split)
2113 CONFIG_BINDING_REGISTER("General", "UseDirectKeyOnPredict", m_use_direct_key_on_predict)
2114 CONFIG_BINDING_REGISTER("General", "NTriggersToShowCandWin", m_n_triggers_to_show_cand_win)
2115 CONFIG_BINDING_REGISTER("General", "ShowCandidatesLabel", m_show_candidates_label)
2116 CONFIG_BINDING_REGISTER("General", "ShowInputMode", m_show_input_mode_on_focus)
2117 
2118 CONFIG_BINDING_REGISTER("Interface", "ShowInputMode", m_show_input_mode_label)
2119 CONFIG_BINDING_REGISTER("Interface", "ShowTypingMethod", m_show_typing_method_label)
2120 CONFIG_BINDING_REGISTER("Interface", "ShowConversionMode", m_show_conv_mode_label)
2121 CONFIG_BINDING_REGISTER("Interface", "ShowPeriodStyle", m_show_period_style_label)
2122 CONFIG_BINDING_REGISTER("Interface", "ShowSymbolStyle", m_show_symbol_style_label)
2123 
2124 CONFIG_BINDING_REGISTER("KeyProfile", "KeyBindingProfile", m_key_profile_enum)
2125 CONFIG_BINDING_REGISTER("KeyProfile", "RomajiTable", m_romaji_table_enum)
2126 CONFIG_BINDING_REGISTER("KeyProfile", "KanaTable", m_kana_table_enum)
2127 CONFIG_BINDING_REGISTER("KeyProfile", "NicolaTable", m_nicola_table_enum)
2128 CONFIG_BINDING_REGISTER("KeyProfile", "CustomKeyBindingProfile", m_key_theme_file)
2129 CONFIG_BINDING_REGISTER("KeyProfile", "CustomRomajiTable", m_romaji_fundamental_table)
2130 CONFIG_BINDING_REGISTER("KeyProfile", "CustomKanaTable", m_kana_fundamental_table)
2131 CONFIG_BINDING_REGISTER("KeyProfile", "CustomNicolaTable", m_nicola_fundamental_table)
2132 
2133 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CIRCLE_INPUT_MODE_KEY, m_key_default.m_hk_CIRCLE_INPUT_MODE)
2134 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CIRCLE_KANA_MODE_KEY, m_key_default.m_hk_CIRCLE_KANA_MODE)
2135 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CIRCLE_LATIN_HIRAGANA_MODE_KEY, m_key_default.m_hk_CIRCLE_LATIN_HIRAGANA_MODE)
2136 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CIRCLE_TYPING_METHOD_KEY, m_key_default.m_hk_CIRCLE_TYPING_METHOD)
2137 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_LATIN_MODE_KEY, m_key_default.m_hk_LATIN_MODE)
2138 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_WIDE_LATIN_MODE_KEY, m_key_default.m_hk_WIDE_LATIN_MODE)
2139 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_HIRAGANA_MODE_KEY, m_key_default.m_hk_HIRAGANA_MODE)
2140 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_KATAKANA_MODE_KEY, m_key_default.m_hk_KATAKANA_MODE)
2141 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_HALF_KATAKANA_MODE_KEY, m_key_default.m_hk_HALF_KATAKANA_MODE)
2142 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CANCEL_PSEUDO_ASCII_MODE_KEY, m_key_default.m_hk_CANCEL_PSEUDO_ASCII_MODE)
2143 
2144 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_INSERT_SPACE_KEY, m_key_default.m_hk_INSERT_SPACE)
2145 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_INSERT_ALT_SPACE_KEY, m_key_default.m_hk_INSERT_ALT_SPACE)
2146 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_INSERT_HALF_SPACE_KEY, m_key_default.m_hk_INSERT_HALF_SPACE)
2147 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_INSERT_WIDE_SPACE_KEY, m_key_default.m_hk_INSERT_WIDE_SPACE)
2148 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_BACKSPACE_KEY, m_key_default.m_hk_BACKSPACE)
2149 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_DELETE_KEY, m_key_default.m_hk_DELETE)
2150 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_COMMIT_KEY, m_key_default.m_hk_COMMIT)
2151 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_COMMIT_REVERSE_LEARN_KEY, m_key_default.m_hk_COMMIT_REVERSE_LEARN)
2152 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CONVERT_KEY, m_key_default.m_hk_CONVERT)
2153 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_PREDICT_KEY, m_key_default.m_hk_PREDICT)
2154 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CANCEL_KEY, m_key_default.m_hk_CANCEL)
2155 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CANCEL_ALL_KEY, m_key_default.m_hk_CANCEL_ALL)
2156 
2157 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_MOVE_CARET_FIRST_KEY, m_key_default.m_hk_MOVE_CARET_FIRST)
2158 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_MOVE_CARET_LAST_KEY, m_key_default.m_hk_MOVE_CARET_LAST)
2159 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_MOVE_CARET_FORWARD_KEY, m_key_default.m_hk_MOVE_CARET_FORWARD)
2160 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_MOVE_CARET_BACKWARD_KEY, m_key_default.m_hk_MOVE_CARET_BACKWARD)
2161 
2162 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_SELECT_FIRST_SEGMENT_KEY, m_key_default.m_hk_SELECT_FIRST_SEGMENT)
2163 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_SELECT_LAST_SEGMENT_KEY, m_key_default.m_hk_SELECT_LAST_SEGMENT)
2164 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_SELECT_NEXT_SEGMENT_KEY, m_key_default.m_hk_SELECT_NEXT_SEGMENT)
2165 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_SELECT_PREV_SEGMENT_KEY, m_key_default.m_hk_SELECT_PREV_SEGMENT)
2166 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_SHRINK_SEGMENT_KEY, m_key_default.m_hk_SHRINK_SEGMENT)
2167 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_EXPAND_SEGMENT_KEY, m_key_default.m_hk_EXPAND_SEGMENT)
2168 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_COMMIT_FIRST_SEGMENT_KEY, m_key_default.m_hk_COMMIT_FIRST_SEGMENT)
2169 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_COMMIT_SELECTED_SEGMENT_KEY, m_key_default.m_hk_COMMIT_SELECTED_SEGMENT)
2170 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_COMMIT_FIRST_SEGMENT_REVERSE_LEARN_KEY, m_key_default.m_hk_COMMIT_FIRST_SEGMENT_REVERSE_LEARN)
2171 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_COMMIT_SELECTED_SEGMENT_REVERSE_LEARN_KEY, m_key_default.m_hk_COMMIT_SELECTED_SEGMENT_REVERSE_LEARN)
2172 
2173 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_SELECT_FIRST_CANDIDATE_KEY, m_key_default.m_hk_SELECT_FIRST_CANDIDATE)
2174 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_SELECT_LAST_CANDIDATE_KEY, m_key_default.m_hk_SELECT_LAST_CANDIDATE)
2175 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_SELECT_NEXT_CANDIDATE_KEY, m_key_default.m_hk_SELECT_NEXT_CANDIDATE)
2176 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_SELECT_PREV_CANDIDATE_KEY, m_key_default.m_hk_SELECT_PREV_CANDIDATE)
2177 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_SELECT_NEXT_CANDIDATE_ALTER_KEY, m_key_default.m_hk_SELECT_NEXT_CANDIDATE_ALTER)
2178 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_SELECT_PREV_CANDIDATE_ALTER_KEY, m_key_default.m_hk_SELECT_PREV_CANDIDATE_ALTER)
2179 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CANDIDATES_PAGE_UP_KEY, m_key_default.m_hk_CANDIDATES_PAGE_UP)
2180 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CANDIDATES_PAGE_DOWN_KEY, m_key_default.m_hk_CANDIDATES_PAGE_DOWN)
2181 
2182 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CONV_CHAR_TYPE_FORWARD_KEY, m_key_default.m_hk_CONV_CHAR_TYPE_FORWARD)
2183 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CONV_CHAR_TYPE_BACKWARD_KEY, m_key_default.m_hk_CONV_CHAR_TYPE_BACKWARD)
2184 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CONV_TO_HIRAGANA_KEY, m_key_default.m_hk_CONV_TO_HIRAGANA)
2185 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CONV_TO_KATAKANA_KEY, m_key_default.m_hk_CONV_TO_KATAKANA)
2186 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CONV_TO_HALF_KEY, m_key_default.m_hk_CONV_TO_HALF)
2187 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CONV_TO_HALF_KATAKANA_KEY, m_key_default.m_hk_CONV_TO_HALF_KATAKANA)
2188 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CONV_TO_WIDE_LATIN_KEY, m_key_default.m_hk_CONV_TO_WIDE_LATIN)
2189 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_CONV_TO_LATIN_KEY, m_key_default.m_hk_CONV_TO_LATIN)
2190 
2191 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_RECONVERT_KEY, m_key_default.m_hk_RECONVERT)
2192 
2193 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_DICT_ADMIN_KEY, m_key_default.m_hk_DICT_ADMIN)
2194 CONFIG_BINDING_REGISTER("Key", ACTION_CONFIG_ADD_WORD_KEY, m_key_default.m_hk_ADD_WORD)
2195 CONFIG_BINDING_REGISTER("Key", "LeftThumbKey", m_left_thumb_keys)
2196 CONFIG_BINDING_REGISTER("Key", "RightThumbKey", m_right_thumb_keys)
2197 CONFIG_BINDING_REGISTER("Key", "KanaLayoutRoKey", m_kana_layout_ro_key)
2198 CONFIG_BINDING_REGISTER("Key", "NicolaTime", m_nicola_time)
2199 
2200 CONFIG_BINDING_REGISTER("Command", "AddWord", m_add_word_command)
2201 CONFIG_BINDING_REGISTER("Command", "DictAdmin", m_dict_admin_command)
2202 CONFIG_BINDING_END()
2203 
2204 std::string AnthyInstance::get_key_profile()
2205 {
2206     const char* key_profile[] = {
2207         "",
2208         "atok.sty",
2209         "canna.sty",
2210         "msime.sty",
2211         "vje-delta.sty",
2212         "wnn.sty",
2213         m_config.m_key_theme_file
2214     };
2215 
2216     if (m_config.m_key_profile_enum >= ARRAY_LEN(key_profile))
2217         m_config.m_key_profile_enum = 0;
2218 
2219     return key_profile[m_config.m_key_profile_enum] ? key_profile[m_config.m_key_profile_enum] : "" ;
2220 }
2221 
2222 
get_romaji_table()2223 std::string AnthyInstance::get_romaji_table()
2224 {
2225     const char* key_profile[] = {
2226         "",
2227         "atok.sty",
2228         "azik.sty",
2229         "canna.sty",
2230         "msime.sty",
2231         "vje-delta.sty",
2232         "wnn.sty",
2233         m_config.m_romaji_fundamental_table
2234     };
2235 
2236     if (m_config.m_romaji_table_enum >= ARRAY_LEN(key_profile))
2237         m_config.m_romaji_table_enum = 0;
2238 
2239     return key_profile[m_config.m_romaji_table_enum];
2240 }
2241 
2242 
get_kana_table()2243 std::string AnthyInstance::get_kana_table()
2244 {
2245     const char* key_profile[] = {
2246         "",
2247         "101kana.sty",
2248         "tsuki-2-203-101.sty",
2249         "tsuki-2-203-106.sty",
2250         "qkana.sty",
2251         m_config.m_kana_fundamental_table
2252     };
2253 
2254     if (m_config.m_kana_table_enum >= ARRAY_LEN(key_profile))
2255         m_config.m_kana_table_enum = 0;
2256 
2257     return key_profile[m_config.m_kana_table_enum];
2258 }
2259 
2260 
get_nicola_table()2261 std::string AnthyInstance::get_nicola_table()
2262 {
2263     const char* key_profile[] = {
2264         "",
2265         "nicola-a.sty",
2266         "nicola-f.sty",
2267         "nicola-j.sty",
2268         "oasys100j.sty"
2269         "tron-dvorak.sty",
2270         "tron-qwerty-jp.sty",
2271         m_config.m_nicola_fundamental_table
2272     };
2273 
2274     if (m_config.m_nicola_table_enum >= ARRAY_LEN(key_profile))
2275         m_config.m_nicola_table_enum = 0;
2276 
2277     return key_profile[m_config.m_nicola_table_enum];
2278 }
2279 
load_config()2280 bool AnthyInstance::load_config()
2281 {
2282     FcitxConfigFileDesc *configDesc = GetFcitxAnthyConfigDesc();
2283     if (!configDesc)
2284         return false;
2285 
2286     FILE *fp = FcitxXDGGetFileUserWithPrefix("conf", "fcitx-anthy.config", "r", NULL);
2287 
2288     if (!fp) {
2289         if (errno == ENOENT)
2290             save_config();
2291     }
2292     FcitxConfigFile *cfile = FcitxConfigParseConfigFileFp(fp, configDesc);
2293 
2294     FcitxAnthyConfigConfigBind(&m_config, cfile, configDesc);
2295     FcitxConfigBindSync(&m_config.gconfig);
2296 
2297     if (fp)
2298         fclose(fp);
2299 
2300     configure();
2301     return true;
2302 }
2303 
save_config()2304 void AnthyInstance::save_config()
2305 {
2306     FcitxConfigFileDesc *configDesc = GetFcitxAnthyConfigDesc();
2307     FILE *fp = FcitxXDGGetFileUserWithPrefix("conf", "fcitx-anthy.config", "w", NULL);
2308     FcitxConfigSaveConfigFileFp(fp, &m_config.gconfig, configDesc);
2309     if (fp)
2310         fclose(fp);
2311 }
2312 
get_file_name(const std::string & name)2313 char* AnthyInstance::get_file_name(const std::string& name)
2314 {
2315     char* retFile = NULL;
2316     FILE* fp = FcitxXDGGetFileWithPrefix("anthy", name.c_str(), "r", &retFile);
2317     if (fp) {
2318         fclose(fp);
2319     }
2320     return retFile;
2321 }
2322 
configure()2323 void AnthyInstance::configure()
2324 {
2325     StyleFile style;
2326     std::string file;
2327     bool loaded = false;
2328 
2329     // load key bindings
2330     char* filename = get_file_name(get_key_profile());
2331     if (filename)
2332         loaded = style.load (filename);
2333 
2334     fcitx_utils_free(filename);
2335 
2336     // clear old actions
2337     m_actions.clear ();
2338     // convert key
2339     APPEND_ACTION (CONVERT,                 action_convert);
2340     APPEND_ACTION (PREDICT,                 action_predict);
2341 
2342     // candidates keys
2343     APPEND_ACTION (CANDIDATES_PAGE_UP,      action_candidates_page_up);
2344     APPEND_ACTION (CANDIDATES_PAGE_DOWN,    action_candidates_page_down);
2345     APPEND_ACTION (SELECT_FIRST_CANDIDATE,  action_select_first_candidate);
2346     APPEND_ACTION (SELECT_LAST_CANDIDATE,   action_select_last_candidate);
2347     APPEND_ACTION (SELECT_NEXT_CANDIDATE,   action_select_next_candidate);
2348     APPEND_ACTION (SELECT_PREV_CANDIDATE,   action_select_prev_candidate);
2349     APPEND_ACTION (SELECT_NEXT_CANDIDATE_ALTER,   action_select_next_candidate);
2350     APPEND_ACTION (SELECT_PREV_CANDIDATE_ALTER,   action_select_prev_candidate);
2351 
2352     // segment keys
2353     APPEND_ACTION (SELECT_FIRST_SEGMENT,    action_select_first_segment);
2354     APPEND_ACTION (SELECT_LAST_SEGMENT,     action_select_last_segment);
2355     APPEND_ACTION (SELECT_NEXT_SEGMENT,     action_select_next_segment);
2356     APPEND_ACTION (SELECT_PREV_SEGMENT,     action_select_prev_segment);
2357     APPEND_ACTION (SHRINK_SEGMENT,          action_shrink_segment);
2358     APPEND_ACTION (EXPAND_SEGMENT,          action_expand_segment);
2359     APPEND_ACTION (COMMIT_FIRST_SEGMENT,    action_commit_first_segment);
2360     APPEND_ACTION (COMMIT_SELECTED_SEGMENT, action_commit_selected_segment);
2361     APPEND_ACTION (COMMIT_FIRST_SEGMENT_REVERSE_LEARN,
2362                    action_commit_first_segment_reverse_preference);
2363     APPEND_ACTION (COMMIT_SELECTED_SEGMENT_REVERSE_LEARN,
2364                    action_commit_selected_segment_reverse_preference);
2365 
2366     // direct convert keys
2367     APPEND_ACTION (CONV_CHAR_TYPE_FORWARD,  action_convert_char_type_forward);
2368     APPEND_ACTION (CONV_CHAR_TYPE_BACKWARD, action_convert_char_type_backward);
2369     APPEND_ACTION (CONV_TO_HIRAGANA,        action_convert_to_hiragana);
2370     APPEND_ACTION (CONV_TO_KATAKANA,        action_convert_to_katakana);
2371     APPEND_ACTION (CONV_TO_HALF,            action_convert_to_half);
2372     APPEND_ACTION (CONV_TO_HALF_KATAKANA,   action_convert_to_half_katakana);
2373     APPEND_ACTION (CONV_TO_LATIN,           action_convert_to_latin);
2374     APPEND_ACTION (CONV_TO_WIDE_LATIN,      action_convert_to_wide_latin);
2375 
2376     // pseudo ascii mode
2377     APPEND_ACTION (CANCEL_PSEUDO_ASCII_MODE,action_cancel_pseudo_ascii_mode);
2378 
2379     // caret keys
2380     APPEND_ACTION (MOVE_CARET_FIRST,        action_move_caret_first);
2381     APPEND_ACTION (MOVE_CARET_LAST,         action_move_caret_last);
2382     APPEND_ACTION (MOVE_CARET_FORWARD,      action_move_caret_forward);
2383     APPEND_ACTION (MOVE_CARET_BACKWARD,     action_move_caret_backward);
2384 
2385     // edit keys
2386     APPEND_ACTION (BACKSPACE,               action_back);
2387     APPEND_ACTION (DELETE,                  action_delete);
2388     APPEND_ACTION (COMMIT,                  action_commit_follow_preference);
2389     APPEND_ACTION (COMMIT_REVERSE_LEARN,    action_commit_reverse_preference);
2390     APPEND_ACTION (CANCEL,                  action_revert);
2391     APPEND_ACTION (CANCEL_ALL,              action_cancel_all);
2392     APPEND_ACTION (INSERT_SPACE,            action_insert_space);
2393     APPEND_ACTION (INSERT_ALT_SPACE,        action_insert_alternative_space);
2394     APPEND_ACTION (INSERT_HALF_SPACE,       action_insert_half_space);
2395     APPEND_ACTION (INSERT_WIDE_SPACE,       action_insert_wide_space);
2396 
2397     // mode keys
2398     APPEND_ACTION (CIRCLE_INPUT_MODE,       action_circle_input_mode);
2399     APPEND_ACTION (CIRCLE_KANA_MODE,        action_circle_kana_mode);
2400     APPEND_ACTION (CIRCLE_LATIN_HIRAGANA_MODE,action_circle_latin_hiragana_mode);
2401     APPEND_ACTION (CIRCLE_TYPING_METHOD,    action_circle_typing_method);
2402     APPEND_ACTION (LATIN_MODE,              action_latin_mode);
2403     APPEND_ACTION (WIDE_LATIN_MODE,         action_wide_latin_mode);
2404     APPEND_ACTION (HIRAGANA_MODE,           action_hiragana_mode);
2405     APPEND_ACTION (KATAKANA_MODE,           action_katakana_mode);
2406     APPEND_ACTION (HALF_KATAKANA_MODE,      action_half_katakana_mode);
2407 
2408     // dict keys
2409     APPEND_ACTION (DICT_ADMIN,              action_launch_dict_admin_tool);
2410     APPEND_ACTION (ADD_WORD,                action_add_word);
2411 
2412     // reconvert
2413     APPEND_ACTION (RECONVERT,               action_reconvert);
2414 
2415     // load custom romaji table
2416     if (m_config.m_custom_romaji_table) {
2417         delete m_config.m_custom_romaji_table;
2418         m_config.m_custom_romaji_table = NULL;
2419     }
2420     const char *section_romaji = "RomajiTable/FundamentalTable";
2421     filename = get_file_name(get_romaji_table());
2422     if (filename && style.load (filename)) {
2423         m_config.m_custom_romaji_table = style.get_key2kana_table (section_romaji);
2424     }
2425     fcitx_utils_free(filename);
2426 
2427     // load custom kana table
2428     if (m_config.m_custom_kana_table) {
2429         delete m_config.m_custom_kana_table;
2430         m_config.m_custom_kana_table = NULL;
2431     }
2432     const char *section_kana = "KanaTable/FundamentalTable";
2433     filename = get_file_name(get_kana_table());
2434     if (filename && style.load (filename)) {
2435         m_config.m_custom_kana_table = style.get_key2kana_table (section_kana);
2436     }
2437     fcitx_utils_free(filename);
2438 
2439     // load custom NICOLA table
2440     if (m_config.m_custom_nicola_table) {
2441         delete m_config.m_custom_nicola_table;
2442         m_config.m_custom_nicola_table = NULL;
2443     }
2444     const char *section_nicola = "NICOLATable/FundamentalTable";
2445     filename = get_file_name(get_nicola_table());
2446     if (filename && style.load (filename)) {
2447         m_config.m_custom_nicola_table = style.get_key2kana_table (section_nicola);
2448     }
2449     fcitx_utils_free(filename);
2450 
2451     // set romaji settings
2452     m_preedit.set_symbol_width (m_config.m_romaji_half_symbol);
2453     m_preedit.set_number_width (m_config.m_romaji_half_number);
2454 
2455     // set input mode
2456     m_preedit.set_input_mode (m_config.m_input_mode);
2457 
2458     // set typing method and pseudo ASCII mode
2459     m_preedit.set_typing_method (m_config.m_typing_method);
2460     m_preedit.set_pseudo_ascii_mode (get_pseudo_ascii_mode ());
2461 
2462     // set period style
2463     set_period_style(m_config.m_period_comma_style);
2464 
2465     // set symbol style
2466     set_symbol_style(m_config.m_symbol_style);
2467 
2468     // setup toolbar
2469     install_properties ();
2470 }
2471 
update_aux_string(const std::string & str)2472 void AnthyInstance::update_aux_string(const std::string& str)
2473 {
2474     FcitxMessages* aux;
2475     aux = m_aux_up;
2476     FcitxMessagesSetMessageCount(aux, 0);
2477     FcitxMessagesAddMessageAtLast(aux, MSG_TIPS, "%s", str.c_str());
2478     m_ui_update = true;
2479 }
2480 
reset_cursor(int cursor)2481 void AnthyInstance::reset_cursor(int cursor)
2482 {
2483     if (cursor >= 0)
2484         m_cursor_pos = cursor;
2485     else
2486         cursor = 0;
2487 }
2488 
auto_commit(FcitxIMCloseEventType type)2489 void AnthyInstance::auto_commit(FcitxIMCloseEventType type)
2490 {
2491     if (type == CET_LostFocus) {
2492         action_commit(m_config.m_learn_on_auto_commit, false);
2493     } else if (type == CET_ChangeByUser) {
2494         reset_im();
2495     } else if (type == CET_ChangeByInactivate) {
2496         FcitxGlobalConfig* config = FcitxInstanceGetGlobalConfig(m_owner);
2497         if (config->bSendTextWhenSwitchEng)
2498             action_commit(m_config.m_learn_on_manual_commit);
2499         else
2500             reset_im();
2501     }
2502 }
2503 
2504 /*
2505 vi:ts=4:nowrap:ai:expandtab
2506 */
2507