reset when press in keypad
[platform/core/uifw/ise-engine-unikey.git] / src / scim_unikey_imengine.cpp
1 /**
2    Scim-Unikey Input Method
3
4    Copyright (C) 2008-2009 Ubuntu-VN <http://www.ubuntu-vn.org>
5    Author: Le Quoc Tuan <mr.lequoctuan@gmail.com>
6    Home: http://scim-unikey.googlecode.com
7    License: GNU LESSER GENERAL PUBLIC LICENSE v2.1
8 */
9
10 #define Uses_SCIM_IMENGINE
11 #define Uses_SCIM_ICONV
12 #define Uses_SCIM_CONFIG_BASE
13 #define Uses_SCIM_CONFIG_PATH
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18
19 #include <libintl.h>
20 #define _(String) dgettext(PACKAGE_NAME,String)
21
22 #include <scim.h>
23 #include "scim_unikey_const.h"
24 #include "scim_unikey_utils.h"
25 #include "scim_unikey_imengine.h"
26
27 #include <string.h>
28 #include "unikey.h"
29 #include "vnconv.h"
30
31 #define scim_module_init                            unikey_LTX_scim_module_init
32 #define scim_module_exit                            unikey_LTX_scim_module_exit
33 #define scim_imengine_module_init                   unikey_LTX_scim_imengine_module_init
34 #define scim_imengine_module_create_factory         unikey_LTX_scim_imengine_module_create_factory
35
36 static unsigned char WordBreakSyms[] =
37 {
38     ',', ';', ':', '.', '\"', '\'', '!', '?', ' ',
39     '<', '>', '=', '+', '-', '*', '/', '\\',
40     '_', '~', '`', '@', '#', '$', '%', '^', '&', '(', ')', '{', '}', '[', ']',
41     '|'
42 };
43
44 static unsigned char WordAutoCommit[] =
45 {
46     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
47     'b', 'c', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n',
48     'p', 'q', 'r', 's', 't', 'v', 'x', 'z',
49     'B', 'C', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N',
50     'P', 'Q', 'R', 'S', 'T', 'V', 'X', 'Z'
51 };
52
53 const String          Unikey_IMNames[]    = {"Telex", "Vni", "STelex", "STelex2"};
54 const UkInputMethod   Unikey_IM[]         = {UkTelex, UkVni, UkSimpleTelex, UkSimpleTelex2};
55 const unsigned int    NUM_INPUTMETHOD     = sizeof(Unikey_IM)/sizeof(Unikey_IM[0]);
56
57 const String          Unikey_OCNames[]    = {"Unicode",
58                                              "TCVN3",
59                                              "VNI Win",
60                                              "VIQR",
61                                              "CString",
62                                              "NCR Decimal",
63                                              "NCR Hex"};
64
65 const unsigned int    Unikey_OC[]         = {CONV_CHARSET_XUTF8,
66                                              CONV_CHARSET_TCVN3,
67                                              CONV_CHARSET_VNIWIN,
68                                              CONV_CHARSET_VIQR,
69                                              CONV_CHARSET_UNI_CSTRING,
70                                              CONV_CHARSET_UNIREF,
71                                              CONV_CHARSET_UNIREF_HEX};
72 const unsigned int    NUM_OUTPUTCHARSET   = sizeof(Unikey_OC)/sizeof(Unikey_OC[0]);
73
74 ConfigPointer   __config;
75
76 using namespace scim;
77
78 extern "C"
79 {
80     void scim_module_init(void)
81     {
82         UnikeySetup();
83     }
84
85     void scim_module_exit(void)
86     {
87         UnikeyCleanup();
88     }
89
90     unsigned int scim_imengine_module_init(ConfigPointer &config)
91     {
92         if (config.null())
93             return 0;
94         __config = config;
95
96         return 1;
97     }
98
99     IMEngineFactoryPointer scim_imengine_module_create_factory(unsigned int index)
100     {
101         return new UnikeyFactory();
102     }
103 }
104
105 UnikeyFactory::UnikeyFactory()
106 {
107     set_languages("vi_VN");
108 }
109 UnikeyFactory::~UnikeyFactory()
110 {
111 }
112 WideString UnikeyFactory::get_name() const
113 {
114     return utf8_mbstowcs("Unikey");
115 }
116 String UnikeyFactory::get_uuid() const
117 {
118     return String(String("16ef5139-de02-494f-8d98-ddfcd60bbae1"));
119 }
120 WideString UnikeyFactory::get_authors() const
121 {
122     return utf8_mbstowcs("Le Quoc Tuan <mr.lequoctuan@gmail.com>");
123 }
124 WideString UnikeyFactory::get_credits() const
125 {
126     return utf8_mbstowcs(String("Scim-Unikey Input Method\n"
127                                 "Version: " SCIM_UNIKEY_VERSION "\n"
128                                 "Copyright © 2008-2009 Ubuntu-VN\n"
129                                 "http://www.ubuntu-vn.org\n\n"
130                                 "Thanks to Pham Kim Long for ukengine")
131         );
132 }
133 WideString UnikeyFactory::get_help() const
134 {
135     return utf8_mbstowcs(_("This IME work best when environment variable are\n"
136                            "- GTK_IM_MODULE=scim-bridge\n"
137                            "- QT_IM_MODULE=xim\n"
138                            " If you use preedit, you don't not need that\n\n"
139                            
140                            "Some time, in some application, you \"must\"\n"
141                            "enable Preedit to type best\n\n"
142
143                            "In some application, scim can't enable,\n"
144                            "this is not a bug of scim-unikey.\n"
145                            "You can try this in terminal: app_name | scim\n\n"
146
147                            "This IME come into being not intend to\n"
148                            "replace scim-m17n, just a choose, I recommend\n"
149                            "use this combine with scim-m17n\n\n"
150
151                            "For other support goto:\n"
152                            "  http://forum.ubuntu-vn.org/viewforum.php?f=85"));
153 }
154 String UnikeyFactory::get_icon_file() const
155 {
156     return String(SCIM_ICONDIR SCIM_UNIKEY_ICON_FILENAME);
157 }
158
159 IMEngineInstancePointer UnikeyFactory::create_instance(const String & encoding, int id)
160 {
161     return new UnikeyInstance(this, encoding, id);
162 }
163
164 UnikeyInstance::UnikeyInstance(UnikeyFactory *factory, const String &encoding, int id)
165     :IMEngineInstanceBase(factory, encoding, id),
166      m_auto_commit(false)
167 {
168     static bool t, o;  //temp variable
169
170     m_preeditstring.clear();
171
172     CreateDefaultUnikeyOptions(&m_ukopt);
173
174     /* Read config
175        if can't read config, set it to default value*/
176
177     t = __config->read(SCIM_IMENGINE_UNIKEY_INPUTMETHOD, &m_im);
178     if (!t) m_im = 0;
179
180     t = __config->read(SCIM_IMENGINE_UNIKEY_OUTPUTCHARSET, &m_oc);
181     if (!t) m_oc = 0;
182
183     t = __config->read(SCIM_IMENGINE_UNIKEY_PREEDIT, &m_preedit);
184     if (!t) m_preedit = SCIM_IMENGINE_UNIKEY_PREEDIT_DEF;
185
186     // read preedit switch key
187     m_preeditskey.clear();
188     String s;
189     int i = 0, j;
190     t = __config->read(SCIM_IMENGINE_UNIKEY_PREEDIT_SWITCH_KEY, &s);
191     if (!t) s=SCIM_IMENGINE_UNIKEY_PREEDIT_SWITCH_KEY_DEF;
192     if (s.length())
193     {
194         while (true)
195         {
196             j=s.find(',', i);
197             if (j!=String::npos)
198                 m_preeditskey.push_back(KeyEvent(s.substr(i, j-i)));
199             else
200                 break;
201             i = j+1;
202         }
203         m_preeditskey.push_back(KeyEvent(s.substr(i)));
204     } // end read preedit switch key
205
206     t = __config->read(SCIM_IMENGINE_UNIKEY_PROCESSWATWORDBEGIN, &o);
207     m_process_w_AtBeginWord = t?o:SCIM_IMENGINE_UNIKEY_PROCESSWATWORDBEGIN_DEF;
208
209 // Unikey Options
210     t = __config->read(SCIM_IMENGINE_UNIKEY_FREEMARKING, &o);
211     m_ukopt.freeMarking = t?o:SCIM_IMENGINE_UNIKEY_FREEMARKING_DEF;
212
213     t = __config->read(SCIM_IMENGINE_UNIKEY_MODERNSTYLE, &o);
214     m_ukopt.modernStyle = t?o:SCIM_IMENGINE_UNIKEY_MODERNSTYLE_DEF;
215
216     t = __config->read(SCIM_IMENGINE_UNIKEY_MACROENABLED, &o);
217     m_ukopt.macroEnabled = t?o:SCIM_IMENGINE_UNIKEY_MACROENABLED_DEF;
218
219     t = __config->read(SCIM_IMENGINE_UNIKEY_SPELLCHECKENABLED, &o);
220     m_ukopt.spellCheckEnabled = t?o:SCIM_IMENGINE_UNIKEY_SPELLCHECKENABLED_DEF;
221
222     t = __config->read(SCIM_IMENGINE_UNIKEY_AUTONONVNRESTORE, &o);
223     m_ukopt.autoNonVnRestore = t?o:SCIM_IMENGINE_UNIKEY_AUTONONVNRESTORE_DEF;
224
225     UnikeySetOptions(&m_ukopt);
226
227     if (m_ukopt.macroEnabled)
228     {
229         UnikeyLoadMacroTable(getMacroFile());
230     }
231
232     reset();
233 }
234
235 UnikeyInstance::~UnikeyInstance()
236 {
237 }
238
239 void UnikeyInstance::focus_in()
240 {
241     register_properties(CreatePropertyList());
242
243     UnikeySetInputMethod(Unikey_IM[m_im]);
244     UnikeySetOutputCharset(Unikey_OC[m_oc]);
245     UnikeySetOptions(&m_ukopt);
246 }
247
248 void UnikeyInstance::focus_out()
249 {
250     reset();
251 }
252
253 void UnikeyInstance::reset()
254 {
255     UnikeyResetBuf();
256
257     m_lastkey_with_shift = false;
258
259     if (m_preedit)
260     {
261         if (m_preeditstring.length())
262         {
263             commit_string(m_preeditstring);
264             hide_preedit_string();
265             m_preeditstring.clear();
266         }
267         m_auto_commit = false;
268     }
269 }
270
271 void UnikeyInstance::Unikey_send_backspace(int nBackspace)
272 {
273     static WideString ws;
274     static int n;
275
276     //  if surrounding text was provided, use it instead of send backspace
277     if (get_surrounding_text(ws, n, nBackspace, 0))
278     {
279         // for type in Auto Complete in OpenOffice
280         // Hope this not rise bugs in others application
281         // not use SCIM_KEY_NullKey, because GTK application crash when GTK_IM_MODULE=scim
282
283         forward_key_event(SCIM_KEY_VoidSymbol);
284
285         delete_surrounding_text(-ws.length(), ws.length());
286     }
287     else
288     {
289         for (int i=0; i < nBackspace; i++)
290             forward_key_event(SCIM_KEY_BackSpace);
291     }
292 }
293
294 void UnikeyInstance::Unikey_update_preedit_string(const WideString s, const bool visible)
295 {
296     AttributeList attlist;
297     Attribute att;
298
299     // underline preedit string
300     att = Attribute(0, s.length(), SCIM_ATTR_DECORATE, SCIM_ATTR_DECORATE_UNDERLINE);
301     attlist.push_back(att);
302
303     if (m_ukopt.spellCheckEnabled==1 && UnikeyLastWordIsNonVn())
304     {
305         // red preedit string
306         att = Attribute(0, s.length(), SCIM_ATTR_FOREGROUND, 0xff0000);
307         attlist.push_back(att);
308     }
309
310     update_preedit_string(s, attlist);
311     update_preedit_caret(s.length());
312
313     if (visible == true)
314     {
315         show_preedit_string();
316     }
317     else
318     {
319         hide_preedit_string();
320     }
321 }
322
323 bool UnikeyInstance::process_key_event(const KeyEvent& key)
324 {
325     bool tmp;
326
327     for (int i = 0; i<m_preeditskey.size(); i++)
328     {
329         if (key==m_preeditskey.at(i))
330         {
331             reset();
332             m_preedit=!m_preedit;
333             register_properties(CreatePropertyList());
334             return true;
335         }
336     }
337
338     tmp = m_preedit?Unikey_process_key_event_preedit(key)
339         :Unikey_process_key_event_direct(key);
340
341     if ((key.code >= SCIM_KEY_space && key.code <= SCIM_KEY_asciitilde)
342         || (key.code >= SCIM_KEY_KP_Multiply && key.code <= SCIM_KEY_KP_9))
343     {
344         m_lastkey_with_shift = key.is_shift_down();
345     }
346     else
347     {
348         m_lastkey_with_shift = false;
349     }
350
351     return tmp;
352 }
353
354 /** This method not use preedit string */
355 bool UnikeyInstance::Unikey_process_key_event_direct(const KeyEvent& key)
356 {
357     if (key.is_key_release())
358     {
359         return false;
360     }
361
362     if (key.is_control_down() || key.mask & SCIM_KEY_AltMask)
363     {
364         reset();
365         return false;
366     }
367
368     if (key.code >= SCIM_KEY_Shift_L && key.code <= SCIM_KEY_Hyper_R)
369     {
370         return false;
371     }
372
373     if (key.code == SCIM_KEY_BackSpace)
374     {
375         UnikeyBackspacePress();     // xu ly phim backspace
376         if (UnikeyBackspaces==0)    // neu ukengine bao khong can xoa ky tu nao,
377             return false;  // thi tra lai backspace cho chuong trinh khach
378         else
379         {
380             Unikey_send_backspace(UnikeyBackspaces);
381
382             // append key that need change tone pos after press backspace
383             if (UnikeyBufChars)
384             {
385                 if (Unikey_OC[m_oc] == CONV_CHARSET_XUTF8)
386                     commit_string(utf8_mbstowcs((const char*)UnikeyBuf, UnikeyBufChars));  // send the solved string to client
387                 else
388                 {
389                     static unsigned char buf[1024];
390                     int bufSize=sizeof(buf)/sizeof(buf[0]);
391
392                     latinToUtf(buf, UnikeyBuf, UnikeyBufChars, &bufSize);
393                     commit_string(utf8_mbstowcs((const char*)buf, sizeof(buf)/sizeof(buf[0]) - bufSize));
394                 }
395             }
396
397             return true;
398         }
399     }
400
401     if (key.code >= SCIM_KEY_space && key.code <= SCIM_KEY_asciitilde)
402     {
403         UnikeySetCapsState(key.mask & SCIM_KEY_ShiftMask,
404                            key.mask & SCIM_KEY_CapsLockMask);
405
406         // shift + space to restore keystroke
407         if (m_lastkey_with_shift == false
408             && key.mask & SCIM_KEY_ShiftMask
409             && key.code == SCIM_KEY_space
410             && !UnikeyAtWordBeginning())
411         {
412             UnikeyRestoreKeyStrokes();
413             if (UnikeyBackspaces == 0)
414             {
415                 UnikeyPutChar(key.code);
416             }
417         }
418
419         else if ((Unikey_IM[m_im] == UkTelex || Unikey_IM[m_im] == UkSimpleTelex2)
420                  && m_process_w_AtBeginWord == false
421                  && UnikeyAtWordBeginning()
422                  && (key.code == SCIM_KEY_w || key.code == SCIM_KEY_W))
423         {
424             UnikeyPutChar(key.code);
425         }
426
427         else
428         {
429             UnikeyFilter(key.code);
430         }
431
432         if (UnikeyBackspaces)
433         {
434             Unikey_send_backspace(UnikeyBackspaces);
435         }
436
437         if (UnikeyBufChars)
438         {
439             if (Unikey_OC[m_oc] == CONV_CHARSET_XUTF8)
440             {
441                 commit_string(utf8_mbstowcs((const char*)UnikeyBuf, UnikeyBufChars));  // send the solved string to client
442             }
443             else
444             {
445                 static unsigned char buf[1024];
446                 int bufSize=sizeof(buf)/sizeof(buf[0]);
447
448                 latinToUtf(buf, UnikeyBuf, UnikeyBufChars, &bufSize);
449                 commit_string(utf8_mbstowcs((const char*)buf, sizeof(buf)/sizeof(buf[0]) - bufSize));
450             }
451         }
452         else
453         {
454             forward_key_event(key);
455             return true;
456         }
457
458         return true;
459     }
460
461     // else
462     reset();
463     return false;
464 }
465
466 /** This method use preedit string */
467 bool UnikeyInstance::Unikey_process_key_event_preedit(const KeyEvent& key)
468 {
469     static int i;
470
471     if (key.code == SCIM_KEY_Tab
472         || key.mask & SCIM_KEY_ControlMask
473         || key.mask & SCIM_KEY_AltMask)
474     {
475         if (m_preeditstring.length())
476         {
477             commit_string(m_preeditstring);
478             hide_preedit_string();
479             m_preeditstring.clear();
480         }
481         reset();
482         return false;
483     }
484
485     if (key.is_key_release())
486         return false;
487
488     if (key.code == SCIM_KEY_Tab
489              || key.code == SCIM_KEY_Return
490              || key.code == SCIM_KEY_Delete
491              || key.code == SCIM_KEY_KP_Enter
492              || (key.code >= SCIM_KEY_Home && key.code <= SCIM_KEY_Insert)
493              || (key.code >= SCIM_KEY_KP_Home && key.code <= SCIM_KEY_KP_Delete))
494     {
495         if (m_preeditstring.length())
496         {
497             commit_string(m_preeditstring);
498             hide_preedit_string();
499             m_preeditstring.clear();
500         }
501
502         reset();
503         return false;
504     }
505
506     else if (key.code >= SCIM_KEY_Shift_L && key.code <= SCIM_KEY_Hyper_R)
507         return false;
508
509     else if (key.code == SCIM_KEY_BackSpace)
510     {
511         UnikeyBackspacePress();     // process Backspace
512
513         if (UnikeyBackspaces==0 || m_preeditstring.empty())    // if Unikey tell no Backspace
514         {
515             reset();
516             return false;  // Return Backspace to client
517         }
518         else
519         {
520             static int len;
521
522             len = m_preeditstring.length();
523             if (len <= UnikeyBackspaces)
524             {
525                 m_preeditstring.clear();
526                 hide_preedit_string();
527                 m_auto_commit = true;
528             }
529             else
530             {
531                 m_preeditstring.erase(len - UnikeyBackspaces, UnikeyBackspaces);
532                 Unikey_update_preedit_string(m_preeditstring, true);
533             }
534
535             // append key that need change tone pos after press backspace
536             if (UnikeyBufChars)
537             {
538                 if (Unikey_OC[m_oc] == CONV_CHARSET_XUTF8)
539                     m_preeditstring.append(utf8_mbstowcs((const char*)UnikeyBuf, UnikeyBufChars));
540                 else
541                 {
542                     static unsigned char buf[1024];
543                     int bufSize=sizeof(buf)/sizeof(buf[0]);
544
545                     latinToUtf(buf, UnikeyBuf, UnikeyBufChars, &bufSize);
546                     m_preeditstring.append(utf8_mbstowcs((const char*)buf, sizeof(buf)/sizeof(buf[0])-bufSize));
547                 }
548
549                 m_auto_commit = false;
550                 Unikey_update_preedit_string(m_preeditstring, true);
551             }
552         }
553
554         return true;
555     }
556
557     else if (key.code >= SCIM_KEY_space && key.code <= SCIM_KEY_asciitilde)
558     {
559         UnikeySetCapsState(key.mask & SCIM_KEY_ShiftMask, key.mask & SCIM_KEY_CapsLockMask);
560
561         // auto commit char: commit char that never change later in preedit string
562         // if macro enabled, then not auto commit. Because macro may change any word
563         if (m_ukopt.macroEnabled==0 && (UnikeyAtWordBeginning() || m_auto_commit))
564         {
565             for (i = 0; i < sizeof(WordAutoCommit); i++)
566                 if (key.code == WordAutoCommit[i])
567                 {
568                     UnikeyPutChar(key.code);
569                     m_auto_commit = true;
570                     forward_key_event(key); // forward keyevent instead of return false
571                     return true;
572                 }
573         } // end auto commit char
574
575         if ((Unikey_IM[m_im] == UkTelex || Unikey_IM[m_im] == UkSimpleTelex2)
576                  && m_process_w_AtBeginWord == false
577                  && UnikeyAtWordBeginning()
578                  && (key.code == SCIM_KEY_w || key.code == SCIM_KEY_W))
579         {
580             UnikeyPutChar(key.code);
581             if (m_ukopt.macroEnabled==0)
582             {
583                 forward_key_event(key);
584             }
585             else
586             {
587                 m_preeditstring.push_back(key.code);
588                 Unikey_update_preedit_string(m_preeditstring, true);
589             }
590
591             m_auto_commit = true;
592             
593             return true;
594         }
595
596         m_auto_commit = false;
597
598         if (m_lastkey_with_shift == false
599             && key.mask & SCIM_KEY_ShiftMask
600             && key.code == SCIM_KEY_space
601             && !UnikeyAtWordBeginning())
602         {
603             UnikeyRestoreKeyStrokes();
604         }
605
606         else
607         {
608             UnikeyFilter(key.code);
609         }
610
611         if (UnikeyBackspaces > 0)
612         {
613             static int len;
614
615             len = m_preeditstring.length();
616
617             if (len <= UnikeyBackspaces)
618                 m_preeditstring.clear();
619             else
620                 m_preeditstring.erase(len - UnikeyBackspaces, UnikeyBackspaces);
621         }
622
623         if (UnikeyBufChars > 0)
624         {
625             if (Unikey_OC[m_oc] == CONV_CHARSET_XUTF8)
626                 m_preeditstring.append(utf8_mbstowcs((const char*)UnikeyBuf, UnikeyBufChars));
627             else
628             {
629                 static unsigned char buf[1024];
630                 int bufSize=sizeof(buf)/sizeof(buf[0]);
631
632                 latinToUtf(buf, UnikeyBuf, UnikeyBufChars, &bufSize);
633                 m_preeditstring.append(utf8_mbstowcs((const char*)buf, sizeof(buf)/sizeof(buf[0])-bufSize));
634             }
635         }
636         else
637         {    
638             m_preeditstring.push_back(key.get_unicode_code());
639         }
640
641         if (m_preeditstring.length())
642         {
643             for (i=0; i < sizeof(WordBreakSyms); i++)
644             {
645                 if (WordBreakSyms[i] == m_preeditstring[m_preeditstring.length()-1] && key.code == WordBreakSyms[i])
646                 {
647                     commit_string(m_preeditstring);
648                     hide_preedit_string();
649                     m_preeditstring.clear();
650                     reset();
651                     return true;
652                 }
653             }
654         }
655
656         Unikey_update_preedit_string(m_preeditstring, true);
657         return true;
658     }
659
660     // else (key non process)
661     reset();
662     return false;
663 }
664
665 PropertyList UnikeyInstance::CreatePropertyList()
666 {
667     PropertyList props;
668     int i;
669
670     Property prop("", "", "", "");
671
672 // input method
673     prop.set_key("/Unikey/InputMethod");
674     prop.set_label(Unikey_IMNames[m_im]);
675     prop.set_icon("");
676     prop.set_tip(_("Choose input method"));
677     props.push_back(prop);
678
679     for (i=0; i<NUM_INPUTMETHOD; i++)
680     {
681         prop.set_key(String("/Unikey/InputMethod/") + Unikey_IMNames[i] + String(m_im==i?"-Checked":""));
682         prop.set_label(Unikey_IMNames[i]);
683         prop.set_icon(m_im==i?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
684         prop.set_tip("");
685         props.push_back(prop);
686     }
687
688 // output charset
689
690     prop.set_key("/Unikey/OutputCharset");
691     prop.set_label(Unikey_OCNames[m_oc]);
692     prop.set_icon("");
693     prop.set_tip(_("Choose output charset"));
694     props.push_back(prop);
695
696     for (i=0; i<NUM_OUTPUTCHARSET; i++)
697     {
698         prop.set_key(String("/Unikey/OutputCharset/") + Unikey_OCNames[i] + String(m_oc==i?"-Checked":""));
699         prop.set_label(Unikey_OCNames[i]);
700         prop.set_icon(m_oc==i?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
701         prop.set_tip("");
702         props.push_back(prop);
703     }
704
705 // unikey options
706     // menu
707     prop.set_key("/Unikey/Options");
708     prop.set_label(_("Options"));
709     prop.set_icon(SCIM_ICONDIR SCIM_UNIKEY_ICON_CONFIGURE);
710     prop.set_tip(_("Configure Unikey here"));
711     props.push_back(prop);
712
713     // spellcheck
714     prop.set_key(m_ukopt.spellCheckEnabled?
715                  "/Unikey/Options/SpellCheck/Disable":"/Unikey/Options/SpellCheck/Enable");
716     prop.set_label(_("Enable spell check"));
717     prop.set_icon(m_ukopt.spellCheckEnabled?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
718     prop.set_tip(_("If enable, you can decrease mistake when typing"));
719     props.push_back(prop);
720     
721     // auto restore keystroke
722     prop.set_key(m_ukopt.autoNonVnRestore?
723                  "/Unikey/Options/AutoRestoreKeys/Disable":"/Unikey/Options/AutoRestoreKeys/Enable");
724     prop.set_label(_("Auto restore keys with invalid words"));
725     prop.set_icon(m_ukopt.autoNonVnRestore?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
726     prop.set_tip(_("When typing a word not in Vietnamese,\n"
727                    "it will auto restore keystroke into original"));
728     props.push_back(prop);
729
730     // modern style
731     prop.set_key(m_ukopt.modernStyle?
732                  "/Unikey/Options/ModernStyle/Disable":"/Unikey/Options/ModernStyle/Enable");
733     prop.set_label(_("Use oà, uý (instead of òa, úy)"));
734     prop.set_icon(m_ukopt.modernStyle?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
735     prop.set_tip("");
736     props.push_back(prop);
737
738     // freeMarking
739     prop.set_key(m_ukopt.freeMarking?
740                  "/Unikey/Options/FreeMarking/Disable":"/Unikey/Options/FreeMarking/Enable");
741     prop.set_label(_("Allow type with more freedom"));
742     prop.set_icon(m_ukopt.freeMarking?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
743     prop.set_tip("");
744     props.push_back(prop);
745
746     // macro
747     prop.set_key(m_ukopt.macroEnabled?
748                  "/Unikey/Options/EnabledMacro/Disable":"/Unikey/Options/EnabledMacro/Enable");
749     prop.set_label(_("Enable Macro"));
750     prop.set_icon(m_ukopt.macroEnabled?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
751     prop.set_tip("");
752     props.push_back(prop);
753
754     // preedit
755     prop.set_key(m_preedit?"/Unikey/Options/Preedit/Disable":"/Unikey/Options/Preedit/Enable");
756     prop.set_label(_("Enable PreEdit"));
757     prop.set_icon(m_preedit?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
758     prop.set_tip(_("This option is best for most application\n"
759                    "But you may don't like it because it have an underline when typing"));
760     props.push_back(prop);
761
762     // process w at begin
763     prop.set_key(m_process_w_AtBeginWord?
764                  "/Unikey/Options/ProcessWAtBegin/Disable":"/Unikey/Options/ProcessWAtBegin/Enable");
765     prop.set_label(_("Process W at word begin"));
766     prop.set_icon(m_process_w_AtBeginWord?SCIM_ICONDIR SCIM_UNIKEY_ICON_CHECK:"");
767     prop.set_tip(_("If enable, type W at begin\n"
768                    "of word will change to Ư."));
769     props.push_back(prop);
770
771     return props;
772 }
773
774 void UnikeyInstance::trigger_property(const String &property)
775 {
776     bool change = false;
777     int i;
778
779 // input method
780     if (!property.compare(0, strlen("/Unikey/InputMethod/"), "/Unikey/InputMethod/"))
781     {
782         for (i=0; i<NUM_INPUTMETHOD; i++)
783             if (!property.compare(strlen("/Unikey/InputMethod/"),
784                                   property.length() - strlen("/Unikey/InputMethod/"),
785                                   Unikey_IMNames[i]))
786             {
787                 m_im = i;
788                 __config->write(SCIM_IMENGINE_UNIKEY_INPUTMETHOD, m_im);
789                 change = true;
790                 break;
791             }
792     }
793
794 // output charset
795     else if (!property.compare(0, strlen("/Unikey/OutputCharset/"), "/Unikey/OutputCharset/"))
796     {
797         for (i=0; i<NUM_OUTPUTCHARSET; i++)
798             if (!property.compare(strlen("/Unikey/OutputCharset/"),
799                                   property.length() - strlen("/Unikey/OutputCharset/"),
800                                   Unikey_OCNames[i]))
801             {
802                 m_oc = i;
803                 __config->write(SCIM_IMENGINE_UNIKEY_OUTPUTCHARSET, m_oc);
804                 change = true;
805                 break;
806             }
807     }
808
809 // spellcheck
810     else if (property == "/Unikey/Options/SpellCheck/Enable")
811     {
812         m_ukopt.spellCheckEnabled = true;
813         __config->write(SCIM_IMENGINE_UNIKEY_SPELLCHECKENABLED, true);
814         change = true;
815     }
816     else if (property == "/Unikey/Options/SpellCheck/Disable")
817     {
818         m_ukopt.spellCheckEnabled = false;
819         __config->write(SCIM_IMENGINE_UNIKEY_SPELLCHECKENABLED, false);
820         change = true;
821     }
822
823 // auto restore keystroke
824     else if (property == "/Unikey/Options/AutoRestoreKeys/Enable")
825     {
826         m_ukopt.autoNonVnRestore = true;
827         __config->write(SCIM_IMENGINE_UNIKEY_AUTONONVNRESTORE, true);
828         change = true;
829     }
830     else if (property == "/Unikey/Options/AutoRestoreKeys/Disable")
831     {
832         m_ukopt.autoNonVnRestore = false;
833         __config->write(SCIM_IMENGINE_UNIKEY_AUTONONVNRESTORE, false);
834         change = true;
835     }
836
837 // modern style
838     else if (property == "/Unikey/Options/ModernStyle/Enable")
839     {
840         m_ukopt.modernStyle = true;
841         __config->write(SCIM_IMENGINE_UNIKEY_MODERNSTYLE, true);
842         change = true;
843     }
844     else if (property == "/Unikey/Options/ModernStyle/Disable")
845     {
846         m_ukopt.modernStyle = false;
847         __config->write(SCIM_IMENGINE_UNIKEY_MODERNSTYLE, false);
848         change = true;
849     }
850
851 // free Marking
852     else if (property == "/Unikey/Options/FreeMarking/Enable")
853     {
854         m_ukopt.freeMarking = true;
855         __config->write(SCIM_IMENGINE_UNIKEY_FREEMARKING, true);
856         change = true;
857     }
858     else if (property == "/Unikey/Options/FreeMarking/Disable")
859     {
860         m_ukopt.freeMarking = false;
861         __config->write(SCIM_IMENGINE_UNIKEY_FREEMARKING, false);
862         change = true;
863     }
864 // macro 
865     else if (property == "/Unikey/Options/EnabledMacro/Enable")
866     {
867         m_ukopt.macroEnabled = true;
868         UnikeyLoadMacroTable(getMacroFile());
869         __config->write(SCIM_IMENGINE_UNIKEY_MACROENABLED, true);
870         change = true;
871     }
872     else if (property == "/Unikey/Options/EnabledMacro/Disable")
873     {
874         m_ukopt.macroEnabled = false;
875         __config->write(SCIM_IMENGINE_UNIKEY_MACROENABLED, false);
876         change = true;
877     }
878
879 // preedit
880     else if (property == "/Unikey/Options/Preedit/Enable")
881     {
882         m_preedit = true;
883         __config->write(SCIM_IMENGINE_UNIKEY_PREEDIT, true);
884         change = true;
885     }
886     else if (property == "/Unikey/Options/Preedit/Disable")
887     {
888         m_preedit = false;
889         __config->write(SCIM_IMENGINE_UNIKEY_PREEDIT, false);
890         change = true;
891     }
892
893 // process w at begin
894     else if (property == "/Unikey/Options/ProcessWAtBegin/Enable")
895     {
896         m_process_w_AtBeginWord = true;
897         __config->write(SCIM_IMENGINE_UNIKEY_PROCESSWATWORDBEGIN, true);
898         change = true;
899     }
900     else if (property == "/Unikey/Options/ProcessWAtBegin/Disable")
901     {
902         m_process_w_AtBeginWord = false;
903         __config->write(SCIM_IMENGINE_UNIKEY_PROCESSWATWORDBEGIN, false);
904         change = true;
905     }
906
907     if (change)
908     {
909         __config->flush();
910         focus_out();
911         focus_in();
912     }
913 }