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