1 /** @file scim_m17n_imengine.cpp
2  */
3 
4 /*
5  * Smart Common Input Method
6  *
7  * Copyright (c) 2004 James Su <suzhe@tsinghua.org.cn>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  * $Id: scim_m17n_imengine.cpp,v 1.26 2007/01/11 00:44:33 suzhe Exp $
24  */
25 
26 #define Uses_SCIM_UTILITY
27 #define Uses_SCIM_IMENGINE
28 #define Uses_SCIM_LOOKUP_TABLE
29 #define Uses_SCIM_CONFIG_BASE
30 #define Uses_STL_MAP
31 
32 #ifdef HAVE_CONFIG_H
33   #include <config.h>
34 #endif
35 
36 #include <string.h>
37 #include <scim.h>
38 
39 #include "scim_m17n_imengine.h"
40 
41 #define scim_module_init m17n_LTX_scim_module_init
42 #define scim_module_exit m17n_LTX_scim_module_exit
43 #define scim_imengine_module_init m17n_LTX_scim_imengine_module_init
44 #define scim_imengine_module_create_factory m17n_LTX_scim_imengine_module_create_factory
45 
46 #define SCIM_PROP_STATUS                  "/IMEngine/M17N/Status"
47 
48 #ifndef SCIM_M17N_ICON_FILE
49     #define SCIM_M17N_ICON_FILE           (SCIM_ICONDIR "/scim-m17n.png")
50 #endif
51 
52 struct M17NInfo {
53     String        lang;
54     String        name;
55     String        uuid;
56 };
57 
58 static std::vector <M17NInfo>                     __m17n_input_methods;
59 static std::map <MInputContext *, M17NInstance *> __m17n_input_contexts;
60 
61 static CommonLookupTable                          __lookup_table;
62 
63 static MConverter   *__m17n_converter = 0;
64 
65 static M17NInstance * __find_instance (MInputContext *ic);
66 
67 static MSymbol __key_to_symbol (const KeyEvent &key);
68 
69 extern "C" {
scim_module_init(void)70     void scim_module_init (void)
71     {
72         __lookup_table.fix_page_size ();
73     }
74 
scim_module_exit(void)75     void scim_module_exit (void)
76     {
77         M17N_FINI();
78     }
79 
scim_imengine_module_init(const ConfigPointer & config)80     uint32 scim_imengine_module_init (const ConfigPointer &config)
81     {
82         SCIM_DEBUG_IMENGINE(1) << "Initialize M17N Engine.\n";
83 
84         MPlist *imlist, *elm;
85         MSymbol utf8;
86 
87         size_t i;
88         size_t count = 0;
89 
90         M17N_INIT();
91         utf8 = msymbol("utf8");
92 
93         __m17n_converter = mconv_buffer_converter(utf8, NULL, 0);
94 
95         if (!__m17n_converter) return 0;
96 
97         imlist = mdatabase_list(msymbol("input-method"), Mnil, Mnil, Mnil);
98 
99         for (elm = imlist; elm && mplist_key(elm) != Mnil; elm = mplist_next(elm)) {
100             MDatabase *mdb = (MDatabase *) mplist_value(elm);
101             MSymbol *tag = mdatabase_tag(mdb);
102             if (tag[1] != Mnil && tag[2] != Mnil) {
103                 const char *im_lang = msymbol_name (tag[1]);
104                 const char *im_name = msymbol_name (tag[2]);
105 
106                 if (im_lang && im_lang[0] && im_name && im_name[0]) {
107                     M17NInfo info;
108 
109                     SCIM_DEBUG_IMENGINE(1) << im_lang << "-" << im_name << "\n";
110 
111                     info.lang = String (im_lang);
112                     info.name = String (im_name);
113 
114                     __m17n_input_methods.push_back (info);
115 
116                     count++;
117                 }
118             }
119         }
120 
121         if (imlist) m17n_object_unref(imlist);
122 
123         // Set uuids.
124         for (i = 0; i < count; ++i)
125             __m17n_input_methods [i].uuid = String ("IMEngine-M17N-" +
126                                                     __m17n_input_methods [i].lang +
127                                                     String ("-") +
128                                                     __m17n_input_methods [i].name);
129 
130         return count;
131     }
132 
scim_imengine_module_create_factory(uint32 engine)133     IMEngineFactoryPointer scim_imengine_module_create_factory (uint32 engine)
134     {
135         if (engine >= __m17n_input_methods.size ()) return 0;
136 
137         M17NFactory *factory = 0;
138 
139         try {
140             factory = new M17NFactory (__m17n_input_methods [engine].lang,
141                                        __m17n_input_methods [engine].name,
142                                        __m17n_input_methods [engine].uuid);
143         } catch (...) {
144             delete factory;
145             factory = 0;
146         }
147 
148         return factory;
149     }
150 }
151 
M17NFactory(const String & lang,const String & name,const String & uuid)152 M17NFactory::M17NFactory (const String &lang,
153                           const String &name,
154                           const String &uuid)
155     : m_im (0), m_lang (lang), m_name (name), m_uuid (uuid)
156 {
157     SCIM_DEBUG_IMENGINE(1) << "Create M17N Factory :\n";
158     SCIM_DEBUG_IMENGINE(1) << "  Lang : " << lang << "\n";
159     SCIM_DEBUG_IMENGINE(1) << "  Name : " << name << "\n";
160     SCIM_DEBUG_IMENGINE(1) << "  UUID : " << uuid << "\n";
161 
162     if (lang.length () >= 2)
163         set_languages (lang);
164 }
165 
~M17NFactory()166 M17NFactory::~M17NFactory ()
167 {
168     if (m_im)
169         minput_close_im (m_im);
170 }
171 
172 bool
load_input_method()173 M17NFactory::load_input_method ()
174 {
175     SCIM_DEBUG_IMENGINE(1) << "load_input_method(" << m_lang << "," << m_name << ")\n";
176 
177     if (m_im) return true;
178 
179     m_im = minput_open_im(msymbol (m_lang.c_str ()), msymbol (m_name.c_str ()), NULL);
180 
181     if (m_im) {
182         m_im->driver.callback_list = M17NInstance::register_callbacks(m_im->driver.callback_list);
183         return true;
184     }
185 
186     return false;
187 }
188 
189 WideString
get_name() const190 M17NFactory::get_name () const
191 {
192     return utf8_mbstowcs (m_lang + String ("-") + m_name);
193 }
194 
195 WideString
get_authors() const196 M17NFactory::get_authors () const
197 {
198     return WideString ();
199 }
200 
201 WideString
get_credits() const202 M17NFactory::get_credits () const
203 {
204     return WideString ();
205 }
206 
207 WideString
get_help() const208 M17NFactory::get_help () const
209 {
210 #if M17N_VERSION >= 10300
211     MText *desc = minput_get_description (msymbol (m_lang.c_str ()), msymbol (m_name.c_str ()));
212     if (desc) {
213         int bufsize = mtext_len (desc) * 6;  // long enough
214         char *buf = new char [ bufsize ];
215         mconv_rebind_buffer(__m17n_converter, (unsigned char *) buf, bufsize);
216         mconv_encode(__m17n_converter, desc);
217         buf[__m17n_converter->nbytes] = 0;
218         m17n_object_unref(desc);
219 
220         return utf8_mbstowcs (buf);
221     }
222 #endif
223     return WideString ();
224 }
225 
226 String
get_uuid() const227 M17NFactory::get_uuid () const
228 {
229     return m_uuid;
230 }
231 
232 String
get_icon_file() const233 M17NFactory::get_icon_file () const
234 {
235 #if M17N_VERSION >= 10300
236     MPlist *l = minput_get_title_icon (msymbol (m_lang.c_str ()), msymbol (m_name.c_str ()));
237     if (l) {
238         char buf [256] = SCIM_M17N_ICON_FILE;
239         MPlist *n = mplist_next (l);
240 
241         if (n && mplist_key (n) == Mtext) {
242             MText *icon = (MText*) mplist_value (n);
243             mconv_rebind_buffer(__m17n_converter, (unsigned char *) buf, 256);
244             mconv_encode(__m17n_converter, icon);
245             buf[__m17n_converter->nbytes] = 0;
246         }
247 
248         m17n_object_unref (l);
249         return String (buf);
250     }
251 #endif
252     return String (SCIM_M17N_ICON_FILE);
253 }
254 
255 IMEngineInstancePointer
create_instance(const String & encoding,int id)256 M17NFactory::create_instance (const String &encoding, int id)
257 {
258     if (m_im || load_input_method ())
259         return new M17NInstance (this, encoding, id);
260 
261     return new DummyIMEngineInstance(dynamic_cast<DummyIMEngineFactory*>(this), encoding, id);
262 }
263 
M17NInstance(M17NFactory * factory,const String & encoding,int id)264 M17NInstance::M17NInstance (M17NFactory  *factory,
265                             const String &encoding,
266                             int           id)
267     : IMEngineInstanceBase (factory, encoding, id),
268       m_ic (0),
269       m_cap (0),
270       m_block_preedit_op (false),
271       m_pending_preedit_start (false),
272       m_pending_preedit_draw (false),
273       m_pending_preedit_done (false),
274       m_preedit_showed (false)
275 {
276     SCIM_DEBUG_IMENGINE(1) << "Create M17N Instance " << encoding << " " << id << "\n";
277 
278     if (factory->m_im) {
279         SCIM_DEBUG_IMENGINE(2) << " Create minput instance.\n";
280         m_ic = minput_create_ic (factory->m_im, NULL);
281     }
282 
283     if (m_ic)
284         __m17n_input_contexts [m_ic] = this;
285 }
286 
~M17NInstance()287 M17NInstance::~M17NInstance ()
288 {
289     SCIM_DEBUG_IMENGINE(1) << "Destroy M17N Instance " << get_id () << "\n";
290 
291     if (m_ic) {
292         __m17n_input_contexts.erase (m_ic);
293         minput_destroy_ic (m_ic);
294     }
295 }
296 
297 bool
process_key_event(const KeyEvent & key)298 M17NInstance::process_key_event (const KeyEvent& key)
299 {
300     if (!m_ic) return false;
301 
302     if (key.is_key_release ()) return true;
303 
304     MSymbol m17n_key = __key_to_symbol (key.map_to_layout (SCIM_KEYBOARD_Default));
305 
306     if (m17n_key == Mnil) return false;
307 
308     return m17n_process_key (m17n_key);
309 }
310 
311 bool
m17n_process_key(MSymbol key)312 M17NInstance::m17n_process_key (MSymbol key)
313 {
314     SCIM_DEBUG_IMENGINE(2) << "process_key_event. " << msymbol_name (key) << "\n";
315 
316     char buf [1024];
317     MText *produced;
318     int ret;
319 
320     m_block_preedit_op = true;
321 
322     ret = minput_filter(m_ic, key, NULL);
323 
324     m_block_preedit_op = false;
325 
326     if (ret) {
327         SCIM_DEBUG_IMENGINE(3) << "minput_filter returns 1\n";
328         do_preedit_op ();
329         return true;
330     }
331 
332     produced = mtext();
333 
334     ret = minput_lookup(m_ic, key, NULL, produced);
335 
336     if (ret) {
337         SCIM_DEBUG_IMENGINE(3) << "minput_lookup returns 1\n";
338     }
339 
340     mconv_rebind_buffer(__m17n_converter, (unsigned char *) buf, 1024);
341     mconv_encode(__m17n_converter, produced);
342     buf[__m17n_converter->nbytes] = 0;
343     m17n_object_unref(produced);
344 
345     if (buf[0]) {
346         SCIM_DEBUG_IMENGINE(2) << "commit_string: " << buf << "\n";
347         commit_string (utf8_mbstowcs (buf));
348     }
349 
350     do_preedit_op ();
351 
352     return ret == 0;
353 }
354 
355 void
do_preedit_op()356 M17NInstance::do_preedit_op ()
357 {
358     if (m_block_preedit_op)
359         return;
360 
361     if (m_pending_preedit_start) {
362         preedit_start_cb (m_ic, Minput_preedit_start);
363         m_pending_preedit_start = false;
364     }
365 
366     if (m_pending_preedit_draw) {
367         preedit_draw_cb (m_ic, Minput_preedit_draw);
368         m_pending_preedit_draw = false;
369     }
370 
371     if (m_pending_preedit_done) {
372         preedit_done_cb (m_ic, Minput_preedit_done);
373         m_pending_preedit_done = false;
374     }
375 }
376 
377 void
move_preedit_caret(unsigned int pos)378 M17NInstance::move_preedit_caret (unsigned int pos)
379 {
380 }
381 
382 void
select_candidate(unsigned int item)383 M17NInstance::select_candidate (unsigned int item)
384 {
385     if (item <= 10) {
386         char buf [4];
387         snprintf (buf, 4, "%d", (item + 1) % 10);
388         m17n_process_key (msymbol (buf));
389     }
390 }
391 
392 void
update_lookup_table_page_size(unsigned int page_size)393 M17NInstance::update_lookup_table_page_size (unsigned int page_size)
394 {
395 }
396 
397 void
lookup_table_page_up()398 M17NInstance::lookup_table_page_up ()
399 {
400     m17n_process_key (msymbol ("Up"));
401 }
402 
403 void
lookup_table_page_down()404 M17NInstance::lookup_table_page_down ()
405 {
406     m17n_process_key (msymbol ("Down"));
407 }
408 
409 void
reset()410 M17NInstance::reset ()
411 {
412     SCIM_DEBUG_IMENGINE(2) << "reset.\n";
413     minput_reset_ic(m_ic);
414 
415     hide_preedit_string ();
416     hide_aux_string ();
417     hide_lookup_table ();
418 
419     m_preedit_showed = false;
420     m_pending_preedit_start = false;
421     m_pending_preedit_draw = false;
422     m_pending_preedit_done = false;
423 }
424 
425 void
focus_in()426 M17NInstance::focus_in ()
427 {
428     SCIM_DEBUG_IMENGINE(2) << "focus_in.\n";
429 
430     PropertyList props;
431     Property     prop (String (SCIM_PROP_STATUS),
432                        String (""));
433 
434     prop.hide ();
435     props.push_back (prop);
436 
437     register_properties (props);
438 
439 #if M17N_VERSION >= 10300
440     m17n_process_key (Minput_focus_in);
441 #else
442     preedit_draw_cb (m_ic, Minput_preedit_draw);
443     candidates_draw_cb (m_ic, Minput_candidates_draw);
444 #endif
445 
446     //FIXME: Minput_focus_in can't trigger status_draw_cb, so call it here.
447     status_draw_cb (m_ic, Minput_status_draw);
448 }
449 
450 void
focus_out()451 M17NInstance::focus_out ()
452 {
453     SCIM_DEBUG_IMENGINE(2) << "focus_out.\n";
454 
455 #if M17N_VERSION >= 10300
456     m17n_process_key (Minput_focus_out);
457 #else
458     reset ();
459 #endif
460 }
461 
462 void
trigger_property(const String & property)463 M17NInstance::trigger_property (const String &property)
464 {
465 }
466 
467 void
update_client_capabilities(unsigned int cap)468 M17NInstance::update_client_capabilities (unsigned int cap)
469 {
470     m_cap = cap;
471 }
472 
473 static M17NInstance *
__find_instance(MInputContext * ic)474 __find_instance (MInputContext *ic)
475 {
476     std::map <MInputContext *, M17NInstance *>::iterator it =
477         __m17n_input_contexts.find (ic);
478 
479     if (it != __m17n_input_contexts.end ())
480         return it->second;
481 
482     return 0;
483 }
484 
485 
486 MPlist *
register_callbacks(MPlist * callback_list)487 M17NInstance::register_callbacks(MPlist *callback_list)
488 {
489     if(!callback_list)
490         callback_list = mplist();
491 
492     mplist_put(callback_list, Minput_preedit_start, (void*)preedit_start_cb);
493     mplist_put(callback_list, Minput_preedit_draw,  (void*)preedit_draw_cb);
494     mplist_put(callback_list, Minput_preedit_done,  (void*)preedit_done_cb);
495     mplist_put(callback_list, Minput_status_start,  (void*)status_start_cb);
496     mplist_put(callback_list, Minput_status_draw,   (void*)status_draw_cb);
497     mplist_put(callback_list, Minput_status_done,   (void*)status_done_cb);
498     mplist_put(callback_list, Minput_candidates_start, (void*)candidates_start_cb);
499     mplist_put(callback_list, Minput_candidates_draw,  (void*)candidates_draw_cb);
500     mplist_put(callback_list, Minput_candidates_done,  (void*)candidates_done_cb);
501 
502 #if M17N_VERSION >= 10300
503     mplist_put(callback_list, Minput_get_surrounding_text,  (void*)get_surrounding_text_cb);
504     mplist_put(callback_list, Minput_delete_surrounding_text,  (void*)delete_surrounding_text_cb);
505 #endif
506 
507     return callback_list;
508 }
509 
510 void
preedit_start_cb(MInputContext * ic,MSymbol command)511 M17NInstance::preedit_start_cb (MInputContext *ic, MSymbol command)
512 {
513     M17NInstance *this_ptr = __find_instance (ic);
514 
515     if (this_ptr && !this_ptr->m_preedit_showed) {
516         SCIM_DEBUG_IMENGINE(2) << "preedit_start_cb.\n";
517 
518         if (this_ptr->m_block_preedit_op) {
519             this_ptr->m_pending_preedit_start = true;
520             return;
521         }
522 
523         this_ptr->show_preedit_string ();
524         this_ptr->m_preedit_showed = true;
525     }
526 }
527 
528 void
preedit_draw_cb(MInputContext * ic,MSymbol command)529 M17NInstance::preedit_draw_cb  (MInputContext *ic, MSymbol command)
530 {
531     M17NInstance *this_ptr = __find_instance (ic);
532 
533     if (this_ptr && ic->preedit) {
534         SCIM_DEBUG_IMENGINE(2) << "preedit_draw_cb.\n";
535 
536         if (this_ptr->m_block_preedit_op) {
537             this_ptr->m_pending_preedit_draw = true;
538             return;
539         }
540 
541         char buf[1024];
542         mconv_rebind_buffer(__m17n_converter, (unsigned char *)buf, 1024);
543         mconv_encode(__m17n_converter, ic->preedit);
544         buf[__m17n_converter->nbytes] = 0;
545 
546         WideString wstr = utf8_mbstowcs (buf);
547         if (wstr.length ()) {
548             AttributeList attrs;
549 
550             if (ic->candidate_from < ic->candidate_to && ic->candidate_to <= wstr.length ())
551                 attrs.push_back (Attribute (ic->candidate_from,
552                                             ic->candidate_to - ic->candidate_from,
553                                             SCIM_ATTR_DECORATE,
554                                             SCIM_ATTR_DECORATE_REVERSE));
555 
556             if (!this_ptr->m_preedit_showed) {
557                 this_ptr->show_preedit_string ();
558                 this_ptr->m_preedit_showed = true;
559             }
560 
561             this_ptr->update_preedit_string (wstr, attrs);
562             this_ptr->update_preedit_caret (ic->cursor_pos);
563         } else {
564             this_ptr->hide_preedit_string ();
565             this_ptr->m_preedit_showed = false;
566         }
567     }
568 }
569 
570 void
preedit_done_cb(MInputContext * ic,MSymbol command)571 M17NInstance::preedit_done_cb  (MInputContext *ic, MSymbol command)
572 {
573     M17NInstance *this_ptr = __find_instance (ic);
574 
575     if (this_ptr && this_ptr->m_preedit_showed) {
576         SCIM_DEBUG_IMENGINE(2) << "preedit_done_cb.\n";
577 
578         if (this_ptr->m_block_preedit_op) {
579             this_ptr->m_pending_preedit_done = true;
580             return;
581         }
582 
583         this_ptr->hide_preedit_string ();
584         this_ptr->m_preedit_showed = false;
585     }
586 }
587 
588 void
status_start_cb(MInputContext * ic,MSymbol command)589 M17NInstance::status_start_cb (MInputContext *ic, MSymbol command)
590 {
591     M17NInstance *this_ptr = __find_instance (ic);
592 
593     if (this_ptr) {
594         SCIM_DEBUG_IMENGINE(2) << "status_start_cb.\n";
595 
596         Property prop (String (SCIM_PROP_STATUS), String (""));
597 
598         this_ptr->update_property (prop);
599     }
600 }
601 
602 void
status_draw_cb(MInputContext * ic,MSymbol command)603 M17NInstance::status_draw_cb (MInputContext *ic, MSymbol command)
604 {
605     M17NInstance *this_ptr = __find_instance (ic);
606 
607     if (this_ptr && ic->status) {
608         SCIM_DEBUG_IMENGINE(2) << "status_draw_cb.\n";
609 
610         char buf[1024];
611         mconv_rebind_buffer(__m17n_converter, (unsigned char *)buf, 1024);
612         mconv_encode(__m17n_converter, ic->status);
613         buf[__m17n_converter->nbytes] = 0;
614 
615         Property prop (String (SCIM_PROP_STATUS), String (buf));
616 
617         this_ptr->update_property (prop);
618     }
619 }
620 
621 void
status_done_cb(MInputContext * ic,MSymbol command)622 M17NInstance::status_done_cb (MInputContext *ic, MSymbol command)
623 {
624     M17NInstance *this_ptr = __find_instance (ic);
625 
626     if (this_ptr) {
627         SCIM_DEBUG_IMENGINE(2) << "status_done_cb.\n";
628 
629         Property prop (String (SCIM_PROP_STATUS), String (""));
630         prop.hide ();
631 
632         this_ptr->update_property (prop);
633     }
634 }
635 
636 void
candidates_start_cb(MInputContext * ic,MSymbol command)637 M17NInstance::candidates_start_cb (MInputContext *ic, MSymbol command)
638 {
639     M17NInstance *this_ptr = __find_instance (ic);
640 
641     if (this_ptr) {
642         SCIM_DEBUG_IMENGINE(2) << "candidates_start_cb.\n";
643         this_ptr->show_lookup_table ();
644     }
645 }
646 
647 void
candidates_draw_cb(MInputContext * ic,MSymbol command)648 M17NInstance::candidates_draw_cb (MInputContext *ic, MSymbol command)
649 {
650     M17NInstance *this_ptr = __find_instance (ic);
651 
652     if (this_ptr) {
653         __lookup_table.clear ();
654 
655         SCIM_DEBUG_IMENGINE(2) << "candidates_draw_cb.\n";
656         SCIM_DEBUG_IMENGINE(3) << "candidate_index = " << ic->candidate_index << "\n";
657         SCIM_DEBUG_IMENGINE(3) << "candidate_from  = " << ic->candidate_from << "\n";
658         SCIM_DEBUG_IMENGINE(3) << "candidate_to    = " << ic->candidate_to << "\n";
659         SCIM_DEBUG_IMENGINE(3) << "candidate_show  = " << ic->candidate_show << "\n";
660 
661         if (ic->candidate_list && ic->candidate_show) {
662             MPlist *group;
663             MText  *mt;
664             char buf [1024];
665             int i, len, cur, page;
666             bool page_up, page_down;
667             WideString wstr;
668 
669             i = 0;
670             page = 0;
671             group = ic->candidate_list;
672             while (1) {
673                 if (mplist_key (group) == Mtext)
674                     len = mtext_len ((MText *) mplist_value (group));
675                 else
676                     len = mplist_length ((MPlist*) mplist_value (group));
677 
678                 if (i + len > ic->candidate_index)
679                     break;
680                 i += len;
681                 group = mplist_next (group);
682 
683                 ++page;
684             }
685 
686             cur = ic->candidate_index - i;
687 
688             page_up = (page > 0);
689             page_down = ((page + 1) < mplist_length (ic->candidate_list));
690 
691             if (page_up)
692                 __lookup_table.append_candidate (0x3000);
693 
694             if (mplist_key (group) == Mtext) {
695                 mt = (MText *) mplist_value (group);
696                 mconv_rebind_buffer(__m17n_converter, (unsigned char *)buf, 1024);
697                 mconv_encode(__m17n_converter, mt);
698                 buf[__m17n_converter->nbytes] = 0;
699                 wstr = utf8_mbstowcs (buf);
700 
701                 for (i = 0; i < wstr.length (); ++i)
702                     __lookup_table.append_candidate (wstr [i]);
703 
704                 if (page_up) {
705                     __lookup_table.set_page_size (1);
706                     __lookup_table.page_down ();
707                 }
708 
709                 __lookup_table.set_page_size (wstr.length ());
710             } else {
711                 MPlist *pl;
712 
713                 len = 0;
714                 for (pl = (MPlist *) mplist_value (group); mplist_key (pl) != Mnil; pl = mplist_next (pl)) {
715                     mt = (MText *) mplist_value (pl);
716                     mconv_rebind_buffer(__m17n_converter, (unsigned char *)buf, 1024);
717                     mconv_encode(__m17n_converter, mt);
718                     buf[__m17n_converter->nbytes] = 0;
719                     wstr = utf8_mbstowcs (buf);
720 
721                     __lookup_table.append_candidate (wstr);
722                     ++ len;
723                 }
724 
725                 if (page_up) {
726                     __lookup_table.set_page_size (1);
727                     __lookup_table.page_down ();
728                 }
729 
730                 __lookup_table.set_page_size (len);
731             }
732 
733             if (page_down)
734                 __lookup_table.append_candidate (0x3000);
735 
736             __lookup_table.set_cursor_pos_in_current_page (cur);
737             __lookup_table.show_cursor ();
738 
739             this_ptr->update_lookup_table (__lookup_table);
740             this_ptr->show_lookup_table ();
741         } else {
742             this_ptr->hide_lookup_table ();
743         }
744     }
745 }
746 
747 void
candidates_done_cb(MInputContext * ic,MSymbol command)748 M17NInstance::candidates_done_cb (MInputContext *ic, MSymbol command)
749 {
750     M17NInstance *this_ptr = __find_instance (ic);
751 
752     if (this_ptr) {
753         SCIM_DEBUG_IMENGINE(2) << "candidates_done_cb.\n";
754         this_ptr->hide_lookup_table ();
755     }
756 }
757 
758 #if M17N_VERSION >= 10300
759 void
get_surrounding_text_cb(MInputContext * ic,MSymbol command)760 M17NInstance::get_surrounding_text_cb (MInputContext *ic, MSymbol command)
761 {
762     M17NInstance *this_ptr = __find_instance (ic);
763 
764     if (this_ptr && (this_ptr->m_cap & SCIM_CLIENT_CAP_SURROUNDING_TEXT)) {
765         SCIM_DEBUG_IMENGINE(2) << "get_surrounding_text_cb.\n";
766         if (ic->plist && mplist_key (ic->plist) == Minteger) {
767             int len = (int) ((size_t) mplist_value (ic->plist));
768             int cursor;
769             WideString wstr;
770             MText *txt = mtext ();
771             if (this_ptr->get_surrounding_text (wstr, cursor, (len < 0) ? (-len) : 0, (len > 0) ? len : 0)) {
772                 for (WideString::const_iterator i = wstr.begin (); i != wstr.end (); ++i)
773                     mtext_cat_char (txt, (int) *i);
774             }
775             mplist_set (ic->plist, Mtext, txt);
776             m17n_object_unref (txt);
777         }
778     }
779 }
780 
781 void
delete_surrounding_text_cb(MInputContext * ic,MSymbol command)782 M17NInstance::delete_surrounding_text_cb (MInputContext *ic, MSymbol command)
783 {
784     M17NInstance *this_ptr = __find_instance (ic);
785 
786     if (this_ptr) {
787         SCIM_DEBUG_IMENGINE(2) << "delete_surrounding_text_cb.\n";
788         if (ic->plist && mplist_key (ic->plist) == Minteger) {
789             int len = (int) ((size_t) mplist_value (ic->plist));
790             // FIXME: There is no way to inform m17n whether it's failed or not.
791             this_ptr->delete_surrounding_text ((len < 0) ? len : 0, (len > 0) ? len : (-len));
792         }
793     }
794 }
795 #endif
796 
797 static MSymbol
__key_to_symbol(const KeyEvent & key)798 __key_to_symbol (const KeyEvent &key)
799 {
800     int mask = 0;
801     String keysym;
802 
803     if (key.code >= SCIM_KEY_space && key.code <= SCIM_KEY_asciitilde) {
804         int c = key.code;
805 
806         if ((c == SCIM_KEY_space) &&
807             key.is_shift_down ())
808             mask |= SCIM_KEY_ShiftMask;
809 
810         if (key.is_control_down ()) {
811             if (c >= 'a' && c <= 'z')
812                 c += 'A' - 'a';
813             mask |= SCIM_KEY_ControlMask;
814         }
815 
816         keysym.push_back (c);
817     } else if (key.code >= SCIM_KEY_Shift_L && key.code <= SCIM_KEY_Hyper_R) {
818         return Mnil;
819     } else {
820         if (!scim_key_to_string (keysym, KeyEvent (key.code, 0)))
821             return Mnil;
822         if (key.is_control_down ())
823             mask |= SCIM_KEY_ControlMask;
824         if (key.is_shift_down ())
825             mask |= SCIM_KEY_ShiftMask;
826     }
827 
828     if (key.is_super_down ())
829         mask |= SCIM_KEY_SuperMask;
830 
831     if (key.is_hyper_down ())
832         mask |= SCIM_KEY_HyperMask;
833 
834     if (key.is_meta_down ())
835         mask |= SCIM_KEY_MetaMask;
836 
837     if (key.is_alt_down ())
838         mask |= SCIM_KEY_AltMask;
839 
840     if (!keysym.length ()) return Mnil;
841 
842     if (mask & SCIM_KEY_HyperMask)
843         keysym = String ("H-") + keysym;
844     if (mask & SCIM_KEY_SuperMask)
845         keysym = String ("s-") + keysym;
846     if (mask & SCIM_KEY_AltMask)
847         keysym = String ("A-") + keysym;
848     if (mask & SCIM_KEY_MetaMask)
849         keysym = String ("M-") + keysym;
850     if (mask & SCIM_KEY_ControlMask)
851         keysym = String ("C-") + keysym;
852     if (mask & SCIM_KEY_ShiftMask)
853         keysym = String ("S-") + keysym;
854 
855     return msymbol (keysym.c_str ());
856 }
857 
858 /*
859 vi:ts=4:nowrap:ai:expandtab
860 */
861