*** empty log message ***
[m17n/m17n-lib.git] / src / input.c
1 /* input.c -- input method module.
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nInputMethod
25     @brief API for Input method.
26
27     An input method is an object to enable inputting various
28     characters.  An input method is identified by a pair of symbols,
29     LANGUAGE and NAME.  This pair decides a input method driver of the
30     input method.  An input method driver is a set of functions for
31     handling the input method.  There are two kinds of input methods;
32     internal one and foreign one.
33
34     <ul>
35     <li> Internal Input Method
36
37     An internal input method has non @c Mnil LANGUAGE, and the body is
38     defined in the m17n database by the tag <Minput_method, LANGUAGE,
39     NAME>.  For this kind of input methods, the m17n library uses two
40     predefined input method drivers, one for CUI use and the other for
41     GUI use.  Those driver utilize the input processing engine
42     provided by the m17n library itself.  The m17n database may
43     provides an input method that is not only for a specific language.
44     The database uses @c Mt as LANGUAGE of such an input method.
45
46     An internal input method accepts an input key which is a symbol
47     associated with an input event.  As there is no way for the @c
48     m17n @c library to know how input events are represented in an
49     application program, a application programmer have to convert an
50     input event to an input key by himself.  See the documentation of
51     the function minput_event_to_key () for the detail.
52
53     <li> Foreign Input Method
54
55     A foreign input method has @c Mnil LANGUAGE, and the body is
56     defined in an external resources (e.g. XIM of X Window System).
57     For this kind of input methods, the symbol NAME must have a
58     property of key @c Minput_driver, and the value must be a pointer
59     to an input method driver.  So, by preparing a proper driver, any
60     kind of input method can be treated in the framework of the @c
61     m17n @c library.
62
63     For convenience, the m17n-X library provides an input method
64     driver that enables the input style of OverTheSpot for XIM, and
65     stores @c Minput_driver property of the symbol @c Mxim with a
66     pointer to the driver.  See the documentation of m17n GUI API for
67     the detail.
68
69     </ul>
70
71     PROCESSING FLOW
72
73     The typical processing flow of handling an input method is: 
74
75      @li open an input method
76      @li create an input context for the input method
77      @li filter an input key
78      @li look up a produced text in the input context  */
79
80 /*=*/
81 /***ja
82     @addtogroup m17nInputMethod
83     @brief ÆþÎϥ᥽¥Ã¥ÉÍÑAPI.
84
85     ÆþÎϥ᥽¥Ã¥É¤Ï¿ÍͤÊʸ»ú¤òÆþÎϤ¹¤ë¤¿¤á¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë¡£ÆþÎÏ¥á
86     ¥½¥Ã¥É¤Ï¥·¥ó¥Ü¥ë LANGUAGE ¤È NAME ¤ÎÁȤˤè¤Ã¤Æ¼±Ê̤µ¤ì¡¢¤³¤ÎÁȤˤè¤Ã
87     ¤ÆÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤¬·è¤Þ¤ë¡£ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤È¤Ï¤¢¤ëÆþÎÏ¥á
88     ¥½¥Ã¥É¤ò°·¤¦¤¿¤á¤Î´Ø¿ô¤Î½¸¤Þ¤ê¤Ç¤¢¤ë¡£ ÆþÎϥ᥽¥Ã¥É¤Ë¤ÏÆâÉô¥á¥½¥Ã
89     ¥É¤È³°Éô¥á¥½¥Ã¥É¤ÎÆóÄ̤꤬¤¢¤ë¡£
90
91     <ul> 
92     <li> ÆâÉôÆþÎϥ᥽¥Ã¥É
93
94     ÆâÉôÆþÎϥ᥽¥Ã¥É¤Ï LANGUAGE ¤¬ @c Mnil °Ê³°¤Î¤â¤Î¤Ç¤¢¤ê¡¢ËÜÂΤÏ
95     m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë <Minput_method, LANGUAGE, NAME>¤È¤¤¤¦¥¿¥°ÉÕ¤­
96     ¤ÇÄêµÁ¤µ¤ì¤Æ¤¤¤ë¡£¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤ËÂФ·¤Æ¡¢m17n ¥é¥¤¥Ö¥é¥ê¤Ë
97     ¤ÏCUIÍѤÈGUIÍѤ½¤ì¤¾¤ì¤ÎÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤¬¤¢¤é¤«¤¸¤á½àÈ÷¤µ¤ì¤Æ
98     ¤¤¤ë¡£¤³¤ì¤é¤Î¥É¥é¥¤¥Ð¤Ïm17n¥é¥¤¥Ö¥é¥ê¼«¿È¤ÎÆþÎϽèÍý¥¨¥ó¥¸¥ó¤òÍøÍÑ
99     ¤¹¤ë¡£m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¤Ï¡¢ÆÃÄê¤Î¸À¸ìÀìÍѤǤʤ¤ÆþÎϥ᥽¥Ã¥É¤âÄê
100     µÁ¤¹¤ë¤³¤È¤¬¤Ç¤­¡¢¤½¤Î¤è¤¦¤ÊÆþÎϥ᥽¥Ã¥É¤Î LANGUAGE ¤Ï @c Mt ¤Ç¤¢
101     ¤ë¡£
102
103     ÆâÉôÆþÎϥ᥽¥Ã¥É¤Ï¡¢¥æ¡¼¥¶¤ÎÆþÎÏ¥¤¥Ù¥ó¥È¤ËÂбþ¤·¤¿ÆþÎÏ¥­¡¼¤ò¼õ¤±¼è
104     ¤ë¡£ÆþÎÏ¥­¡¼¤Ï¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£@c m17n @c ¥é¥¤¥Ö¥é¥ê ¤ÏÆþÎÏ¥¤¥Ù¥ó¥È
105     ¤¬¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¡¦¥×¥í¥°¥é¥à¤Ç¤É¤Î¤è¤¦¤Ëɽ¸½¤µ¤ì¤Æ¤¤¤ë¤«¤òÃΤë½Ñ
106     ¤ò»ý¤¿¤Ê¤¤¤Î¤Ç¡¢ÆþÎÏ¥¤¥Ù¥ó¥È¤«¤éÆþÎÏ¥­¡¼¤Ø¤ÎÊÑ´¹¤Ï¥¢¥×¥ê¥±¡¼¥·¥ç¥ó
107     ¥×¥í¥°¥é¥Þ¤ÎÀÕǤ¤Ç¹Ô¤ï¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï´Ø¿ô 
108     minput_event_to_key () ¤ÎÀâÌÀ¤ò»²¾È¡£
109
110     <li> ³°ÉôÆþÎϥ᥽¥Ã¥É
111
112     ³°ÉôÆþÎϥ᥽¥Ã¥É¤Ï LANGUAGE ¤¬ @c Mnil ¤Î¤â¤Î¤Ç¤¢¤ê¡¢ËÜÂΤϳ°Éô¤Î
113     ¥ê¥½¡¼¥¹¤È¤·¤ÆÄêµÁ¤µ¤ì¤ë¡£¡Ê¤¿¤È¤¨¤ÐX Window System ¤ÎXIM ¤Ê¤É¡£) 
114     ¤³¤Î¼ï¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¡¢¥·¥ó¥Ü¥ë NAME ¤Ï@c Minput_driver ¤ò¥­¡¼
115     ¤È¤¹¤ë¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Á¡¢¤½¤ÎÃͤÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç
116     ¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤·¤¿¤¬¤Ã¤Æ¡¢Å¬Àڤʥɥ饤¥Ð¤ò½àÈ÷¤¹¤ë¤³¤È¤Ë¤è¤Ã¤Æ¡¢
117     ¤¤¤«¤Ê¤ë¼ïÎà¤ÎÆþÎϥ᥽¥Ã¥É¤â @c m17n @c ¥é¥¤¥Ö¥é¥ê¤ÎÏÈÁȤÎÃæ¤Ç°·¤¦
118     »ö¤¬¤Ç¤­¤ë¡£
119
120     ´Êñ¤Î¤¿¤á¡¢m17n X ¥é¥¤¥Ö¥é¥ê¤Ï XIM ¤Î OverTheSpot ¤ÎÆþÎÏ¥¹¥¿¥¤¥ë
121     ¤ò¼Â¸½¤¹¤ëÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤òÄ󶡤·¡¢¤Þ¤¿¥·¥ó¥Ü¥ë @c Mxim ¤Î @c
122     Minput_driver ¥×¥í¥Ñ¥Æ¥£¤ÎÃͤȤ·¤Æ¤½¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÝ»ý¤·
123     ¤Æ¤¤¤ë¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ïm17n-win API ¤Î¥É¥­¥å¥á¥ó¥È¤ò»²¾È¤Î¤³¤È¡£
124
125     </ul> 
126
127     ½èÍý¤Îή¤ì
128
129     ÆþÎϥ᥽¥Ã¥É½èÍý¤Îŵ·¿Åª¤Ê½èÍý¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
130     
131     @li ÆþÎϥ᥽¥Ã¥É¤Î¥ª¡¼¥×¥ó
132     @li ¤½¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ÎÀ¸À®
133     @li ÆþÎÏ¥¤¥Ù¥ó¥È¤Î¥Õ¥£¥ë¥¿
134     @li ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ç¤ÎÀ¸À®¥Æ¥­¥¹¥È¤Î¸¡º÷     */
135
136 /*=*/
137
138 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
139 /*** @addtogroup m17nInternal
140      @{ */
141
142 #include <stdio.h>
143 #include <string.h>
144 #include <dlfcn.h>
145
146 #include "config.h"
147 #include "m17n-gui.h"
148 #include "m17n-misc.h"
149 #include "internal.h"
150 #include "mtext.h"
151 #include "input.h"
152 #include "symbol.h"
153 #include "plist.h"
154
155 static MSymbol Minput_method;
156
157 /** Symbols to load an input method data.  */
158 static MSymbol Mtitle, Mmacro, Mmodule, Mstate;
159
160 /** Symbols for actions.  */
161 static MSymbol Minsert, Mdelete, Mmark, Mmove, Mpushback, Mundo, Mcall, Mshift;
162 static MSymbol Mselect, Mshow, Mhide;
163 static MSymbol Mset, Madd, Msub, Mmul, Mdiv, Mequal, Mless, Mgreater;
164
165 static MSymbol Mcandidate_list, Mcandidate_index;
166
167 static MSymbol Minit, Mfini;
168
169 /** Symbols for key events.  */
170 static MSymbol one_char_symbol[256];
171
172 static MSymbol M_key_alias;
173
174 /** Structure to hold a map.  */
175
176 struct MIMMap
177 {
178   /** List of actions to take when we reach the map.  In a root map,
179       the actions are executed only when there's no more key.  */
180   MPlist *map_actions;
181
182   /** List of deeper maps.  If NULL, this is a terminal map.  */
183   MPlist *submaps;
184
185   /** List of actions to take when we leave the map successfully.  In
186       a root map, the actions are executed only when none of submaps
187       handle the current key.  */
188   MPlist *branch_actions;
189 };
190
191 typedef MPlist *(*MIMExternalFunc) (MPlist *plist);
192
193 typedef struct
194 {
195   void *handle;
196   MPlist *func_list;            /* function name vs (MIMExternalFunc *) */
197 } MIMExternalModule;
198
199 struct MIMState
200 {
201   /** Name of the state.  */
202   MSymbol name;
203
204   /** Title of the state, or NULL.  */
205   MText *title;
206
207   /** Key translation map of the state.  Built by merging all maps of
208       branches.  */
209   MIMMap *map;
210 };
211
212
213 static int
214 marker_code (MSymbol sym)
215 {
216   char *name;
217
218   if (sym == Mnil)
219     return -1;
220   name = MSYMBOL_NAME (sym);
221   return ((name[0] == '@'
222            && ((name[1] >= '0' && name[1] <= '9')
223                || name[1] == '<' || name[1] == '>'
224                || name[1] == '=' || name[1] == '+' || name[1] == '-'
225                || name[1] == '[' || name[1] == ']')
226            && name[2] == '\0')
227           ? name[1] : -1);
228 }
229
230 int
231 integer_value (MInputContext *ic, MPlist *arg)
232 {
233   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
234   int code;
235   MText *preedit = ic->preedit;
236   int len = mtext_nbytes (preedit);
237
238   if (MPLIST_INTEGER_P (arg))
239     return MPLIST_INTEGER (arg);
240   code = marker_code (MPLIST_SYMBOL (arg));
241   if (code < 0)
242     return (int) mplist_get (ic_info->vars, MPLIST_SYMBOL (arg));
243   if (code >= '0' && code <= '9')
244     code -= '0';
245   else if (code == '=')
246     code = ic->cursor_pos;
247   else if (code == '-' || code == '[')
248     code = ic->cursor_pos - 1;
249   else if (code == '+' || code == ']')
250     code = ic->cursor_pos + 1;
251   else if (code == '<')
252     code = 0;
253   else if (code == '<')
254     code = len;
255   return (code >= 0 && code < len ? mtext_ref_char (preedit, code) : -1);
256 }
257
258
259 /* Parse PLIST as an action list while modifying the list to regularize
260    actions.  PLIST should have this form:
261       PLIST ::= ( (ACTION-NAME ACTION-ARG *) *).
262    Return 0 if successfully parsed, otherwise return -1.  */
263
264 static int
265 parse_action_list (MPlist *plist, MPlist *macros)
266 {
267   MPLIST_DO (plist, plist)
268     {
269       if (MPLIST_MTEXT_P (plist))
270         {
271           /* This is a short form of (insert MTEXT).  */
272           /* if (mtext_nchars (MPLIST_MTEXT (plist)) == 0)
273              MERROR (MERROR_IM, -1); */
274         }
275       else if (MPLIST_PLIST_P (plist)
276                && (MPLIST_MTEXT_P (MPLIST_PLIST (plist))
277                    || MPLIST_PLIST_P (MPLIST_PLIST (plist))))
278         {
279           MPlist *pl;
280
281           /* This is a short form of (insert (GROUPS *)).  */
282           MPLIST_DO (pl, MPLIST_PLIST (plist))
283             {
284               if (MPLIST_PLIST_P (pl))
285                 {
286                   MPlist *elt;
287
288                   MPLIST_DO (elt, MPLIST_PLIST (pl))
289                     if (! MPLIST_MTEXT_P (elt)
290                         || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
291                       MERROR (MERROR_IM, -1);
292                 }
293               else
294                 {
295                   if (! MPLIST_MTEXT_P (pl)
296                       || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
297                     MERROR (MERROR_IM, -1);
298                 }
299             }
300         }
301       else if (MPLIST_INTEGER_P (plist))
302         {
303           int c = MPLIST_INTEGER (plist);
304
305           if (c < 0 || c > MCHAR_MAX)
306             MERROR (MERROR_IM, -1);
307         }
308       else if (MPLIST_PLIST_P (plist)
309                && MPLIST_SYMBOL_P (MPLIST_PLIST (plist)))
310         {
311           MPlist *pl = MPLIST_PLIST (plist);
312           MSymbol action_name = MPLIST_SYMBOL (pl);
313
314           pl = MPLIST_NEXT (pl);
315
316           if (action_name == Minsert)
317             {
318               if (MPLIST_MTEXT_P (pl))
319                 {
320                   if (mtext_nchars (MPLIST_MTEXT (pl)) == 0)
321                     MERROR (MERROR_IM, -1);
322                 }
323               else if (MPLIST_PLIST_P (pl))
324                 {
325                   MPLIST_DO (pl, pl)
326                     {
327                       if (MPLIST_PLIST_P (pl))
328                         {
329                           MPlist *elt;
330
331                           MPLIST_DO (elt, MPLIST_PLIST (pl))
332                             if (! MPLIST_MTEXT_P (elt)
333                                 || mtext_nchars (MPLIST_MTEXT (elt)) == 0)
334                               MERROR (MERROR_IM, -1);
335                         }
336                       else
337                         {
338                           if (! MPLIST_MTEXT_P (pl)
339                               || mtext_nchars (MPLIST_MTEXT (pl)) == 0)
340                             MERROR (MERROR_IM, -1);
341                         }
342                     }
343                 }
344               else if (! MPLIST_SYMBOL_P (pl))
345                 MERROR (MERROR_IM, -1); 
346             }
347           else if (action_name == Mselect
348                    || action_name == Mdelete
349                    || action_name == Mmove)
350             {
351               if (! MPLIST_SYMBOL_P (pl)
352                   && ! MPLIST_INTEGER_P (pl))
353                 MERROR (MERROR_IM, -1);
354             }
355           else if (action_name == Mmark
356                    || action_name == Mcall
357                    || action_name == Mshift)
358             {
359               if (! MPLIST_SYMBOL_P (pl))
360                 MERROR (MERROR_IM, -1);
361             }
362           else if (action_name == Mshow || action_name == Mhide
363                    || action_name == Mundo)
364             {
365               if (! MPLIST_TAIL_P (pl))
366                 MERROR (MERROR_IM, -1);
367             }
368           else if (action_name == Mpushback)
369             {
370               if (! MPLIST_INTEGER_P (pl))
371                 MERROR (MERROR_IM, -1);
372             }
373           else if (action_name == Mset || action_name == Madd
374                    || action_name == Msub || action_name == Mmul
375                    || action_name == Mdiv)
376             {
377               if (! (MPLIST_SYMBOL_P (pl)
378                      && (MPLIST_INTEGER_P (MPLIST_NEXT (pl))
379                          || MPLIST_SYMBOL_P (MPLIST_NEXT (pl)))))
380                 MERROR (MERROR_IM, -1);
381             }
382           else if (action_name == Mequal || action_name == Mless
383                    || action_name == Mgreater)
384             {
385               if (! ((MPLIST_INTEGER_P (pl) || MPLIST_SYMBOL_P (pl))
386                      && (MPLIST_INTEGER_P (MPLIST_NEXT (pl))
387                          || MPLIST_SYMBOL_P (MPLIST_NEXT (pl)))))
388                 MERROR (MERROR_IM, -1);
389               pl = MPLIST_NEXT (MPLIST_NEXT (pl));
390               if (! MPLIST_PLIST_P (pl))
391                 MERROR (MERROR_IM, -1);
392               if (parse_action_list (MPLIST_PLIST (pl), macros) < 0)
393                 MERROR (MERROR_IM, -1);
394               pl = MPLIST_NEXT (pl);
395               if (MPLIST_PLIST_P (pl)
396                   && parse_action_list (MPLIST_PLIST (pl), macros) < 0)
397                 MERROR (MERROR_IM, -1);
398             }
399           else if (! macros || ! mplist_get (macros, action_name))
400             MERROR (MERROR_IM, -1);
401         }
402       else
403         MERROR (MERROR_IM, -1);
404     }
405
406   return 0;
407 }
408
409
410 /* Load a translation into MAP from PLIST.
411    PLIST has this form:
412       PLIST ::= ( KEYSEQ MAP-ACTION * )  */
413
414 static int
415 load_translation (MIMMap *map, MPlist *plist, MPlist *branch_actions,
416                   MPlist *macros)
417 {
418   MSymbol *keyseq;
419   int len, i;
420
421   if (MPLIST_MTEXT_P (plist))
422     {
423       MText *mt = MPLIST_MTEXT (plist);
424
425       len = mtext_nchars (mt);
426       if (len == 0 || len != mtext_nbytes (mt))
427         MERROR (MERROR_IM, -1);
428       keyseq = (MSymbol *) alloca (sizeof (MSymbol) * len);
429       for (i = 0; i < len; i++)
430         keyseq[i] = one_char_symbol[MTEXT_DATA (mt)[i]];
431     }
432   else if (MPLIST_PLIST_P (plist))
433     {
434       MPlist *elt = MPLIST_PLIST (plist);
435           
436       len = MPLIST_LENGTH (elt);
437       if (len == 0)
438         MERROR (MERROR_IM, -1);
439       keyseq = (MSymbol *) alloca (sizeof (int) * len);
440       for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt))
441         {
442           if (MPLIST_INTEGER_P (elt))
443             {
444               int c = MPLIST_INTEGER (elt);
445
446               if (c < 0 || c >= 0x100)
447                 MERROR (MERROR_IM, -1);
448               keyseq[i] = one_char_symbol[c];
449             }
450           else if (MPLIST_SYMBOL_P (elt))
451             keyseq[i] = MPLIST_SYMBOL (elt);
452           else
453             MERROR (MERROR_IM, -1);
454         }
455     }
456   else
457     MERROR (MERROR_IM, -1);
458
459   for (i = 0; i < len; i++)
460     {
461       MIMMap *deeper = NULL;
462
463       if (map->submaps)
464         deeper = mplist_get (map->submaps, keyseq[i]);
465       else
466         map->submaps = mplist ();
467       if (! deeper)
468         {
469           /* Fixme: It is better to make all deeper maps at once.  */
470           MSTRUCT_CALLOC (deeper, MERROR_IM);
471           mplist_put (map->submaps, keyseq[i], deeper);
472         }
473       map = deeper;
474     }
475
476   /* We reach a terminal map.  */
477   if (map->map_actions
478       || map->branch_actions)
479     /* This map is already defined.  We avoid overriding it.  */
480     return 0;
481
482   plist = MPLIST_NEXT (plist);
483   if (! MPLIST_TAIL_P (plist))
484     {
485       if (parse_action_list (plist, macros) < 0)
486         MERROR (MERROR_IM, -1);
487       map->map_actions = plist;
488       M17N_OBJECT_REF (plist);
489     }
490   if (branch_actions)
491     {
492       map->branch_actions = branch_actions;
493       M17N_OBJECT_REF (branch_actions);
494     }
495
496   return 0;
497 }
498
499 /* Load a branch from PLIST into MAP.  PLIST has this form:
500       PLIST ::= ( MAP-NAME BRANCH-ACTION * )
501    MAPS is a plist of raw maps.
502    STATE is the current state.  */
503
504 static int
505 load_branch (MPlist *plist, MPlist *maps, MIMMap *map, MPlist *macros)
506 {
507   MSymbol map_name;
508   MPlist *branch_actions;
509
510   if (! MPLIST_SYMBOL_P (plist))
511     MERROR (MERROR_IM, -1);
512   map_name = MPLIST_SYMBOL (plist);
513   plist = MPLIST_NEXT (plist);
514   if (MPLIST_TAIL_P (plist))
515     branch_actions = NULL;
516   else if (parse_action_list (plist, macros) < 0)
517     MERROR (MERROR_IM, -1);
518   else
519     branch_actions = plist;
520   if (map_name == Mnil)
521     {
522       map->branch_actions = branch_actions;
523       if (branch_actions)
524         M17N_OBJECT_REF (branch_actions);
525     }
526   else if (map_name == Mt)
527     {
528       map->map_actions = branch_actions;
529       if (branch_actions)
530         M17N_OBJECT_REF (branch_actions);
531     }
532   else
533     {
534       plist = (MPlist *) mplist_get (maps, map_name);
535       if (! plist || ! MPLIST_PLIST_P (plist))
536         MERROR (MERROR_IM, -1);
537       MPLIST_DO (plist, plist)
538         if (! MPLIST_PLIST_P (plist)
539             || (load_translation (map, MPLIST_PLIST (plist), branch_actions,
540                                   macros)
541                 < 0))
542           MERROR (MERROR_IM, -1);
543     }
544
545   return 0;
546 }
547
548 /* Load a macro from PLIST into MACROS.
549    PLIST has this from:
550       PLIST ::= ( MACRO-NAME ACTION * )
551    MACROS is a plist of macro names vs action list.  */
552 static int
553 load_macros (MPlist *plist, MPlist *macros)
554 {
555   MSymbol name; 
556
557   if (! MPLIST_SYMBOL_P (plist))
558     MERROR (MERROR_IM, -1);
559   name = MPLIST_SYMBOL (plist);
560   plist = MPLIST_NEXT (plist);
561   if (MPLIST_TAIL_P (plist)
562       || parse_action_list (plist, macros) < 0)
563     MERROR (MERROR_IM, -1);
564   mplist_put (macros, name, plist);
565   M17N_OBJECT_REF (plist);
566   return 0;
567 }
568
569 /* Load an external module from PLIST into EXTERNALS.
570    PLIST has this form:
571       PLIST ::= ( MODULE-NAME FUNCTION * )
572    EXTERNALS is a plist of MODULE-NAME vs (MIMExternalModule *).  */
573
574 #ifndef DLOPEN_SHLIB_EXT
575 #define DLOPEN_SHLIB_EXT ".so"
576 #endif
577
578 static int
579 load_external_module (MPlist *plist, MPlist *externals)
580 {
581   void *handle;
582   MSymbol module;
583   char *module_file;
584   MIMExternalModule *external;
585   MPlist *func_list;
586   void *func;
587
588   if (MPLIST_MTEXT_P (plist))
589     module = msymbol ((char *) MTEXT_DATA (MPLIST_MTEXT (plist)));
590   else if (MPLIST_SYMBOL_P (plist))
591     module = MPLIST_SYMBOL (plist);
592   module_file = alloca (strlen (MSYMBOL_NAME (module))
593                         + strlen (DLOPEN_SHLIB_EXT) + 1);
594   sprintf (module_file, "%s%s", MSYMBOL_NAME (module), DLOPEN_SHLIB_EXT);
595
596   handle = dlopen (module_file, RTLD_NOW);
597   if (! handle)
598     {
599       fprintf (stderr, "%s\n", dlerror ());
600       MERROR (MERROR_IM, -1);
601     }
602   func_list = mplist ();
603   MPLIST_DO (plist, MPLIST_NEXT (plist))
604     {
605       if (! MPLIST_SYMBOL_P (plist))
606         MERROR_GOTO (MERROR_IM, err_label);
607       func = dlsym (handle, MSYMBOL_NAME (MPLIST_SYMBOL (plist)));
608       if (! func)
609         MERROR_GOTO (MERROR_IM, err_label);
610       mplist_add (func_list, MPLIST_SYMBOL (plist), func);
611     }
612
613   MSTRUCT_MALLOC (external, MERROR_IM);
614   external->handle = handle;
615   external->func_list = func_list;
616   mplist_add (externals, module, external);
617   return 0;
618
619  err_label:
620   dlclose (handle);
621   M17N_OBJECT_UNREF (func_list);
622   return -1;
623 }
624
625
626 /** Load a state from PLIST into a newly allocated state object.
627     PLIST has this form:
628       PLIST ::= ( STATE-NAME STATE-TITLE ? BRANCH * )
629       BRANCH ::= ( MAP-NAME BRANCH-ACTION * )
630    MAPS is a plist of defined maps.
631    Return the state object.  */
632
633 static MIMState *
634 load_state (MPlist *plist, MPlist *maps, MSymbol language, MPlist *macros)
635 {
636   MIMState *state;
637
638   MSTRUCT_CALLOC (state, MERROR_IM);
639   if (! MPLIST_SYMBOL_P (plist))
640     MERROR (MERROR_IM, NULL);
641   state->name = MPLIST_SYMBOL (plist);
642   plist = MPLIST_NEXT (plist);
643   if (MPLIST_MTEXT_P (plist))
644     {
645       state->title = MPLIST_MTEXT (plist);
646       mtext_put_prop (state->title, 0, mtext_nchars (state->title),
647                       Mlanguage, language);
648       M17N_OBJECT_REF (state->title);
649       plist = MPLIST_NEXT (plist);
650     }
651   MSTRUCT_CALLOC (state->map, MERROR_IM);
652   MPLIST_DO (plist, plist)
653     if (! MPLIST_PLIST_P (plist)
654         || load_branch (MPLIST_PLIST (plist), maps, state->map, macros) < 0)
655       MERROR (MERROR_IM, NULL);
656   return state;
657 }
658
659
660 static void
661 free_map (MIMMap *map)
662 {
663   MPlist *plist;
664
665   M17N_OBJECT_UNREF (map->map_actions);
666   if (map->submaps)
667     {
668       MPLIST_DO (plist, map->submaps)
669         free_map ((MIMMap *) MPLIST_VAL (plist));
670       M17N_OBJECT_UNREF (map->submaps);
671     }
672   M17N_OBJECT_UNREF (map->branch_actions);
673   free (map);
674 }
675
676 /* Load an input method from PLIST into IM_INTO, and return it.  */
677
678 static int
679 load_input_method (MSymbol language, MSymbol name, MPlist *plist,
680                    MInputMethodInfo *im_info)
681 {
682   MText *title = NULL;
683   MPlist *maps = NULL;
684   MPlist *states = NULL;
685   MPlist *externals = NULL;
686   MPlist *macros = NULL;
687   MPlist *elt;
688
689   if (! MPLIST_PLIST_P (plist))
690     MERROR (MERROR_IM, -1);
691   for (; MPLIST_PLIST_P (plist); plist = MPLIST_NEXT (plist))
692     {
693       elt = MPLIST_PLIST (plist);
694       if (! MPLIST_SYMBOL_P (elt))
695         MERROR_GOTO (MERROR_IM, err);
696       if (MPLIST_SYMBOL (elt) == Mtitle)
697         {
698           elt = MPLIST_NEXT (elt);
699           if (MPLIST_MTEXT_P (elt))
700             {
701               title = MPLIST_MTEXT (elt);
702               M17N_OBJECT_REF (title);
703             }
704           else
705             MERROR_GOTO (MERROR_IM, err);
706         }
707       else if (MPLIST_SYMBOL (elt) == Mmap)
708         {
709           maps = mplist__from_alist (MPLIST_NEXT (elt));
710           if (! maps)
711             MERROR_GOTO (MERROR_IM, err);
712         }
713       else if (MPLIST_SYMBOL (elt) == Mmacro)
714         {
715           macros = mplist ();
716           MPLIST_DO (elt, MPLIST_NEXT (elt))
717           {
718             if (! MPLIST_PLIST_P (elt)
719                 || load_macros (MPLIST_PLIST (elt), macros) < 0)
720               MERROR_GOTO (MERROR_IM, err);
721           }
722         }
723       else if (MPLIST_SYMBOL (elt) == Mmodule)
724         {
725           externals = mplist ();
726           MPLIST_DO (elt, MPLIST_NEXT (elt))
727           {
728             if (! MPLIST_PLIST_P (elt)
729                 || load_external_module (MPLIST_PLIST (elt), externals) < 0)
730               MERROR_GOTO (MERROR_IM, err);
731           }
732         }
733       else if (MPLIST_SYMBOL (elt) == Mstate)
734         {
735           states = mplist ();
736           MPLIST_DO (elt, MPLIST_NEXT (elt))
737           {
738             MIMState *state;
739
740             if (! MPLIST_PLIST_P (elt))
741               MERROR_GOTO (MERROR_IM, err);
742             state = load_state (MPLIST_PLIST (elt), maps, language, macros);
743             if (! state)
744               MERROR_GOTO (MERROR_IM, err);
745             mplist_put (states, state->name, state);
746           }
747         }
748     }
749
750   MPLIST_DO (elt, maps)
751     M17N_OBJECT_UNREF (MPLIST_VAL (elt));
752   M17N_OBJECT_UNREF (maps);
753   if (! title)
754     title = mtext_from_data (MSYMBOL_NAME (name), MSYMBOL_NAMELEN (name),
755                              MTEXT_FORMAT_US_ASCII);
756   im_info->title = title;
757   im_info->externals = externals;
758   im_info->macros = macros;
759   im_info->states = states;
760   return 0;
761
762  err:
763   if (maps)
764     {
765       MPLIST_DO (elt, maps)
766         M17N_OBJECT_UNREF (MPLIST_VAL (elt));
767       M17N_OBJECT_UNREF (maps);
768     }
769   if (title)
770     M17N_OBJECT_UNREF (title);
771   if (states)
772     {
773       MPLIST_DO (plist, states)
774       {
775         MIMState *state = (MIMState *) MPLIST_VAL (plist);
776
777         if (state->title)
778           M17N_OBJECT_UNREF (state->title);
779         if (state->map)
780           free_map (state->map);
781         free (state);
782       }
783       M17N_OBJECT_UNREF (states);
784     }
785   if (externals)
786     {
787       MPLIST_DO (plist, externals)
788       {
789         MIMExternalModule *external = MPLIST_VAL (plist);
790
791         dlclose (external->handle);
792         M17N_OBJECT_UNREF (external->func_list);
793         free (external);
794         MPLIST_KEY (plist) = Mt;
795       }
796       M17N_OBJECT_UNREF (externals);
797     }
798   return -1;
799 }
800
801 \f
802
803 static int take_action_list (MInputContext *ic, MPlist *action_list);
804
805 static void
806 shift_state (MInputContext *ic, MSymbol state_name)
807 {
808   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
809   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
810   MIMState *state = ic_info->state;
811
812   /* Find a state to shift to.  If not found, shift to the initial
813      state.  */
814   state = (MIMState *) mplist_get (im_info->states, state_name);
815   if (! state)
816     state = (MIMState *) MPLIST_VAL (im_info->states);
817
818   /* Enter the new state.  */
819   ic_info->state = state;
820   ic_info->map = state->map;
821   ic_info->state_key_head = ic_info->key_head;
822   if (state == (MIMState *) MPLIST_VAL (im_info->states))
823     {
824       /* We have shifted to the initial state.  */
825       MPlist *p;
826
827       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
828                              Mcandidate_list, NULL, 0);
829       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
830                              Mcandidate_index, NULL, 0);
831       mtext_cat (ic->produced, ic->preedit);
832       mtext_reset (ic->preedit);
833       ic->candidate_list = NULL;
834       ic->candidate_show = 0;
835       ic->preedit_changed = ic->candidates_changed = 1;
836       MPLIST_DO (p, ic_info->markers)
837         MPLIST_VAL (p) = 0;
838       MPLIST_DO (p, ic_info->vars)
839         MPLIST_VAL (p) = 0;
840       ic->cursor_pos = 0;
841       memmove (ic_info->keys, ic_info->keys + ic_info->state_key_head,
842                sizeof (int) * (ic_info->used - ic_info->state_key_head));
843       ic_info->used -= ic_info->state_key_head;
844       ic_info->state_key_head = ic_info->key_head = 0;
845     }
846   mtext_cpy (ic_info->preedit_saved, ic->preedit);
847   ic_info->state_pos = ic->cursor_pos;
848   ic->status = state->title;
849   if (! ic->status)
850     ic->status = im_info->title;
851   ic->status_changed = 1;
852   if (ic_info->key_head == ic_info->used
853       && ic_info->map == ic_info->state->map
854       && ic_info->map->map_actions)
855     take_action_list (ic, ic_info->map->map_actions);
856 }
857
858
859 static MPlist *
860 find_candidates_group (MPlist *plist, int index,
861                        int *start_index, int *end_index, int *group_index)
862 {
863   int i = 0, gidx = 0, len;
864
865   MPLIST_DO (plist, plist)
866     {
867       if (MPLIST_MTEXT_P (plist))
868         len = mtext_nchars (MPLIST_MTEXT (plist));
869       else
870         len = mplist_length (MPLIST_PLIST (plist));
871       if (i + len > index)
872         {
873           if (start_index)
874             *start_index = i;
875           if (end_index)
876             *end_index = i + len;
877           if (group_index)
878             *group_index = gidx;
879           return plist;
880         }
881       i += len;
882       gidx++;
883     }
884   return NULL;
885 }
886
887 static void
888 preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
889 {
890   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
891   MPlist *markers;
892   int nchars = mt ? mtext_nchars (mt) : 1;
893
894   if (mt)
895     mtext_ins (ic->preedit, pos, mt);
896   else
897     mtext_ins_char (ic->preedit, pos, c, 1);
898   MPLIST_DO (markers, ic_info->markers)
899     if (MPLIST_INTEGER (markers) > pos)
900       MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + nchars);
901   if (ic->cursor_pos >= pos)
902     ic->cursor_pos += nchars;
903   ic->preedit_changed = 1;
904 }
905
906
907 static void
908 preedit_delete (MInputContext *ic, int from, int to)
909 {
910   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
911   MPlist *markers;
912
913   mtext_del (ic->preedit, from, to);
914   MPLIST_DO (markers, ic_info->markers)
915     {
916       if (MPLIST_INTEGER (markers) > to)
917         MPLIST_VAL (markers)
918           = (void *) (MPLIST_INTEGER (markers) - (to - from));
919       else if (MPLIST_INTEGER (markers) > from);
920         MPLIST_VAL (markers) = (void *) from;
921     }
922   if (ic->cursor_pos >= to)
923     ic->cursor_pos -= to - from;
924   else if (ic->cursor_pos > from)
925     ic->cursor_pos = from;
926   ic->preedit_changed = 1;
927 }
928
929
930 static int
931 new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt)
932 {
933   int code = marker_code (sym);
934
935   if (mt && (code == '[' || code == ']'))
936     {
937       int pos = current;
938
939       if (code == '[' && current > 0)
940         {
941           if (mtext_prop_range (mt, Mcandidate_list, pos - 1, &pos, NULL, 1)
942               && pos > 0)
943             current = pos;
944         }
945       else if (code == ']' && current < mtext_nchars (mt))
946         {
947           if (mtext_prop_range (mt, Mcandidate_list, pos, NULL, &pos, 1))
948             current = pos;
949         }
950       return current;
951     }
952   if (code >= 0)
953     return (code == '<' ? 0
954             : code == '>' ? limit
955             : code == '-' ? current - 1
956             : code == '+' ? current + 1
957             : code == '=' ? current
958             : code - '0' > limit ? limit
959             : code - '0');
960   if (! ic)  
961     return 0;
962   return (int) mplist_get (((MInputContextInfo *) ic->info)->markers, sym);
963 }
964
965 static void
966 udpate_candidate (MInputContext *ic, MTextProperty *prop, int idx)
967 {
968   int from = mtext_property_start (prop);
969   int to = mtext_property_end (prop);
970   int start;
971   MPlist *candidate_list = mtext_property_value (prop);
972   MPlist *group = find_candidates_group (candidate_list, idx, &start,
973                                          NULL, NULL);
974   int ingroup_index = idx - start;
975   MText *mt;
976
977   preedit_delete (ic, from, to);
978   if (MPLIST_MTEXT_P (group))
979     {
980       mt = MPLIST_MTEXT (group);
981       preedit_insert (ic, from, NULL, mtext_ref_char (mt, ingroup_index));
982       to = from + 1;
983     }
984   else
985     {
986       int i;
987       MPlist *plist;
988
989       for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
990            i++, plist = MPLIST_NEXT (plist));
991       mt = MPLIST_MTEXT (plist);
992       preedit_insert (ic, from, mt, 0);
993       to = from + mtext_nchars (mt);
994     }
995   mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
996   mtext_put_prop (ic->preedit, from, to, Mcandidate_index, (void *) idx);
997   ic->cursor_pos = to;
998 }
999
1000
1001 static int
1002 take_action_list (MInputContext *ic, MPlist *action_list)
1003 {
1004   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1005   MPlist *candidate_list = ic->candidate_list;
1006   int candidate_index = ic->candidate_index;
1007   int candidate_show = ic->candidate_show;
1008   MTextProperty *prop;
1009
1010   MPLIST_DO (action_list, action_list)
1011     {
1012       MPlist *action;
1013       MSymbol name;
1014       MPlist *args;
1015
1016       if (MPLIST_MTEXT_P (action_list)
1017           || MPLIST_INTEGER_P (action_list))
1018         name = Minsert, args = action_list;
1019       else if (MPLIST_PLIST_P (action_list)
1020                && (MPLIST_MTEXT_P (MPLIST_PLIST (action_list))
1021                    || MPLIST_PLIST_P (MPLIST_PLIST (action_list))))
1022         name = Minsert, args = action_list;
1023       else
1024         {
1025           action = MPLIST_PLIST (action_list);
1026           name = MPLIST_SYMBOL (action);
1027           args = MPLIST_NEXT (action);
1028         }
1029
1030       if (name == Minsert)
1031         {
1032           if (MPLIST_MTEXT_P (args))
1033             preedit_insert (ic, ic->cursor_pos, MPLIST_MTEXT (args), 0);
1034           else if (MPLIST_INTEGER_P (args))
1035             preedit_insert (ic, ic->cursor_pos, NULL, MPLIST_INTEGER (args));
1036           else if (MPLIST_SYMBOL_P (args))
1037             {
1038               int c = integer_value (ic, args);
1039
1040               if (c >= 0 && c <= MCHAR_MAX)
1041                 preedit_insert (ic, ic->cursor_pos, NULL, c);
1042             }
1043           else
1044             {
1045               MText *mt;
1046               int len;
1047
1048               args = MPLIST_PLIST (args);
1049               if (MPLIST_MTEXT_P (args))
1050                 {
1051                   preedit_insert (ic, ic->cursor_pos, NULL,
1052                                   mtext_ref_char (MPLIST_MTEXT (args), 0));
1053                   len = 1;
1054                 }
1055               else
1056                 {
1057                   mt = MPLIST_MTEXT (MPLIST_PLIST (args));
1058                   preedit_insert (ic, ic->cursor_pos, mt, 0);
1059                   len = mtext_nchars (mt);
1060                 }
1061               mtext_put_prop (ic->preedit,
1062                               ic->cursor_pos - len, ic->cursor_pos,
1063                               Mcandidate_list, args);
1064               mtext_put_prop (ic->preedit,
1065                               ic->cursor_pos - len, ic->cursor_pos,
1066                               Mcandidate_index, (void *) 0);
1067             }
1068         }
1069       else if (name == Mselect)
1070         {
1071           int start, end;
1072           int code, idx, gindex;
1073           int pos = ic->cursor_pos;
1074           MPlist *group;
1075
1076           if (pos == 0
1077               || ! (prop = mtext_get_property (ic->preedit, pos - 1,
1078                                                Mcandidate_list)))
1079             continue;
1080           if (MPLIST_SYMBOL_P (args))
1081             {
1082               code = marker_code (MPLIST_SYMBOL (args));
1083               if (code < 0)
1084                 continue;
1085             }
1086           else
1087             code = -1;
1088           idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
1089           group = find_candidates_group (mtext_property_value (prop), idx,
1090                                          &start, &end, &gindex);
1091
1092           if (code != '[' && code != ']')
1093             {
1094               idx = (start
1095                      + (code >= 0
1096                         ? new_index (NULL, ic->candidate_index - start,
1097                                      end - start - 1, MPLIST_SYMBOL (args),
1098                                      NULL)
1099                         : MPLIST_INTEGER (args)));
1100               if (idx < 0
1101                   || (idx >= end
1102                       && MPLIST_TAIL_P (MPLIST_NEXT (group))))
1103                 idx = 0;
1104             }
1105           else
1106             {
1107               int ingroup_index = idx - start;
1108               int len;
1109
1110               group = mtext_property_value (prop);
1111               len = mplist_length (group);
1112               if (code == '[')
1113                 {
1114                   gindex--;
1115                   if (gindex < 0)
1116                     gindex = len - 1;;
1117                 }
1118               else
1119                 {
1120                   gindex++;
1121                   if (gindex >= len)
1122                     gindex = 0;
1123                 }
1124               for (idx = 0; gindex > 0; gindex--, group = MPLIST_NEXT (group))
1125                 idx += (MPLIST_MTEXT_P (group)
1126                         ? mtext_nchars (MPLIST_MTEXT (group))
1127                         : mplist_length (MPLIST_PLIST (group)));
1128               len = (MPLIST_MTEXT_P (group)
1129                      ? mtext_nchars (MPLIST_MTEXT (group))
1130                      : mplist_length (MPLIST_PLIST (group)));
1131               if (ingroup_index >= len)
1132                 ingroup_index = len - 1;
1133               idx += ingroup_index;
1134             }
1135           udpate_candidate (ic, prop, idx);
1136         }
1137       else if (name == Mshow)
1138         ic->candidate_show = 1;
1139       else if (name == Mhide)
1140         ic->candidate_show = 0;
1141       else if (name == Mdelete)
1142         {
1143           int len = mtext_nchars (ic->preedit);
1144           int to = (MPLIST_SYMBOL_P (args)
1145                     ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
1146                                  ic->preedit)
1147                     : MPLIST_INTEGER (args));
1148
1149           if (to < 0)
1150             to = 0;
1151           else if (to > len)
1152             to = len;
1153           if (to < ic->cursor_pos)
1154             preedit_delete (ic, to, ic->cursor_pos);
1155           else if (to > ic->cursor_pos)
1156             preedit_delete (ic, ic->cursor_pos, to);
1157         }
1158       else if (name == Mmove)
1159         {
1160           int len = mtext_nchars (ic->preedit);
1161           int pos
1162             = (MPLIST_SYMBOL_P (args)
1163                ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
1164                             ic->preedit)
1165                : MPLIST_INTEGER (args));
1166
1167           if (pos < 0)
1168             pos = 0;
1169           else if (pos > len)
1170             pos = len;
1171           if (pos != ic->cursor_pos)
1172             {
1173               ic->cursor_pos = pos;
1174               ic->preedit_changed = 1;
1175             }
1176         }
1177       else if (name == Mmark)
1178         {
1179           int code = marker_code (MPLIST_SYMBOL (args));
1180
1181           if (code < 0)
1182             mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
1183                         (void *) ic->cursor_pos);
1184         }
1185       else if (name == Mpushback)
1186         {
1187           int num = MPLIST_INTEGER (args);
1188
1189           if (num > 0)
1190             ic_info->key_head -= num;
1191           else
1192             ic_info->key_head = num;
1193           if (ic_info->key_head > ic_info->used)
1194             ic_info->key_head = ic_info->used;
1195         }
1196       else if (name == Mcall)
1197         {
1198           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1199           MIMExternalFunc func = NULL;
1200           MSymbol module, func_name;
1201           MPlist *func_args, *val;
1202           int ret = 0;
1203
1204           module = MPLIST_SYMBOL (args);
1205           args = MPLIST_NEXT (args);
1206           func_name = MPLIST_SYMBOL (args);
1207
1208           if (im_info->externals)
1209             {
1210               MIMExternalModule *external
1211                 = (MIMExternalModule *) mplist_get (im_info->externals,
1212                                                     module);
1213               if (external)
1214                 func = (MIMExternalFunc) mplist_get (external->func_list,
1215                                                      func_name);
1216             }
1217           if (! func)
1218             continue;
1219           func_args = mplist ();
1220           mplist_add (func_args, Mt, ic);
1221           MPLIST_DO (args, MPLIST_NEXT (args))
1222             {
1223               int code;
1224
1225               if (MPLIST_KEY (args) == Msymbol
1226                   && MPLIST_KEY (args) != Mnil
1227                   && (code = marker_code (MPLIST_SYMBOL (args))) >= 0)
1228                 {
1229                   code = new_index (ic, ic->cursor_pos, 
1230                                     mtext_nchars (ic->preedit),
1231                                     MPLIST_SYMBOL (args), ic->preedit);
1232                   mplist_add (func_args, Minteger, (void *) code);
1233                 }
1234               else
1235                 mplist_add (func_args, MPLIST_KEY (args), MPLIST_VAL (args));
1236             }
1237           val = (func) (func_args);
1238           M17N_OBJECT_UNREF (func_args);
1239           if (val && ! MPLIST_TAIL_P (val))
1240             ret = take_action_list (ic, val);
1241           M17N_OBJECT_UNREF (val);
1242           if (ret < 0)
1243             return ret;
1244         }
1245       else if (name == Mshift)
1246         {
1247           shift_state (ic, MPLIST_SYMBOL (args));
1248         }
1249       else if (name == Mundo)
1250         {
1251           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1252           int unhandle = 0;
1253
1254           mtext_reset (ic->preedit);
1255           mtext_reset (ic_info->preedit_saved);
1256           ic->cursor_pos = ic_info->state_pos = 0;
1257           ic_info->state_key_head = ic_info->key_head = 0;
1258           ic_info->used -= 2;
1259           if (ic_info->used < 0)
1260             {
1261               ic_info->used = 0;
1262               unhandle = 1;
1263             }
1264           shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
1265           if (unhandle)
1266             return -1;
1267           break;
1268         }
1269       else if (name == Mset || name == Madd || name == Msub
1270                || name == Mmul || name == Mdiv)
1271         {
1272           MSymbol sym = MPLIST_SYMBOL (args);
1273           int val1 = (int) mplist_get (ic_info->vars, sym), val2;
1274
1275           args = MPLIST_NEXT (args);
1276           val2 = integer_value (ic, args);
1277           if (name == Mset)
1278             val1 = val2;
1279           else if (name == Madd)
1280             val1 += val2;
1281           else if (name == Msub)
1282             val1 -= val2;
1283           else if (name == Mmul)
1284             val1 *= val2;
1285           else
1286             val1 /= val2;
1287           mplist_put (ic_info->vars, sym, (void *) val1);
1288         }
1289       else if (name == Mequal || name == Mless || name == Mgreater)
1290         {
1291           int val1, val2;
1292           MPlist *actions1, *actions2;
1293           int ret;
1294
1295           val1 = integer_value (ic, args);
1296           args = MPLIST_NEXT (args);
1297           val2 = integer_value (ic, args);
1298           args = MPLIST_NEXT (args);
1299           actions1 = MPLIST_PLIST (args);
1300           args = MPLIST_NEXT (args);
1301           if (MPLIST_TAIL_P (args))
1302             actions2 = NULL;
1303           else
1304             actions2 = MPLIST_PLIST (args);
1305           if (name == Mequal ? val1 == val2
1306               : name == Mless ? val1 < val2
1307               : val1 > val2)
1308             ret = take_action_list (ic, actions1);
1309           else if (actions2)
1310             ret = take_action_list (ic, actions2);
1311           if (ret < 0)
1312             return ret;
1313         }
1314       else
1315         {
1316           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1317           MPlist *actions;
1318
1319           if (im_info->macros
1320               && (actions = mplist_get (im_info->macros, name)))
1321             {
1322               if (take_action_list (ic, actions) < 0)
1323                 return -1;
1324             };
1325         }
1326     }
1327
1328   prop = NULL;
1329   ic->candidate_list = NULL;
1330   if (ic->cursor_pos > 0
1331       && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
1332                                      Mcandidate_list)))
1333     {
1334       ic->candidate_list = mtext_property_value (prop);
1335       ic->candidate_index
1336         = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
1337                                 Mcandidate_index);
1338       ic->candidate_from = mtext_property_start (prop);
1339       ic->candidate_to = mtext_property_end (prop);
1340     }
1341
1342   ic->candidates_changed |= (candidate_list != ic->candidate_list
1343                              || candidate_index != ic->candidate_index
1344                              || candidate_show != ic->candidate_show);
1345   return 0;
1346 }
1347
1348
1349 /* Handle the input key KEY in the current state and map specified in
1350    the input context IC.  If KEY is handled correctly, return 0.
1351    Otherwise, return -1.  */
1352
1353 static int
1354 handle_key (MInputContext *ic)
1355 {
1356   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1357   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1358   MIMMap *map = ic_info->map;
1359   MIMMap *submap = NULL;
1360   MSymbol key = ic_info->keys[ic_info->key_head];
1361   int i;
1362
1363   if (map->submaps)
1364     {
1365       submap = mplist_get (map->submaps, key);
1366       if (! submap && (key = msymbol_get (key, M_key_alias)) != Mnil)
1367         submap = mplist_get (map->submaps, key);
1368     }
1369
1370   if (submap)
1371     {
1372       mtext_cpy (ic->preedit, ic_info->preedit_saved);
1373       ic->cursor_pos = ic_info->state_pos;
1374       ic_info->key_head++;
1375       ic_info->map = map = submap;
1376       if (map->map_actions)
1377         {
1378           if (take_action_list (ic, map->map_actions) < 0)
1379             return -1;
1380         }
1381       else if (map->submaps)
1382         {
1383           for (i = ic_info->state_key_head; i < ic_info->key_head; i++)
1384             {
1385               MSymbol key = ic_info->keys[i];
1386               char *name = msymbol_name (key);
1387
1388               if (! name[0] || ! name[1])
1389                 mtext_ins_char (ic->preedit, ic->cursor_pos++, name[0], 1);
1390             }
1391           ic->preedit_changed = 1;
1392         }
1393
1394       /* If this is the terminal map or we have shifted to another
1395          state, perform branch actions (if any).  */
1396       if (! map->submaps || map != ic_info->map)
1397         {
1398           if (map->branch_actions)
1399             {
1400               if (take_action_list (ic, map->branch_actions) < 0)
1401                 return -1;
1402             }
1403           /* If MAP is still not the root map, shift to the current
1404              state.  */
1405           if (ic_info->map != ic_info->state->map)
1406             shift_state (ic, ic_info->state->name);
1407         }
1408     }
1409   else
1410     {
1411       /* MAP can not handle KEY.  */
1412
1413       /* If MAP is the root map of the initial state, it means that
1414          the current input method can not handle KEY.  */
1415       if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
1416         return -1;
1417
1418       if (map != ic_info->state->map)
1419         {
1420           /* If MAP is not the root map... */
1421           /* If MAP has branch actions, perform them.  */
1422           if (map->branch_actions)
1423             take_action_list (ic, map->branch_actions);
1424           /* If MAP is still not the root map, shift to the current
1425              state. */
1426           if (ic_info->map != ic_info->state->map)
1427             {
1428               shift_state (ic, ic_info->state->name);
1429               /* If MAP has branch_actions, perform them.  */
1430               if (ic_info->map->branch_actions)
1431                 take_action_list (ic, ic_info->map->branch_actions);
1432             }
1433         }
1434       else
1435         {
1436           /* MAP is the root map, perform branch actions (if any) or
1437              shift to the initial state.  */
1438           if (map->branch_actions)
1439             take_action_list (ic, map->branch_actions);
1440           else
1441             shift_state (ic,
1442                          ((MIMState *) MPLIST_VAL (im_info->states))->name);
1443         }
1444     }
1445   return 0;
1446 }
1447
1448 static void
1449 reset_ic (MInputContext *ic)
1450 {
1451   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1452   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1453
1454   MLIST_RESET (ic_info);
1455   ic_info->state = (MIMState *) MPLIST_VAL (im_info->states);
1456   ic_info->map = ic_info->state->map;
1457   ic_info->state_key_head = ic_info->key_head = 0;
1458   ic->cursor_pos = ic_info->state_pos = 0;
1459   ic->status = ic_info->state->title;
1460   if (! ic->status)
1461     ic->status = im_info->title;
1462   ic->candidate_list = NULL;
1463   ic->candidate_show = 0;
1464   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 1;
1465   if (ic_info->map->map_actions)
1466     take_action_list (ic, ic_info->map->map_actions);
1467 }
1468
1469 static int
1470 open_im (MInputMethod *im)
1471 {
1472   MDatabase *mdb;
1473   MInputMethodInfo *im_info;
1474   MPlist *plist;
1475   int result;
1476
1477   mdb = mdatabase_find (Minput_method, im->language, im->name, Mnil);
1478   if (! mdb)
1479     return -1;
1480   plist = mdatabase_load (mdb);
1481   if (! plist)
1482     MERROR (MERROR_IM, -1);
1483   MSTRUCT_CALLOC (im_info, MERROR_IM);
1484   im->info = im_info;
1485   result = load_input_method (im->language, im->name, plist, im_info);
1486   M17N_OBJECT_UNREF (plist);
1487   if (result < 0)
1488     MERROR (MERROR_IM, -1);
1489   return 0;
1490 }
1491
1492 static void
1493 close_im (MInputMethod *im)
1494 {
1495   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
1496   MPlist *plist;
1497
1498   if (im_info->title)
1499     M17N_OBJECT_UNREF (im_info->title);
1500   if (im_info->states)
1501     {
1502       MPLIST_DO (plist, im_info->states)
1503         {
1504           MIMState *state = (MIMState *) MPLIST_VAL (plist);
1505
1506           if (state->title)
1507             M17N_OBJECT_UNREF (state->title);
1508           if (state->map)
1509             free_map (state->map);
1510           free (state);
1511         }
1512       M17N_OBJECT_UNREF (im_info->states);
1513     }
1514
1515   if (im_info->macros)
1516     {
1517       MPLIST_DO (plist, im_info->macros)
1518         M17N_OBJECT_UNREF (MPLIST_VAL (plist)); 
1519       M17N_OBJECT_UNREF (im_info->macros);
1520     }
1521
1522   if (im_info->externals)
1523     {
1524       MPLIST_DO (plist, im_info->externals)
1525         {
1526           MIMExternalModule *external = MPLIST_VAL (plist);
1527
1528           dlclose (external->handle);
1529           M17N_OBJECT_UNREF (external->func_list);
1530           free (external);
1531           MPLIST_KEY (plist) = Mt;
1532         }
1533       M17N_OBJECT_UNREF (im_info->externals);
1534     }
1535   free (im_info);
1536   im->info = NULL;
1537 }
1538
1539
1540 static int
1541 create_ic (MInputContext *ic)
1542 {
1543   MInputMethod *im = ic->im;
1544   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
1545   MInputContextInfo *ic_info;
1546
1547   if (ic->info)
1548     ic_info = (MInputContextInfo *) ic->info;
1549   else
1550     {
1551       MSTRUCT_CALLOC (ic_info, MERROR_IM);
1552       ic->info = ic_info;
1553     }
1554   MLIST_INIT1 (ic_info, keys, 8);
1555   ic_info->markers = mplist ();
1556   ic_info->vars = mplist ();
1557   ic_info->preedit_saved = mtext ();
1558   if (im_info->externals)
1559     {
1560       MPlist *func_args = mplist (), *plist;
1561
1562       mplist_add (func_args, Mt, ic);
1563       MPLIST_DO (plist, im_info->externals)
1564         {
1565           MIMExternalModule *external = MPLIST_VAL (plist);
1566           MIMExternalFunc func
1567             = (MIMExternalFunc) mplist_get (external->func_list, Minit);
1568
1569           if (func)
1570             (func) (func_args);
1571         }
1572       M17N_OBJECT_UNREF (func_args);
1573     }
1574   reset_ic (ic);
1575   return 0;
1576 }
1577
1578 static void
1579 destroy_ic (MInputContext *ic)
1580 {
1581   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1582   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1583
1584   if (im_info->externals)
1585     {
1586       MPlist *func_args = mplist (), *plist;
1587
1588       mplist_add (func_args, Mt, ic);
1589       MPLIST_DO (plist, im_info->externals)
1590         {
1591           MIMExternalModule *external = MPLIST_VAL (plist);
1592           MIMExternalFunc func
1593             = (MIMExternalFunc) mplist_get (external->func_list, Mfini);
1594
1595           if (func)
1596             (func) (func_args);
1597         }
1598       M17N_OBJECT_UNREF (func_args);
1599     }
1600   MLIST_FREE1 (ic_info, keys);
1601   M17N_OBJECT_UNREF (ic_info->preedit_saved);
1602   M17N_OBJECT_UNREF (ic_info->markers);
1603   M17N_OBJECT_UNREF (ic_info->vars);
1604   free (ic->info);
1605 }
1606
1607
1608 /** Handle the input key KEY in the current state and map of IC->info.
1609     If KEY is handled but no text is produced, return 0, otherwise
1610     return 1.
1611
1612     Ignore ARG.  */
1613
1614 static int
1615 filter (MInputContext *ic, MSymbol key, void *arg)
1616 {
1617   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1618   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1619   int i = 0;
1620
1621   mtext_reset (ic->produced);
1622   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
1623   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
1624   ic_info->key_unhandled = 0;
1625   do {
1626     if (handle_key (ic) < 0)
1627       {
1628         /* KEY was not handled.  Reset the status and break the
1629            loop.  */
1630         reset_ic (ic);
1631         /* This forces returning 1.  */
1632         ic_info->key_unhandled = 1;
1633         break;
1634       }
1635     if (i++ == 100)
1636       {
1637         mdebug_hook ();
1638         reset_ic (ic);
1639         ic_info->key_unhandled = 1;
1640         break;
1641       }
1642     /* Break the loop if all keys were handled.  */
1643   } while (ic_info->key_head < ic_info->used);
1644
1645   /* If the current map is the root of the initial state, we should
1646      produce any preedit text in ic->produced.  */
1647   if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map
1648       && mtext_nchars (ic->preedit) > 0)
1649     shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
1650
1651   if (mtext_nchars (ic->produced) > 0)
1652     {
1653       MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
1654
1655       if (lang != Mnil)
1656         mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
1657                         Mlanguage, ic->im->language);
1658     }
1659
1660   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
1661 }
1662
1663
1664 /** Return 1 if the last event or key was not handled, otherwise
1665     return 0.
1666
1667     There is no need of looking up because ic->produced should already
1668     contain the produced text (if any).
1669
1670     Ignore KEY.  */
1671
1672 static int
1673 lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
1674 {
1675   mtext_cat (mt, ic->produced);
1676   mtext_reset (ic->produced);
1677   return (((MInputContextInfo *) ic->info)->key_unhandled ? -1 : 0);
1678 }
1679
1680 /* Support functions for mdebug_dump_im.  */
1681
1682 static void
1683 dump_im_map (MPlist *map_list, int indent)
1684 {
1685   char *prefix;
1686   MSymbol key = MPLIST_KEY (map_list);
1687   MIMMap *map = (MIMMap *) MPLIST_VAL (map_list);
1688
1689   prefix = (char *) alloca (indent + 1);
1690   memset (prefix, 32, indent);
1691   prefix[indent] = '\0';
1692
1693   fprintf (stderr, "(\"%s\" ", msymbol_name (key));
1694   if (map->map_actions)
1695     mdebug_dump_plist (map->map_actions, indent + 2);
1696   if (map->submaps)
1697     {
1698       MPLIST_DO (map_list, map->submaps)
1699         {
1700           fprintf (stderr, "\n%s  ", prefix);
1701           dump_im_map (map_list, indent + 2);
1702         }
1703     }
1704   if (map->branch_actions)
1705     {
1706       fprintf (stderr, "\n%s  (branch\n%s    ", prefix, prefix);
1707       mdebug_dump_plist (map->branch_actions, indent + 4);
1708       fprintf (stderr, ")");      
1709     }
1710   fprintf (stderr, ")");
1711 }
1712
1713
1714 static void
1715 dump_im_state (MIMState *state, int indent)
1716 {
1717   char *prefix;
1718   MPlist *map_list;
1719
1720   prefix = (char *) alloca (indent + 1);
1721   memset (prefix, 32, indent);
1722   prefix[indent] = '\0';
1723
1724   fprintf (stderr, "(%s", msymbol_name (state->name));
1725   if (state->map->submaps)
1726     {
1727       MPLIST_DO (map_list, state->map->submaps)
1728         {
1729           fprintf (stderr, "\n%s  ", prefix);
1730           dump_im_map (map_list, indent + 2);
1731         }
1732     }
1733   fprintf (stderr, ")");
1734 }
1735
1736 \f
1737
1738 int
1739 minput__init ()
1740 {
1741   char *key_names[32]
1742     = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1743         "BackSpace", "Tab", "Linefeed", "Clear", NULL, "Return", NULL, NULL,
1744         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1745         NULL, NULL, NULL, "Escape", NULL, NULL, NULL, NULL };
1746   char buf[6], buf2[256];
1747   int i;
1748
1749   Minput_method = msymbol ("input-method");
1750   Minput_driver = msymbol ("input-driver");
1751   Mtitle = msymbol ("title");
1752   Mmacro = msymbol ("macro");
1753   Mmodule = msymbol ("module");
1754   Mmap = msymbol ("map");
1755   Mstate = msymbol ("state");
1756   Minsert = msymbol ("insert");
1757   Mdelete = msymbol ("delete");
1758   Mmove = msymbol ("move");
1759   Mmark = msymbol ("mark");
1760   Mpushback = msymbol ("pushback");
1761   Mundo = msymbol ("undo");
1762   Mcall = msymbol ("call");
1763   Mshift = msymbol ("shift");
1764   Mselect = msymbol ("select");
1765   Mshow = msymbol ("show");
1766   Mhide = msymbol ("hide");
1767   Mset = msymbol ("set");
1768   Madd = msymbol ("add");
1769   Msub = msymbol ("sub");
1770   Mmul = msymbol ("mul");
1771   Mdiv = msymbol ("div");
1772   Mequal = msymbol ("=");
1773   Mless = msymbol ("<");
1774   Mgreater = msymbol (">");
1775
1776   Minput_preedit_start = msymbol ("input-preedit-start");
1777   Minput_preedit_done = msymbol ("input-preedit-done");
1778   Minput_preedit_draw = msymbol ("input-preedit-draw");
1779   Minput_status_start = msymbol ("input-status-start");
1780   Minput_status_done = msymbol ("input-status-done");
1781   Minput_status_draw = msymbol ("input-status-draw");
1782   Minput_candidates_start = msymbol ("input-candidates-start");
1783   Minput_candidates_done = msymbol ("input-candidates-done");
1784   Minput_candidates_draw = msymbol ("input-candidates-draw");
1785   Minput_set_spot = msymbol ("input-set-spot");
1786   Minput_toggle = msymbol ("input-toggle");
1787
1788   Mcandidate_list = msymbol_as_managing_key ("  candidate-list");
1789   Mcandidate_index = msymbol ("  candidate-index");
1790
1791   Minit = msymbol ("init");
1792   Mfini = msymbol ("fini");
1793
1794   M_key_alias = msymbol ("  key-alias");
1795
1796   buf[0] = 'C';
1797   buf[1] = '-';
1798   buf[3] = '\0';
1799   for (i = 0, buf[2] = '@'; i < ' '; i++, buf[2]++)
1800     {
1801       one_char_symbol[i] = msymbol (buf);
1802       if (key_names[i])
1803         msymbol_put (one_char_symbol[i], M_key_alias,  msymbol (key_names[i]));
1804     }
1805   for (buf[2] = i; i < 127; i++, buf[2]++)
1806     one_char_symbol[i] = msymbol (buf + 2);
1807   one_char_symbol[i++] = msymbol ("Delete");
1808   buf[2] = 'M';
1809   buf[3] = '-';
1810   buf[5] = '\0';
1811   buf2[0] = 'M';
1812   buf2[1] = '-';
1813   for (buf[4] = '@'; i < 160; i++, buf[4]++)
1814     {
1815       one_char_symbol[i] = msymbol (buf);
1816       if (key_names[i - 128])
1817         {
1818           strcpy (buf2 + 2, key_names[i - 128]);
1819           msymbol_put (one_char_symbol[i], M_key_alias,  msymbol (buf2));
1820         }
1821     }
1822   for (buf[4] = i - 128; i < 255; i++, buf[4]++)
1823     one_char_symbol[i] = msymbol (buf + 2);
1824   one_char_symbol[i] = msymbol ("M-Delete");
1825
1826   minput_default_driver.open_im = open_im;
1827   minput_default_driver.close_im = close_im;
1828   minput_default_driver.create_ic = create_ic;
1829   minput_default_driver.destroy_ic = destroy_ic;
1830   minput_default_driver.filter = filter;
1831   minput_default_driver.lookup = lookup;
1832   minput_default_driver.callback_list = NULL;
1833   minput_driver = &minput_default_driver;
1834   return 0;
1835 }
1836
1837 void
1838 minput__fini ()
1839 {
1840   if (minput_default_driver.callback_list)
1841     {
1842       M17N_OBJECT_UNREF (minput_default_driver.callback_list);
1843       minput_default_driver.callback_list = NULL;
1844     }
1845   if (minput_driver->callback_list)
1846     {
1847       M17N_OBJECT_UNREF (minput_driver->callback_list);
1848       minput_driver->callback_list = NULL;
1849     }
1850 }
1851
1852 void
1853 minput__callback (MInputContext *ic, MSymbol command)
1854 {
1855   if (ic->im->driver.callback_list)
1856     {
1857       MInputCallbackFunc func
1858         = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list,
1859                                            command);
1860
1861       if (func)
1862         (func) (ic, command);
1863     }
1864 }
1865
1866 MSymbol
1867 minput__char_to_key (int c)
1868 {
1869   if (c < 0 || c >= 0x100)
1870     return Mnil;
1871
1872   return one_char_symbol[c];
1873 }
1874
1875 /*** @} */
1876 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1877
1878 \f
1879 /* External API */
1880
1881 /*** @addtogroup m17nInputMethod */
1882 /*** @{ */
1883 /*=*/
1884
1885 /***en
1886     @name Variables: Predefined symbols for callback commands.
1887
1888     These are the predefined symbols that are used as the @c COMMAND
1889     argument of callback functions of an input method driver (see
1890     #MInputDriver::callback_list).  */ 
1891 /***ja
1892     @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
1893
1894     ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Î¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ë¤ª¤¤¤Æ @c COMMAND °ú¿ô¤È¤·
1895     ¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë (#MInputDriver::callback_list »²¾È)¡£
1896       */ 
1897 /*** @{ */ 
1898 /*=*/
1899
1900 MSymbol Minput_preedit_start;
1901 MSymbol Minput_preedit_done;
1902 MSymbol Minput_preedit_draw;
1903 MSymbol Minput_status_start;
1904 MSymbol Minput_status_done;
1905 MSymbol Minput_status_draw;
1906 MSymbol Minput_candidates_start;
1907 MSymbol Minput_candidates_done;
1908 MSymbol Minput_candidates_draw;
1909 MSymbol Minput_set_spot;
1910 MSymbol Minput_toggle;
1911 /*** @} */
1912 /*=*/
1913
1914 /***en
1915     @brief The default driver for internal input methods.
1916
1917     The variable #minput_default_driver is the default driver for
1918     internal input methods.
1919
1920     The member MInputDriver::open_im () searches the m17n database for
1921     an input method that matches the tag \<#Minput_method, $LANGUAGE,
1922     $NAME\> and loads it.
1923
1924     The member MInputDriver::callback_list () is @c NULL.  Thus, it is
1925     programmers responsibility to set it to a plist of proper callback
1926     functions.  Otherwise, no feedback information (e.g. preedit text)
1927     can be shown to users.
1928
1929     The macro M17N_INIT () sets the variable #minput_driver to the
1930     pointer to this driver so that all internal input methods use it.
1931
1932     Therefore, unless @c minput_driver is set differently, the driver
1933     dependent arguments $ARG of the functions whose name begin with
1934     "minput_" are all ignored.  */
1935
1936 /***ja
1937     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð.
1938
1939     ÆþÎϥɥ饤¥Ð #minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë
1940     ¥È¤Î¥É¥é¥¤¥Ð¤Ç¤¢¤ë¡£
1941
1942     ¥á¥ó¥Ð MInputDriver::open_im () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é¥¿¥° 
1943     \<#Minput_method, $LANGUAGE, $NAME\> ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤òõ¤·¡¢
1944     ¤½¤ì¤ò¥í¡¼¥É¤¹¤ë¡£
1945
1946     ¥á¥ó¥Ð MInputDriver::callback_list () ¤Ï @c NULL ¤Ê¤Î¤Ç¡¢¥×¥í¥°¥é
1947     ¥Þ¦¤ÇÀÕǤ¤ò»ý¤Ã¤Æ, Å¬Àڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Î plist ¤ËÀßÄꤷ¤Ê¤¯¤Æ
1948     ¤Ï¤Ê¤é¤Ê¤¤¡£¤µ¤â¤Ê¤¤¤È¡¢preedit ¥Æ¥­¥¹¥È¤Ê¤É¤Î¥Õ¥£¡¼¥É¥Ð¥Ã¥¯¾ðÊó¤¬
1949     ¥æ¡¼¥¶¤Ëɽ¼¨¤µ¤ì¤Ê¤¤¡£
1950
1951     ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô #minput_driver ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó
1952     ¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
1953
1954     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
1955     ¤Ç»Ï¤Þ¤ë´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤¹¤Ù¤Æ̵»ë¤µ¤ì¤ë¡£  */
1956
1957 MInputDriver minput_default_driver;
1958 /*=*/
1959
1960 /***en
1961     @brief The driver for internal input methods.
1962
1963     The variable #minput_driver is a pointer to the input method
1964     driver that is used by internal input methods.  The macro
1965     M17N_INIT () initializes it to a pointer to #minput_default_driver
1966     (if <m17n.h> is included) or to #minput_gui_driver (if
1967     <m17n-gui.h> is included).  */ 
1968 /***ja
1969     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð.
1970
1971     ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á
1972     ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥íM17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó
1973     ¥¿¤ò #minput_default_driver (<m17n.h> ¤¬´Þ¤Þ¤ì¤ë»þ) ¤Þ¤¿¤Ï 
1974     #minput_gui_driver ( <m17n-gui.h> ¤¬´Þ¤Þ¤ì¤ë»þ) ¤Ë½é´ü²½¤¹¤ë¡£  */ 
1975
1976 MInputDriver *minput_driver;
1977
1978 MSymbol Minput_driver;
1979
1980 /*=*/
1981
1982 /***en
1983     @brief Open an input method.
1984
1985     The minput_open_im () function opens an input method that matches
1986     language $LANGUAGE and name $NAME, and returns a pointer to the
1987     input method object newly allocated.
1988
1989     This function at first decides an driver for the input method as
1990     below.
1991
1992     If $LANGUAGE is not #Mnil, the driver pointed by the variable
1993     #minput_driver is used.
1994
1995     If $LANGUAGE is #Mnil and $NAME has #Minput_driver property, the
1996     driver pointed to by the property value is used to open the input
1997     method.  If $NAME has no such property, @c NULL is returned.
1998
1999     Then, the member MInputDriver::open_im () of the driver is
2000     called.  
2001
2002     $ARG is set in the member @c arg of the structure MInputMethod so
2003     that the driver can refer to it.  */
2004
2005 /***ja
2006     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë.
2007
2008     ´Ø¿ô minput_open_im () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME ¤Ë¹çÃפ¹¤ëÆþ
2009     Îϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¥ª¥Ö¥¸¥§¥¯
2010     ¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
2011     
2012     ¤³¤Î´Ø¿ô¤Ï¡¢¤Þ¤ºÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤ò°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ·èÄꤹ¤ë¡£
2013
2014     $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô #minput_driver ¤Ç»Ø¤µ¤ì¤Æ¤¤¤ë
2015     ¥É¥é¥¤¥Ð¤òÍѤ¤¤ë¡£
2016
2017     $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver ¥×¥í¥Ñ¥Æ¥£¤ò»ý
2018     ¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǻؤµ¤ì¤Æ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþ
2019     Îϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£$NAME ¤Ë¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì
2020     ¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
2021
2022     ¼¡¤¤¤Ç¡¢¥É¥é¥¤¥Ð¤Î¥á¥ó¥Ð MInputDriver::open_im () ¤¬¸Æ¤Ð¤ì¤ë¡£
2023
2024     $ARG ¤Ï¡¢¥É¥é¥¤¥Ð¤¬»²¾È¤Ç¤­¤ë¤è¤¦¤Ë¡¢¹½Â¤ÂΠMInputMethod ¤Î¥á¥ó¥Ð 
2025     @c arg ¤ËÀßÄꤵ¤ì¤ë¡£
2026
2027     @latexonly \IPAlabel{minput_open} @endlatexonly
2028
2029 */
2030
2031 MInputMethod *
2032 minput_open_im (MSymbol language, MSymbol name, void *arg)
2033 {
2034   MInputMethod *im;
2035   MInputDriver *driver;
2036
2037   if (language)
2038     driver = minput_driver;
2039   else
2040     {
2041       driver = (MInputDriver *) msymbol_get (name, Minput_driver);
2042       if (! driver)
2043         MERROR (MERROR_IM, NULL);
2044     }
2045
2046   MSTRUCT_CALLOC (im, MERROR_IM);
2047   im->language = language;
2048   im->name = name;
2049   im->arg = arg;
2050   im->driver = *driver;
2051   if ((*im->driver.open_im) (im) < 0)
2052     {
2053       free (im);
2054       return NULL;
2055     }
2056   return im;
2057 }
2058
2059 /*=*/
2060
2061 /***en
2062     @brief Close an input method.
2063
2064     The minput_close_im () function closes the input method $IM, which
2065     must have been created by minput_open_im ().  */
2066
2067 /***ja
2068     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë.
2069
2070     ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£¤³¤Î
2071     ÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì
2072     ¤Ð¤Ê¤é¤Ê¤¤¡£  */
2073
2074 void
2075 minput_close_im (MInputMethod *im)
2076 {
2077   (*im->driver.close_im) (im);
2078   free (im);
2079 }
2080
2081 /*=*/
2082
2083 /***en
2084     @brief Create an input context.
2085
2086     The minput_create_ic () function creates an input context object
2087     associated with input method $IM, and calls callback functions
2088     corresponding to #Minput_preedit_start, #Minput_status_start, and
2089     #Minput_status_draw in this order.
2090
2091     @return
2092
2093     If an input context is successfully created, minput_create_ic ()
2094     returns a pointer to it.  Otherwise it returns @c NULL.  */
2095
2096 /***ja
2097     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë.
2098
2099     ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯
2100     ¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢ #Minput_preedit_start,
2101     #Minput_status_start, #Minput_status_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø
2102     ¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
2103
2104     @return
2105
2106     ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤¬À¸À®¤µ¤ì¤¿¾ì¹ç¡¢minput_create_ic () ¤Ï¤½¤ÎÆþÎÏ¥³
2107     ¥ó¥Æ¥¯¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
2108       */
2109
2110 MInputContext *
2111 minput_create_ic (MInputMethod *im, void *arg)
2112 {
2113   MInputContext *ic;
2114
2115   MSTRUCT_CALLOC (ic, MERROR_IM);
2116   ic->im = im;
2117   ic->arg = arg;
2118   ic->preedit = mtext ();
2119   ic->candidate_list = NULL;
2120   ic->produced = mtext ();
2121   ic->spot.x = ic->spot.y = 0;
2122   ic->active = 1;
2123   ic->plist = mplist ();
2124   if ((*im->driver.create_ic) (ic) < 0)
2125     {
2126       M17N_OBJECT_UNREF (ic->preedit);
2127       M17N_OBJECT_UNREF (ic->produced);
2128       M17N_OBJECT_UNREF (ic->plist);
2129       free (ic);
2130       return NULL;
2131     };
2132
2133   if (im->driver.callback_list)
2134     {
2135       minput__callback (ic, Minput_preedit_start);
2136       minput__callback (ic, Minput_status_start);
2137       minput__callback (ic, Minput_status_draw);
2138     }
2139
2140   return ic;
2141 }
2142
2143 /*=*/
2144
2145 /***en
2146     @brief Destroy an input context.
2147
2148     The minput_destroy_ic () function destroys the input context $IC,
2149     which must have been created by minput_create_ic ().  It calls
2150     callback functions corresponding to #Minput_preedit_done,
2151     #Minput_status_done, and #Mcandidate_done in this order.  */
2152
2153 /***ja
2154     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë.
2155
2156     ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£¤³
2157     ¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê
2158     ¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï#Minput_preedit_done,
2159     #Minput_status_done, #Mcandidate_done ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò
2160     ¤³¤Î½ç¤Ë¸Æ¤Ö¡£
2161   */
2162
2163 void
2164 minput_destroy_ic (MInputContext *ic)
2165 {
2166   if (ic->im->driver.callback_list)
2167     {
2168       minput__callback (ic, Minput_preedit_done);
2169       minput__callback (ic, Minput_status_done);
2170       minput__callback (ic, Minput_candidates_done);
2171     }
2172   (*ic->im->driver.destroy_ic) (ic);
2173   M17N_OBJECT_UNREF (ic->preedit);
2174   M17N_OBJECT_UNREF (ic->produced);
2175   M17N_OBJECT_UNREF (ic->plist);
2176   free (ic);
2177 }
2178
2179 /*=*/
2180
2181 /***en
2182     @brief Filter an input key.
2183
2184     The minput_filter () function filters input key $KEY according to
2185     input context $IC, and calls callback functions corresponding to
2186     #Minput_preedit_draw, #Minput_status_draw, and #Mcandidate_draw if
2187     the preedit text, the status, and the current candidate are
2188     changed respectively.
2189
2190     @return
2191     If $KEY is filtered out, this function returns 1.  In that case,
2192     the caller should discard the key.  Otherwise, it returns 0, and
2193     the caller should handle the key, for instance, by calling the
2194     function minput_lookup () with the same key.  */
2195
2196 /***ja
2197     @brief ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ë.
2198
2199     ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Ë±þ
2200     ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥­¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½
2201     ¤·¤¿ºÝ¤Ë¤Ï¤½¤ì¤¾¤ì#Minput_preedit_draw, #Minput_status_draw,
2202     #Mcandidate_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£
2203
2204     @return 
2205     $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¸Æ¤Ó
2206     ½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó
2207     ½Ð¤·Â¦¤Ï¡¢¤¿¤È¤¨¤ÐƱ¤¸¥­¡¼¤Ç´Ø¿ô minput_lookup () ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢
2208     ¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£
2209
2210     @latexonly \IPAlabel{minput_filter} @endlatexonly
2211 */
2212
2213 int
2214 minput_filter (MInputContext *ic, MSymbol key, void *arg)
2215 {
2216   int ret;
2217
2218   if (! ic
2219       || ! ic->active)
2220     return 0;
2221   ret = (*ic->im->driver.filter) (ic, key, arg);
2222
2223   if (ic->im->driver.callback_list)
2224     {
2225       if (ic->preedit_changed)
2226         minput__callback (ic, Minput_preedit_draw);
2227       if (ic->status_changed)
2228         minput__callback (ic, Minput_status_draw);
2229       if (ic->candidates_changed)
2230         minput__callback (ic, Minput_candidates_draw);
2231       ic->preedit_changed = ic->status_changed = ic->candidates_changed = 0;
2232     }
2233
2234   return ret;
2235 }
2236
2237 /*=*/
2238
2239 /***en
2240     @brief Lookup a text produced in the input context.
2241
2242     The minput_lookup () function looks up a text in the input context
2243     $IC.  $KEY must be the same one provided to the previous call of
2244     minput_filter ().
2245
2246     If a text was produced by the input method, it is concatenated
2247     to M-text $MT.
2248
2249     This function calls #MInputDriver::lookup.
2250
2251     @return
2252     If $KEY was correctly handled by the input method, this function
2253     returns 0.  Otherwise, returns -1, even in that case, some text
2254     may be produced in $MT.  */
2255
2256 /***ja
2257     @brief ÆþÎϥ᥽¥Ã¥É¤¬ºî¤Ã¤¿¥Æ¥­¥¹¥È¤Î¸¡º÷.
2258
2259     ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤ò¸¡º÷¤¹
2260     ¤ë¡£$KEY ¤Ï´Ø¿ôminput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î
2261     ¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2262
2263     ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥Æ¥­¥¹¥È¤Ï M-text
2264     $MT ¤ËÏ¢·ë¤µ¤ì¤ë¡£
2265
2266     ¤³¤Î´Ø¿ô¤Ï¡¢#MInputDriver::lookup ¤ò¸Æ¤Ö¡£
2267
2268     @return 
2269     $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤òÊÖ¤¹¡£
2270     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¤Ç¤â $MT ¤Ë²¿¤é¤«¤Î¥Æ¥­¥¹¥È¤¬À¸
2271     À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£
2272
2273     @latexonly \IPAlabel{minput_lookup} @endlatexonly  */
2274
2275 int
2276 minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
2277 {
2278   return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1);
2279 }
2280 /*=*/
2281
2282 /***en
2283     @brief Set the spot of the input context.
2284
2285     The minput_set_spot () function set the spot of input context $IC
2286     to coordinate ($X, $Y) with the height $ASCENT and $DESCENT.
2287     The semantics of these values depend on the input method driver.
2288     $FONTSIZE specfies the fontsize of a preedit text in 1/10 point.
2289
2290     For instance, an driver designed to work in CUI environment may
2291     use $X and $Y as column and row numbers, and ignore $ASCENT and
2292     $DESCENT.  An driver designed to work on a window system may treat
2293     $X and $Y as pixel offsets relative to the origin of the client
2294     window, and treat $ASCENT and $DESCENT as ascent and descent
2295     pixels of a line at ($X . $Y).
2296
2297     $MT and $POS is an M-text and a character position at the spot.
2298     $MT may be @c NULL, in which case, the input method cannot get
2299     information about the text around the spot.  */
2300
2301 /***ja
2302     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë
2303
2304     ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂ
2305     É¸ ($X, $Y)¤Ë ¡¢¹â¤µ $ASCENT¡¢$DESCENT ¤ÇÀßÄꤹ¤ë¡£ ¤³¤ì¤é¤ÎÃͤΰÕ
2306     Ì£¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë¡£$FONTSIZE ¤Ïpreedit ¥Æ¥­¥¹¥È¤Î
2307     ¥Õ¥©¥ó¥È¥µ¥¤¥º¤ò 1/10 ¥Ý¥¤¥ó¥Èñ°Ì¤Ç»ØÄꤹ¤ë¡£
2308
2309     ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ë¥É¥é¥¤¥Ð¤Ï $X, $Y ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô¤ÎÈÖ
2310     ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT¡¢$DESCENT ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿¥¦¥£
2311     ¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤΥɥ饤¥Ð¤Ï $X,$Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É¥¦¤Î
2312     ¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢$ASCENT 
2313     ¤È $DESCENT ¤ò ($X . $Y) ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯¥»¥ëñ°Ì
2314     ¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£  
2315
2316     $MT ¤È $POS ¤Ï¤½¤Î¥¹¥Ý¥Ã¥È¤Î M-text ¤Èʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$MT ¤Ï @c
2317     NULL ¤Ç¤â¤è¤¯¡¢¤½¤Î¾ì¹ç¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤Ï¥¹¥Ý¥Ã¥È¼þÊդΥƥ­¥¹¥È¤Ë
2318     ´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£
2319     */
2320
2321 void
2322 minput_set_spot (MInputContext *ic, int x, int y,
2323                  int ascent, int descent, int fontsize,
2324                  MText *mt, int pos)
2325 {
2326   ic->spot.x = x;
2327   ic->spot.y = y;
2328   ic->spot.ascent = ascent;
2329   ic->spot.descent = descent;
2330   ic->spot.fontsize = fontsize;
2331   ic->spot.mt = mt;
2332   ic->spot.pos = pos;
2333   if (ic->im->driver.callback_list)
2334     minput__callback (ic, Minput_set_spot);
2335 }
2336 /*=*/
2337
2338 /***en
2339     @brief Toggle input method.
2340
2341     The minput_toggle () function toggles the input method associated
2342     with the input context $IC.  */
2343 /***ja
2344     @brief ÆþÎϥ᥽¥Ã¥É¤òÀÚÂؤ¨¤ë.
2345
2346     ´Ø¿ô minput_toggle () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ËÂбþÉÕ¤±¤é¤ì¤¿ÆþÎÏ
2347     ¥á¥½¥Ã¥É¤ò¥È¥°¥ë¤¹¤ë¡£
2348     */
2349
2350 void
2351 minput_toggle (MInputContext *ic)
2352 {
2353   if (ic->im->driver.callback_list)
2354     minput__callback (ic, Minput_toggle);
2355   ic->active = ! ic->active;
2356 }
2357
2358
2359 /*** @} */
2360 /*=*/
2361 /*** @addtogroup m17nDebug */
2362 /*=*/
2363 /*** @{  */
2364 /*=*/
2365
2366 /***en
2367     @brief Dump an input method.
2368
2369     The mdebug_dump_im () function prints the input method $IM in a
2370     human readable way to the stderr.  $INDENT specifies how many
2371     columns to indent the lines but the first one.
2372
2373     @return
2374     This function returns $IM.  */
2375 /***ja
2376     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥À¥ó¥×¤¹¤ë.
2377
2378     ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ò stderr ¤Ë¿Í´Ö¤Ë²ÄÆɤÊ
2379     ·Á¤Ç°õºþ¤¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
2380
2381     @return
2382     ¤³¤Î´Ø¿ô¤Ï $IM ¤òÊÖ¤¹¡£  */
2383
2384 MInputMethod *
2385 mdebug_dump_im (MInputMethod *im, int indent)
2386 {
2387   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
2388   char *prefix;
2389
2390   prefix = (char *) alloca (indent + 1);
2391   memset (prefix, 32, indent);
2392   prefix[indent] = '\0';
2393
2394   fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
2395            msymbol_name (im->name));
2396   mdebug_dump_mtext (im_info->title, 0, 0);
2397   if (im->name != Mnil)
2398     {
2399       MPlist *state;
2400
2401       MPLIST_DO (state, im_info->states)
2402         {
2403           fprintf (stderr, "\n%s  ", prefix);
2404           dump_im_state (MPLIST_VAL (state), indent + 2);
2405         }
2406     }
2407   fprintf (stderr, ")");
2408   return im;
2409 }
2410
2411 /*** @} */ 
2412
2413 /*
2414   Local Variables:
2415   coding: euc-japan
2416   End:
2417 */