(reset_ic): Set key_unhandled to 0.
[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_nchars (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   for (; MPLIST_PLIST_P (plist); plist = MPLIST_NEXT (plist))
696     {
697       elt = MPLIST_PLIST (plist);
698       if (! MPLIST_SYMBOL_P (elt))
699         MERROR_GOTO (MERROR_IM, err);
700       if (MPLIST_SYMBOL (elt) == Mtitle)
701         {
702           elt = MPLIST_NEXT (elt);
703           if (MPLIST_MTEXT_P (elt))
704             {
705               title = MPLIST_MTEXT (elt);
706               M17N_OBJECT_REF (title);
707             }
708           else
709             MERROR_GOTO (MERROR_IM, err);
710         }
711       else if (MPLIST_SYMBOL (elt) == Mmap)
712         {
713           maps = mplist__from_alist (MPLIST_NEXT (elt));
714           if (! maps)
715             MERROR_GOTO (MERROR_IM, err);
716         }
717       else if (MPLIST_SYMBOL (elt) == Mmacro)
718         {
719           macros = mplist ();
720           MPLIST_DO (elt, MPLIST_NEXT (elt))
721           {
722             if (! MPLIST_PLIST_P (elt)
723                 || load_macros (MPLIST_PLIST (elt), macros) < 0)
724               MERROR_GOTO (MERROR_IM, err);
725           }
726         }
727       else if (MPLIST_SYMBOL (elt) == Mmodule)
728         {
729           externals = mplist ();
730           MPLIST_DO (elt, MPLIST_NEXT (elt))
731           {
732             if (! MPLIST_PLIST_P (elt)
733                 || load_external_module (MPLIST_PLIST (elt), externals) < 0)
734               MERROR_GOTO (MERROR_IM, err);
735           }
736         }
737       else if (MPLIST_SYMBOL (elt) == Mstate)
738         {
739           states = mplist ();
740           MPLIST_DO (elt, MPLIST_NEXT (elt))
741           {
742             MIMState *state;
743
744             if (! MPLIST_PLIST_P (elt))
745               MERROR_GOTO (MERROR_IM, err);
746             state = load_state (MPLIST_PLIST (elt), maps, language, macros);
747             if (! state)
748               MERROR_GOTO (MERROR_IM, err);
749             mplist_put (states, state->name, state);
750           }
751         }
752     }
753
754   if (maps)
755     {
756       MPLIST_DO (elt, maps)
757         M17N_OBJECT_UNREF (MPLIST_VAL (elt));
758       M17N_OBJECT_UNREF (maps);
759     }
760   if (! title)
761     title = mtext_from_data (MSYMBOL_NAME (name), MSYMBOL_NAMELEN (name),
762                              MTEXT_FORMAT_US_ASCII);
763   im_info->title = title;
764   im_info->externals = externals;
765   im_info->macros = macros;
766   im_info->states = states;
767   return 0;
768
769  err:
770   if (maps)
771     {
772       MPLIST_DO (elt, maps)
773         M17N_OBJECT_UNREF (MPLIST_VAL (elt));
774       M17N_OBJECT_UNREF (maps);
775     }
776   if (title)
777     M17N_OBJECT_UNREF (title);
778   if (states)
779     {
780       MPLIST_DO (plist, states)
781       {
782         MIMState *state = (MIMState *) MPLIST_VAL (plist);
783
784         if (state->title)
785           M17N_OBJECT_UNREF (state->title);
786         if (state->map)
787           free_map (state->map);
788         free (state);
789       }
790       M17N_OBJECT_UNREF (states);
791     }
792   if (externals)
793     {
794       MPLIST_DO (plist, externals)
795       {
796         MIMExternalModule *external = MPLIST_VAL (plist);
797
798         dlclose (external->handle);
799         M17N_OBJECT_UNREF (external->func_list);
800         free (external);
801         MPLIST_KEY (plist) = Mt;
802       }
803       M17N_OBJECT_UNREF (externals);
804     }
805   return -1;
806 }
807
808 \f
809
810 static int take_action_list (MInputContext *ic, MPlist *action_list);
811
812 static void
813 shift_state (MInputContext *ic, MSymbol state_name)
814 {
815   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
816   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
817   MIMState *state;
818
819   /* Find a state to shift to.  If not found, shift to the initial
820      state.  */
821   state = (MIMState *) mplist_get (im_info->states, state_name);
822   if (! state)
823     state = (MIMState *) MPLIST_VAL (im_info->states);
824
825   MDEBUG_PRINT1 ("\n[IM] state-shift (%s)", MSYMBOL_NAME (state->name));
826
827   /* Enter the new state.  */
828   ic_info->state = state;
829   ic_info->map = state->map;
830   ic_info->state_key_head = ic_info->key_head;
831   if (state == (MIMState *) MPLIST_VAL (im_info->states))
832     {
833       /* We have shifted to the initial state.  */
834       MPlist *p;
835
836       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
837                              Mcandidate_list, NULL, 0);
838       mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit),
839                              Mcandidate_index, NULL, 0);
840       mtext_cat (ic->produced, ic->preedit);
841       if ((mdebug__flag & mdebug_mask)
842           && mtext_nchars (ic->produced) > 0)
843         {
844           int i;
845
846           MDEBUG_PRINT (" (produced");
847             for (i = 0; i < mtext_nchars (ic->produced); i++)
848               MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->produced, i));
849           MDEBUG_PRINT (")");
850         }
851       mtext_reset (ic->preedit);
852       ic->candidate_list = NULL;
853       ic->candidate_show = 0;
854       ic->preedit_changed = ic->candidates_changed = 1;
855       MPLIST_DO (p, ic_info->markers)
856         MPLIST_VAL (p) = 0;
857       MPLIST_DO (p, ic_info->vars)
858         MPLIST_VAL (p) = 0;
859       ic->cursor_pos = 0;
860       memmove (ic_info->keys, ic_info->keys + ic_info->state_key_head,
861                sizeof (int) * (ic_info->used - ic_info->state_key_head));
862       ic_info->used -= ic_info->state_key_head;
863       ic_info->state_key_head = ic_info->key_head = 0;
864     }
865   mtext_cpy (ic_info->preedit_saved, ic->preedit);
866   ic_info->state_pos = ic->cursor_pos;
867   ic->status = state->title;
868   if (! ic->status)
869     ic->status = im_info->title;
870   ic->status_changed = 1;
871   if (ic_info->key_head == ic_info->used
872       && ic_info->map == ic_info->state->map
873       && ic_info->map->map_actions)
874     {
875       MDEBUG_PRINT (" init-actions:");
876       take_action_list (ic, ic_info->map->map_actions);
877     }
878 }
879
880 /* Find a candidate group that contains a candidate number INDEX from
881    PLIST.  Set START_INDEX to the first candidate number of the group,
882    END_INDEX to the last candidate number plus 1, GROUP_INDEX to the
883    candidate group number if they are non-NULL.  If INDEX is -1, find
884    the last candidate group.  */
885
886 static MPlist *
887 find_candidates_group (MPlist *plist, int index,
888                        int *start_index, int *end_index, int *group_index)
889 {
890   int i = 0, gidx = 0, len;
891
892   MPLIST_DO (plist, plist)
893     {
894       if (MPLIST_MTEXT_P (plist))
895         len = mtext_nchars (MPLIST_MTEXT (plist));
896       else
897         len = mplist_length (MPLIST_PLIST (plist));
898       if (index < 0 ? MPLIST_TAIL_P (MPLIST_NEXT (plist))
899           : i + len > index)
900         {
901           if (start_index)
902             *start_index = i;
903           if (end_index)
904             *end_index = i + len;
905           if (group_index)
906             *group_index = gidx;
907           return plist;
908         }
909       i += len;
910       gidx++;
911     }
912   return NULL;
913 }
914
915 static void
916 preedit_insert (MInputContext *ic, int pos, MText *mt, int c)
917 {
918   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
919   MPlist *markers;
920   int nchars = mt ? mtext_nchars (mt) : 1;
921
922   if (mt)
923     mtext_ins (ic->preedit, pos, mt);
924   else
925     mtext_ins_char (ic->preedit, pos, c, 1);
926   MPLIST_DO (markers, ic_info->markers)
927     if (MPLIST_INTEGER (markers) > pos)
928       MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + nchars);
929   if (ic->cursor_pos >= pos)
930     ic->cursor_pos += nchars;
931   ic->preedit_changed = 1;
932 }
933
934
935 static void
936 preedit_delete (MInputContext *ic, int from, int to)
937 {
938   MInputContextInfo *ic_info = ((MInputContext *) ic)->info;
939   MPlist *markers;
940
941   mtext_del (ic->preedit, from, to);
942   MPLIST_DO (markers, ic_info->markers)
943     {
944       if (MPLIST_INTEGER (markers) > to)
945         MPLIST_VAL (markers)
946           = (void *) (MPLIST_INTEGER (markers) - (to - from));
947       else if (MPLIST_INTEGER (markers) > from);
948         MPLIST_VAL (markers) = (void *) from;
949     }
950   if (ic->cursor_pos >= to)
951     ic->cursor_pos -= to - from;
952   else if (ic->cursor_pos > from)
953     ic->cursor_pos = from;
954   ic->preedit_changed = 1;
955 }
956
957
958 static int
959 new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt)
960 {
961   int code = marker_code (sym);
962
963   if (mt && (code == '[' || code == ']'))
964     {
965       int pos = current;
966
967       if (code == '[' && current > 0)
968         {
969           if (mtext_prop_range (mt, Mcandidate_list, pos - 1, &pos, NULL, 1)
970               && pos > 0)
971             current = pos;
972         }
973       else if (code == ']' && current < mtext_nchars (mt))
974         {
975           if (mtext_prop_range (mt, Mcandidate_list, pos, NULL, &pos, 1))
976             current = pos;
977         }
978       return current;
979     }
980   if (code >= 0)
981     return (code == '<' ? 0
982             : code == '>' ? limit
983             : code == '-' ? current - 1
984             : code == '+' ? current + 1
985             : code == '=' ? current
986             : code - '0' > limit ? limit
987             : code - '0');
988   if (! ic)  
989     return 0;
990   return (int) mplist_get (((MInputContextInfo *) ic->info)->markers, sym);
991 }
992
993 static void
994 update_candidate (MInputContext *ic, MTextProperty *prop, int idx)
995 {
996   int from = mtext_property_start (prop);
997   int to = mtext_property_end (prop);
998   int start;
999   MPlist *candidate_list = mtext_property_value (prop);
1000   MPlist *group = find_candidates_group (candidate_list, idx, &start,
1001                                          NULL, NULL);
1002   int ingroup_index = idx - start;
1003   MText *mt;
1004
1005   preedit_delete (ic, from, to);
1006   if (MPLIST_MTEXT_P (group))
1007     {
1008       mt = MPLIST_MTEXT (group);
1009       preedit_insert (ic, from, NULL, mtext_ref_char (mt, ingroup_index));
1010       to = from + 1;
1011     }
1012   else
1013     {
1014       int i;
1015       MPlist *plist;
1016
1017       for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
1018            i++, plist = MPLIST_NEXT (plist));
1019       mt = MPLIST_MTEXT (plist);
1020       preedit_insert (ic, from, mt, 0);
1021       to = from + mtext_nchars (mt);
1022     }
1023   mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
1024   mtext_put_prop (ic->preedit, from, to, Mcandidate_index, (void *) idx);
1025   ic->cursor_pos = to;
1026 }
1027
1028
1029 static int
1030 take_action_list (MInputContext *ic, MPlist *action_list)
1031 {
1032   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1033   MPlist *candidate_list = ic->candidate_list;
1034   int candidate_index = ic->candidate_index;
1035   int candidate_show = ic->candidate_show;
1036   MTextProperty *prop;
1037
1038   MPLIST_DO (action_list, action_list)
1039     {
1040       MPlist *action;
1041       MSymbol name;
1042       MPlist *args;
1043
1044       if (MPLIST_MTEXT_P (action_list)
1045           || MPLIST_INTEGER_P (action_list))
1046         name = Minsert, args = action_list;
1047       else if (MPLIST_PLIST_P (action_list)
1048                && (MPLIST_MTEXT_P (MPLIST_PLIST (action_list))
1049                    || MPLIST_PLIST_P (MPLIST_PLIST (action_list))))
1050         name = Minsert, args = action_list;
1051       else
1052         {
1053           action = MPLIST_PLIST (action_list);
1054           name = MPLIST_SYMBOL (action);
1055           args = MPLIST_NEXT (action);
1056         }
1057
1058       MDEBUG_PRINT1 (" %s", MSYMBOL_NAME (name));
1059       if (name == Minsert)
1060         {
1061           if (MPLIST_MTEXT_P (args))
1062             preedit_insert (ic, ic->cursor_pos, MPLIST_MTEXT (args), 0);
1063           else if (MPLIST_INTEGER_P (args))
1064             preedit_insert (ic, ic->cursor_pos, NULL, MPLIST_INTEGER (args));
1065           else if (MPLIST_SYMBOL_P (args))
1066             {
1067               int c = integer_value (ic, args);
1068
1069               if (c >= 0 && c <= MCHAR_MAX)
1070                 preedit_insert (ic, ic->cursor_pos, NULL, c);
1071             }
1072           else
1073             {
1074               MText *mt;
1075               int len;
1076
1077               args = MPLIST_PLIST (args);
1078               if (MPLIST_MTEXT_P (args))
1079                 {
1080                   preedit_insert (ic, ic->cursor_pos, NULL,
1081                                   mtext_ref_char (MPLIST_MTEXT (args), 0));
1082                   len = 1;
1083                 }
1084               else
1085                 {
1086                   mt = MPLIST_MTEXT (MPLIST_PLIST (args));
1087                   preedit_insert (ic, ic->cursor_pos, mt, 0);
1088                   len = mtext_nchars (mt);
1089                 }
1090               mtext_put_prop (ic->preedit,
1091                               ic->cursor_pos - len, ic->cursor_pos,
1092                               Mcandidate_list, args);
1093               mtext_put_prop (ic->preedit,
1094                               ic->cursor_pos - len, ic->cursor_pos,
1095                               Mcandidate_index, (void *) 0);
1096             }
1097         }
1098       else if (name == Mselect)
1099         {
1100           int start, end;
1101           int code, idx, gindex;
1102           int pos = ic->cursor_pos;
1103           MPlist *group;
1104
1105           if (pos == 0
1106               || ! (prop = mtext_get_property (ic->preedit, pos - 1,
1107                                                Mcandidate_list)))
1108             continue;
1109           if (MPLIST_SYMBOL_P (args))
1110             {
1111               code = marker_code (MPLIST_SYMBOL (args));
1112               if (code < 0)
1113                 continue;
1114             }
1115           else
1116             code = -1;
1117           idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
1118           group = find_candidates_group (mtext_property_value (prop), idx,
1119                                          &start, &end, &gindex);
1120
1121           if (code != '[' && code != ']')
1122             {
1123               idx = (start
1124                      + (code >= 0
1125                         ? new_index (NULL, ic->candidate_index - start,
1126                                      end - start - 1, MPLIST_SYMBOL (args),
1127                                      NULL)
1128                         : MPLIST_INTEGER (args)));
1129               if (idx < 0)
1130                 {
1131                   find_candidates_group (mtext_property_value (prop), -1,
1132                                          NULL, &end, NULL);
1133                   idx = end - 1;
1134                 }
1135               else if (idx >= end
1136                        && MPLIST_TAIL_P (MPLIST_NEXT (group)))
1137                 idx = 0;
1138             }
1139           else
1140             {
1141               int ingroup_index = idx - start;
1142               int len;
1143
1144               group = mtext_property_value (prop);
1145               len = mplist_length (group);
1146               if (code == '[')
1147                 {
1148                   gindex--;
1149                   if (gindex < 0)
1150                     gindex = len - 1;;
1151                 }
1152               else
1153                 {
1154                   gindex++;
1155                   if (gindex >= len)
1156                     gindex = 0;
1157                 }
1158               for (idx = 0; gindex > 0; gindex--, group = MPLIST_NEXT (group))
1159                 idx += (MPLIST_MTEXT_P (group)
1160                         ? mtext_nchars (MPLIST_MTEXT (group))
1161                         : mplist_length (MPLIST_PLIST (group)));
1162               len = (MPLIST_MTEXT_P (group)
1163                      ? mtext_nchars (MPLIST_MTEXT (group))
1164                      : mplist_length (MPLIST_PLIST (group)));
1165               if (ingroup_index >= len)
1166                 ingroup_index = len - 1;
1167               idx += ingroup_index;
1168             }
1169           update_candidate (ic, prop, idx);
1170         }
1171       else if (name == Mshow)
1172         ic->candidate_show = 1;
1173       else if (name == Mhide)
1174         ic->candidate_show = 0;
1175       else if (name == Mdelete)
1176         {
1177           int len = mtext_nchars (ic->preedit);
1178           int to = (MPLIST_SYMBOL_P (args)
1179                     ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
1180                                  ic->preedit)
1181                     : MPLIST_INTEGER (args));
1182
1183           if (to < 0)
1184             to = 0;
1185           else if (to > len)
1186             to = len;
1187           if (to < ic->cursor_pos)
1188             preedit_delete (ic, to, ic->cursor_pos);
1189           else if (to > ic->cursor_pos)
1190             preedit_delete (ic, ic->cursor_pos, to);
1191         }
1192       else if (name == Mmove)
1193         {
1194           int len = mtext_nchars (ic->preedit);
1195           int pos
1196             = (MPLIST_SYMBOL_P (args)
1197                ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
1198                             ic->preedit)
1199                : MPLIST_INTEGER (args));
1200
1201           if (pos < 0)
1202             pos = 0;
1203           else if (pos > len)
1204             pos = len;
1205           if (pos != ic->cursor_pos)
1206             {
1207               ic->cursor_pos = pos;
1208               ic->preedit_changed = 1;
1209             }
1210         }
1211       else if (name == Mmark)
1212         {
1213           int code = marker_code (MPLIST_SYMBOL (args));
1214
1215           if (code < 0)
1216             mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
1217                         (void *) ic->cursor_pos);
1218         }
1219       else if (name == Mpushback)
1220         {
1221           int num = MPLIST_INTEGER (args);
1222
1223           if (num > 0)
1224             ic_info->key_head -= num;
1225           else
1226             ic_info->key_head = num;
1227           if (ic_info->key_head > ic_info->used)
1228             ic_info->key_head = ic_info->used;
1229         }
1230       else if (name == Mcall)
1231         {
1232           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1233           MIMExternalFunc func = NULL;
1234           MSymbol module, func_name;
1235           MPlist *func_args, *val;
1236           int ret = 0;
1237
1238           module = MPLIST_SYMBOL (args);
1239           args = MPLIST_NEXT (args);
1240           func_name = MPLIST_SYMBOL (args);
1241
1242           if (im_info->externals)
1243             {
1244               MIMExternalModule *external
1245                 = (MIMExternalModule *) mplist_get (im_info->externals,
1246                                                     module);
1247               if (external)
1248                 func = (MIMExternalFunc) mplist_get (external->func_list,
1249                                                      func_name);
1250             }
1251           if (! func)
1252             continue;
1253           func_args = mplist ();
1254           mplist_add (func_args, Mt, ic);
1255           MPLIST_DO (args, MPLIST_NEXT (args))
1256             {
1257               int code;
1258
1259               if (MPLIST_KEY (args) == Msymbol
1260                   && MPLIST_KEY (args) != Mnil
1261                   && (code = marker_code (MPLIST_SYMBOL (args))) >= 0)
1262                 {
1263                   code = new_index (ic, ic->cursor_pos, 
1264                                     mtext_nchars (ic->preedit),
1265                                     MPLIST_SYMBOL (args), ic->preedit);
1266                   mplist_add (func_args, Minteger, (void *) code);
1267                 }
1268               else
1269                 mplist_add (func_args, MPLIST_KEY (args), MPLIST_VAL (args));
1270             }
1271           val = (func) (func_args);
1272           M17N_OBJECT_UNREF (func_args);
1273           if (val && ! MPLIST_TAIL_P (val))
1274             ret = take_action_list (ic, val);
1275           M17N_OBJECT_UNREF (val);
1276           if (ret < 0)
1277             return ret;
1278         }
1279       else if (name == Mshift)
1280         {
1281           shift_state (ic, MPLIST_SYMBOL (args));
1282         }
1283       else if (name == Mundo)
1284         {
1285           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1286           int unhandle = 0;
1287
1288           mtext_reset (ic->preedit);
1289           mtext_reset (ic_info->preedit_saved);
1290           ic->cursor_pos = ic_info->state_pos = 0;
1291           ic_info->state_key_head = ic_info->key_head = 0;
1292           ic_info->used -= 2;
1293           if (ic_info->used < 0)
1294             {
1295               ic_info->used = 0;
1296               unhandle = 1;
1297             }
1298           shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
1299           if (unhandle)
1300             return -1;
1301           break;
1302         }
1303       else if (name == Mset || name == Madd || name == Msub
1304                || name == Mmul || name == Mdiv)
1305         {
1306           MSymbol sym = MPLIST_SYMBOL (args);
1307           int val1 = (int) mplist_get (ic_info->vars, sym), val2;
1308
1309           args = MPLIST_NEXT (args);
1310           val2 = integer_value (ic, args);
1311           if (name == Mset)
1312             val1 = val2;
1313           else if (name == Madd)
1314             val1 += val2;
1315           else if (name == Msub)
1316             val1 -= val2;
1317           else if (name == Mmul)
1318             val1 *= val2;
1319           else
1320             val1 /= val2;
1321           mplist_put (ic_info->vars, sym, (void *) val1);
1322           MDEBUG_PRINT2 ("(%s=%d)", MSYMBOL_NAME (sym), val1);
1323         }
1324       else if (name == Mequal || name == Mless || name == Mgreater)
1325         {
1326           int val1, val2;
1327           MPlist *actions1, *actions2;
1328           int ret = 0;
1329
1330           val1 = integer_value (ic, args);
1331           args = MPLIST_NEXT (args);
1332           val2 = integer_value (ic, args);
1333           args = MPLIST_NEXT (args);
1334           actions1 = MPLIST_PLIST (args);
1335           args = MPLIST_NEXT (args);
1336           if (MPLIST_TAIL_P (args))
1337             actions2 = NULL;
1338           else
1339             actions2 = MPLIST_PLIST (args);
1340           if (name == Mequal ? val1 == val2
1341               : name == Mless ? val1 < val2
1342               : val1 > val2)
1343             ret = take_action_list (ic, actions1);
1344           else if (actions2)
1345             ret = take_action_list (ic, actions2);
1346           if (ret < 0)
1347             return ret;
1348         }
1349       else
1350         {
1351           MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1352           MPlist *actions;
1353
1354           if (im_info->macros
1355               && (actions = mplist_get (im_info->macros, name)))
1356             {
1357               if (take_action_list (ic, actions) < 0)
1358                 return -1;
1359             };
1360         }
1361     }
1362
1363   prop = NULL;
1364   ic->candidate_list = NULL;
1365   if (ic->cursor_pos > 0
1366       && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
1367                                      Mcandidate_list)))
1368     {
1369       ic->candidate_list = mtext_property_value (prop);
1370       ic->candidate_index
1371         = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
1372                                 Mcandidate_index);
1373       ic->candidate_from = mtext_property_start (prop);
1374       ic->candidate_to = mtext_property_end (prop);
1375     }
1376
1377   ic->candidates_changed |= (candidate_list != ic->candidate_list
1378                              || candidate_index != ic->candidate_index
1379                              || candidate_show != ic->candidate_show);
1380   return 0;
1381 }
1382
1383
1384 /* Handle the input key KEY in the current state and map specified in
1385    the input context IC.  If KEY is handled correctly, return 0.
1386    Otherwise, return -1.  */
1387
1388 static int
1389 handle_key (MInputContext *ic)
1390 {
1391   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1392   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1393   MIMMap *map = ic_info->map;
1394   MIMMap *submap = NULL;
1395   MSymbol key = ic_info->keys[ic_info->key_head];
1396   int i;
1397
1398   MDEBUG_PRINT2 ("[IM] handle `%s' in state %s", 
1399                  MSYMBOL_NAME (key), MSYMBOL_NAME (ic_info->state->name));
1400
1401   if (map->submaps)
1402     {
1403       submap = mplist_get (map->submaps, key);
1404       if (! submap && (key = msymbol_get (key, M_key_alias)) != Mnil)
1405         submap = mplist_get (map->submaps, key);
1406     }
1407
1408   if (submap)
1409     {
1410       MDEBUG_PRINT (" submap-found");
1411       mtext_cpy (ic->preedit, ic_info->preedit_saved);
1412       ic->cursor_pos = ic_info->state_pos;
1413       ic_info->key_head++;
1414       ic_info->map = map = submap;
1415       if (map->map_actions)
1416         {
1417           MDEBUG_PRINT (" map-actions:");
1418           if (take_action_list (ic, map->map_actions) < 0)
1419             return -1;
1420         }
1421       else if (map->submaps)
1422         {
1423           for (i = ic_info->state_key_head; i < ic_info->key_head; i++)
1424             {
1425               MSymbol key = ic_info->keys[i];
1426               char *name = msymbol_name (key);
1427
1428               if (! name[0] || ! name[1])
1429                 mtext_ins_char (ic->preedit, ic->cursor_pos++, name[0], 1);
1430             }
1431           ic->preedit_changed = 1;
1432         }
1433
1434       /* If this is the terminal map or we have shifted to another
1435          state, perform branch actions (if any).  */
1436       if (! map->submaps || map != ic_info->map)
1437         {
1438           if (map->branch_actions)
1439             {
1440               MDEBUG_PRINT (" branch-actions:");
1441               if (take_action_list (ic, map->branch_actions) < 0)
1442                 return -1;
1443             }
1444           /* If MAP is still not the root map, shift to the current
1445              state.  */
1446           if (ic_info->map != ic_info->state->map)
1447             shift_state (ic, ic_info->state->name);
1448         }
1449       MDEBUG_PRINT ("\n");
1450     }
1451   else
1452     {
1453       /* MAP can not handle KEY.  */
1454
1455       /* If MAP is the root map of the initial state, it means that
1456          the current input method can not handle KEY.  */
1457       if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
1458         {
1459           MDEBUG_PRINT (" unhandled\n");
1460           return -1;
1461         }
1462
1463       if (map != ic_info->state->map)
1464         {
1465           /* If MAP is not the root map... */
1466           /* If MAP has branch actions, perform them.  */
1467           if (map->branch_actions)
1468             {
1469               MDEBUG_PRINT (" branch-actions:");
1470               take_action_list (ic, map->branch_actions);
1471             }
1472           /* If MAP is still not the root map, shift to the current
1473              state. */
1474           if (ic_info->map != ic_info->state->map)
1475             {
1476               shift_state (ic, ic_info->state->name);
1477               /* If MAP has branch_actions, perform them.  */
1478               if (ic_info->map->branch_actions)
1479                 {
1480                   MDEBUG_PRINT (" init-actions:");
1481                   take_action_list (ic, ic_info->map->branch_actions);
1482                 }
1483             }
1484         }
1485       else
1486         {
1487           /* MAP is the root map, perform branch actions (if any) or
1488              shift to the initial state.  */
1489           if (map->branch_actions)
1490             {
1491               MDEBUG_PRINT (" branch-actions:");
1492               take_action_list (ic, map->branch_actions);
1493             }
1494           else
1495             shift_state (ic,
1496                          ((MIMState *) MPLIST_VAL (im_info->states))->name);
1497         }
1498       MDEBUG_PRINT ("\n");
1499     }
1500   return 0;
1501 }
1502
1503 static void
1504 reset_ic (MInputContext *ic, MSymbol ignore)
1505 {
1506   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1507   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1508
1509   if (im_info->states)
1510     /* Shift to the initial state.  */
1511     shift_state (ic, Mnil);
1512   else
1513     ic_info->state = NULL;
1514   MLIST_RESET (ic_info);
1515   ic_info->map = ic_info->state ? ic_info->state->map : NULL;
1516   ic_info->state_key_head = ic_info->key_head = 0;
1517   ic_info->key_unhandled = 0;
1518   ic->cursor_pos = ic_info->state_pos = 0;
1519   ic->status = ic_info->state ? ic_info->state->title : NULL;
1520   if (! ic->status)
1521     ic->status = im_info->title;
1522   ic->candidate_list = NULL;
1523   ic->candidate_show = 0;
1524   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 1;
1525   if (ic_info->map && ic_info->map->map_actions)
1526     take_action_list (ic, ic_info->map->map_actions);
1527 }
1528
1529 static int
1530 open_im (MInputMethod *im)
1531 {
1532   MDatabase *mdb;
1533   MInputMethodInfo *im_info;
1534   MPlist *plist;
1535   int result;
1536
1537   mdb = mdatabase_find (Minput_method, im->language, im->name, Mnil);
1538   if (! mdb)
1539     return -1;
1540   plist = mdatabase_load (mdb);
1541   if (! plist)
1542     MERROR (MERROR_IM, -1);
1543   MSTRUCT_CALLOC (im_info, MERROR_IM);
1544   im->info = im_info;
1545   result = load_input_method (im->language, im->name, plist, im_info);
1546   M17N_OBJECT_UNREF (plist);
1547   if (result < 0)
1548     MERROR (MERROR_IM, -1);
1549   return 0;
1550 }
1551
1552 static void
1553 close_im (MInputMethod *im)
1554 {
1555   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
1556   MPlist *plist;
1557
1558   if (im_info->title)
1559     M17N_OBJECT_UNREF (im_info->title);
1560   if (im_info->states)
1561     {
1562       MPLIST_DO (plist, im_info->states)
1563         {
1564           MIMState *state = (MIMState *) MPLIST_VAL (plist);
1565
1566           if (state->title)
1567             M17N_OBJECT_UNREF (state->title);
1568           if (state->map)
1569             free_map (state->map);
1570           free (state);
1571         }
1572       M17N_OBJECT_UNREF (im_info->states);
1573     }
1574
1575   if (im_info->macros)
1576     {
1577       MPLIST_DO (plist, im_info->macros)
1578         M17N_OBJECT_UNREF (MPLIST_VAL (plist)); 
1579       M17N_OBJECT_UNREF (im_info->macros);
1580     }
1581
1582   if (im_info->externals)
1583     {
1584       MPLIST_DO (plist, im_info->externals)
1585         {
1586           MIMExternalModule *external = MPLIST_VAL (plist);
1587
1588           dlclose (external->handle);
1589           M17N_OBJECT_UNREF (external->func_list);
1590           free (external);
1591           MPLIST_KEY (plist) = Mt;
1592         }
1593       M17N_OBJECT_UNREF (im_info->externals);
1594     }
1595   free (im_info);
1596   im->info = NULL;
1597 }
1598
1599
1600 static int
1601 create_ic (MInputContext *ic)
1602 {
1603   MInputMethod *im = ic->im;
1604   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
1605   MInputContextInfo *ic_info;
1606
1607   if (ic->info)
1608     ic_info = (MInputContextInfo *) ic->info;
1609   else
1610     {
1611       MSTRUCT_CALLOC (ic_info, MERROR_IM);
1612       ic->info = ic_info;
1613     }
1614   MLIST_INIT1 (ic_info, keys, 8);
1615   ic_info->markers = mplist ();
1616   ic_info->vars = mplist ();
1617   ic_info->preedit_saved = mtext ();
1618   if (im_info->externals)
1619     {
1620       MPlist *func_args = mplist (), *plist;
1621
1622       mplist_add (func_args, Mt, ic);
1623       MPLIST_DO (plist, im_info->externals)
1624         {
1625           MIMExternalModule *external = MPLIST_VAL (plist);
1626           MIMExternalFunc func
1627             = (MIMExternalFunc) mplist_get (external->func_list, Minit);
1628
1629           if (func)
1630             (func) (func_args);
1631         }
1632       M17N_OBJECT_UNREF (func_args);
1633     }
1634   reset_ic (ic, Mnil);
1635   return 0;
1636 }
1637
1638 static void
1639 destroy_ic (MInputContext *ic)
1640 {
1641   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1642   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1643
1644   if (im_info->externals)
1645     {
1646       MPlist *func_args = mplist (), *plist;
1647
1648       mplist_add (func_args, Mt, ic);
1649       MPLIST_DO (plist, im_info->externals)
1650         {
1651           MIMExternalModule *external = MPLIST_VAL (plist);
1652           MIMExternalFunc func
1653             = (MIMExternalFunc) mplist_get (external->func_list, Mfini);
1654
1655           if (func)
1656             (func) (func_args);
1657         }
1658       M17N_OBJECT_UNREF (func_args);
1659     }
1660   MLIST_FREE1 (ic_info, keys);
1661   M17N_OBJECT_UNREF (ic_info->preedit_saved);
1662   M17N_OBJECT_UNREF (ic_info->markers);
1663   M17N_OBJECT_UNREF (ic_info->vars);
1664   free (ic->info);
1665 }
1666
1667
1668 /** Handle the input key KEY in the current state and map of IC->info.
1669     If KEY is handled but no text is produced, return 0, otherwise
1670     return 1.
1671
1672     Ignore ARG.  */
1673
1674 static int
1675 filter (MInputContext *ic, MSymbol key, void *arg)
1676 {
1677   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1678   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1679   int i = 0;
1680
1681   if (! ic_info->state)
1682     {
1683       ic_info->key_unhandled = 1;
1684       return 0;
1685     }
1686   mtext_reset (ic->produced);
1687   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
1688   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
1689   ic_info->key_unhandled = 0;
1690   do {
1691     if (handle_key (ic) < 0)
1692       {
1693         /* KEY was not handled.  Reset the status and break the
1694            loop.  */
1695         reset_ic (ic, Mnil);
1696         /* This forces returning 1.  */
1697         ic_info->key_unhandled = 1;
1698         break;
1699       }
1700     if (i++ == 100)
1701       {
1702         mdebug_hook ();
1703         reset_ic (ic, Mnil);
1704         ic_info->key_unhandled = 1;
1705         break;
1706       }
1707     /* Break the loop if all keys were handled.  */
1708   } while (ic_info->key_head < ic_info->used);
1709
1710   /* If the current map is the root of the initial state, we should
1711      produce any preedit text in ic->produced.  */
1712   if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map
1713       && mtext_nchars (ic->preedit) > 0)
1714     shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
1715
1716   if (mtext_nchars (ic->produced) > 0)
1717     {
1718       MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
1719
1720       if (lang != Mnil)
1721         mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
1722                         Mlanguage, ic->im->language);
1723     }
1724
1725   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
1726 }
1727
1728
1729 /** Return 1 if the last event or key was not handled, otherwise
1730     return 0.
1731
1732     There is no need of looking up because ic->produced should already
1733     contain the produced text (if any).
1734
1735     Ignore KEY.  */
1736
1737 static int
1738 lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
1739 {
1740   mtext_cat (mt, ic->produced);
1741   mtext_reset (ic->produced);
1742   return (((MInputContextInfo *) ic->info)->key_unhandled ? -1 : 0);
1743 }
1744
1745 /* Support functions for mdebug_dump_im.  */
1746
1747 static void
1748 dump_im_map (MPlist *map_list, int indent)
1749 {
1750   char *prefix;
1751   MSymbol key = MPLIST_KEY (map_list);
1752   MIMMap *map = (MIMMap *) MPLIST_VAL (map_list);
1753
1754   prefix = (char *) alloca (indent + 1);
1755   memset (prefix, 32, indent);
1756   prefix[indent] = '\0';
1757
1758   fprintf (stderr, "(\"%s\" ", msymbol_name (key));
1759   if (map->map_actions)
1760     mdebug_dump_plist (map->map_actions, indent + 2);
1761   if (map->submaps)
1762     {
1763       MPLIST_DO (map_list, map->submaps)
1764         {
1765           fprintf (stderr, "\n%s  ", prefix);
1766           dump_im_map (map_list, indent + 2);
1767         }
1768     }
1769   if (map->branch_actions)
1770     {
1771       fprintf (stderr, "\n%s  (branch\n%s    ", prefix, prefix);
1772       mdebug_dump_plist (map->branch_actions, indent + 4);
1773       fprintf (stderr, ")");      
1774     }
1775   fprintf (stderr, ")");
1776 }
1777
1778
1779 static void
1780 dump_im_state (MIMState *state, int indent)
1781 {
1782   char *prefix;
1783   MPlist *map_list;
1784
1785   prefix = (char *) alloca (indent + 1);
1786   memset (prefix, 32, indent);
1787   prefix[indent] = '\0';
1788
1789   fprintf (stderr, "(%s", msymbol_name (state->name));
1790   if (state->map->submaps)
1791     {
1792       MPLIST_DO (map_list, state->map->submaps)
1793         {
1794           fprintf (stderr, "\n%s  ", prefix);
1795           dump_im_map (map_list, indent + 2);
1796         }
1797     }
1798   fprintf (stderr, ")");
1799 }
1800
1801 \f
1802
1803 int
1804 minput__init ()
1805 {
1806   char *key_names[32]
1807     = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1808         "BackSpace", "Tab", "Linefeed", "Clear", NULL, "Return", NULL, NULL,
1809         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1810         NULL, NULL, NULL, "Escape", NULL, NULL, NULL, NULL };
1811   char buf[6], buf2[256];
1812   int i;
1813
1814   Minput_method = msymbol ("input-method");
1815   Minput_driver = msymbol ("input-driver");
1816   Mtitle = msymbol ("title");
1817   Mmacro = msymbol ("macro");
1818   Mmodule = msymbol ("module");
1819   Mmap = msymbol ("map");
1820   Mstate = msymbol ("state");
1821   Minsert = msymbol ("insert");
1822   Mdelete = msymbol ("delete");
1823   Mmove = msymbol ("move");
1824   Mmark = msymbol ("mark");
1825   Mpushback = msymbol ("pushback");
1826   Mundo = msymbol ("undo");
1827   Mcall = msymbol ("call");
1828   Mshift = msymbol ("shift");
1829   Mselect = msymbol ("select");
1830   Mshow = msymbol ("show");
1831   Mhide = msymbol ("hide");
1832   Mset = msymbol ("set");
1833   Madd = msymbol ("add");
1834   Msub = msymbol ("sub");
1835   Mmul = msymbol ("mul");
1836   Mdiv = msymbol ("div");
1837   Mequal = msymbol ("=");
1838   Mless = msymbol ("<");
1839   Mgreater = msymbol (">");
1840
1841   Minput_preedit_start = msymbol ("input-preedit-start");
1842   Minput_preedit_done = msymbol ("input-preedit-done");
1843   Minput_preedit_draw = msymbol ("input-preedit-draw");
1844   Minput_status_start = msymbol ("input-status-start");
1845   Minput_status_done = msymbol ("input-status-done");
1846   Minput_status_draw = msymbol ("input-status-draw");
1847   Minput_candidates_start = msymbol ("input-candidates-start");
1848   Minput_candidates_done = msymbol ("input-candidates-done");
1849   Minput_candidates_draw = msymbol ("input-candidates-draw");
1850   Minput_set_spot = msymbol ("input-set-spot");
1851   Minput_toggle = msymbol ("input-toggle");
1852   Minput_reset = msymbol ("input-reset");
1853
1854   Mcandidate_list = msymbol_as_managing_key ("  candidate-list");
1855   Mcandidate_index = msymbol ("  candidate-index");
1856
1857   Minit = msymbol ("init");
1858   Mfini = msymbol ("fini");
1859
1860   M_key_alias = msymbol ("  key-alias");
1861
1862   buf[0] = 'C';
1863   buf[1] = '-';
1864   buf[3] = '\0';
1865   for (i = 0, buf[2] = '@'; i < ' '; i++, buf[2]++)
1866     {
1867       one_char_symbol[i] = msymbol (buf);
1868       if (key_names[i])
1869         msymbol_put (one_char_symbol[i], M_key_alias,  msymbol (key_names[i]));
1870     }
1871   for (buf[2] = i; i < 127; i++, buf[2]++)
1872     one_char_symbol[i] = msymbol (buf + 2);
1873   one_char_symbol[i++] = msymbol ("Delete");
1874   buf[2] = 'M';
1875   buf[3] = '-';
1876   buf[5] = '\0';
1877   buf2[0] = 'M';
1878   buf2[1] = '-';
1879   for (buf[4] = '@'; i < 160; i++, buf[4]++)
1880     {
1881       one_char_symbol[i] = msymbol (buf);
1882       if (key_names[i - 128])
1883         {
1884           strcpy (buf2 + 2, key_names[i - 128]);
1885           msymbol_put (one_char_symbol[i], M_key_alias,  msymbol (buf2));
1886         }
1887     }
1888   for (buf[4] = i - 128; i < 255; i++, buf[4]++)
1889     one_char_symbol[i] = msymbol (buf + 2);
1890   one_char_symbol[i] = msymbol ("M-Delete");
1891
1892   minput_default_driver.open_im = open_im;
1893   minput_default_driver.close_im = close_im;
1894   minput_default_driver.create_ic = create_ic;
1895   minput_default_driver.destroy_ic = destroy_ic;
1896   minput_default_driver.filter = filter;
1897   minput_default_driver.lookup = lookup;
1898   minput_default_driver.callback_list = mplist ();
1899   mplist_put (minput_default_driver.callback_list, Minput_reset,
1900               (void *) reset_ic);
1901   minput_driver = &minput_default_driver;
1902   return 0;
1903 }
1904
1905 void
1906 minput__fini ()
1907 {
1908   if (minput_default_driver.callback_list)
1909     {
1910       M17N_OBJECT_UNREF (minput_default_driver.callback_list);
1911       minput_default_driver.callback_list = NULL;
1912     }
1913   if (minput_driver->callback_list)
1914     {
1915       M17N_OBJECT_UNREF (minput_driver->callback_list);
1916       minput_driver->callback_list = NULL;
1917     }
1918 }
1919
1920 void
1921 minput__callback (MInputContext *ic, MSymbol command)
1922 {
1923   if (ic->im->driver.callback_list)
1924     {
1925       MInputCallbackFunc func
1926         = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list,
1927                                            command);
1928
1929       if (func)
1930         (func) (ic, command);
1931     }
1932 }
1933
1934 MSymbol
1935 minput__char_to_key (int c)
1936 {
1937   if (c < 0 || c >= 0x100)
1938     return Mnil;
1939
1940   return one_char_symbol[c];
1941 }
1942
1943 /*** @} */
1944 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1945
1946 \f
1947 /* External API */
1948
1949 /*** @addtogroup m17nInputMethod */
1950 /*** @{ */
1951 /*=*/
1952
1953 /***en
1954     @name Variables: Predefined symbols for callback commands.
1955
1956     These are the predefined symbols that are used as the @c COMMAND
1957     argument of callback functions of an input method driver (see
1958     #MInputDriver::callback_list ).  */ 
1959 /***ja
1960     @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
1961
1962     ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Î¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ë¤ª¤¤¤Æ @c COMMAND °ú¿ô¤È¤·
1963     ¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë (#MInputDriver::callback_list »²¾È)¡£
1964       */ 
1965 /*** @{ */ 
1966 /*=*/
1967
1968 MSymbol Minput_preedit_start;
1969 MSymbol Minput_preedit_done;
1970 MSymbol Minput_preedit_draw;
1971 MSymbol Minput_status_start;
1972 MSymbol Minput_status_done;
1973 MSymbol Minput_status_draw;
1974 MSymbol Minput_candidates_start;
1975 MSymbol Minput_candidates_done;
1976 MSymbol Minput_candidates_draw;
1977 MSymbol Minput_set_spot;
1978 MSymbol Minput_toggle;
1979 MSymbol Minput_reset;
1980 /*** @} */
1981 /*=*/
1982
1983 /***en
1984     @brief The default driver for internal input methods.
1985
1986     The variable #minput_default_driver is the default driver for
1987     internal input methods.
1988
1989     The member MInputDriver::open_im () searches the m17n database for
1990     an input method that matches the tag \< #Minput_method, $LANGUAGE,
1991     $NAME\> and loads it.
1992
1993     The member MInputDriver::callback_list () is @c NULL.  Thus, it is
1994     programmers responsibility to set it to a plist of proper callback
1995     functions.  Otherwise, no feedback information (e.g. preedit text)
1996     can be shown to users.
1997
1998     The macro M17N_INIT () sets the variable #minput_driver to the
1999     pointer to this driver so that all internal input methods use it.
2000
2001     Therefore, unless @c minput_driver is set differently, the driver
2002     dependent arguments $ARG of the functions whose name begin with
2003     "minput_" are all ignored.  */
2004
2005 /***ja
2006     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð.
2007
2008     ÆþÎϥɥ饤¥Ð #minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë
2009     ¥È¤Î¥É¥é¥¤¥Ð¤Ç¤¢¤ë¡£
2010
2011     ¥á¥ó¥Ð MInputDriver::open_im () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é¥¿¥° 
2012     \< #Minput_method, $LANGUAGE, $NAME\> ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤òõ¤·¡¢
2013     ¤½¤ì¤ò¥í¡¼¥É¤¹¤ë¡£
2014
2015     ¥á¥ó¥Ð MInputDriver::callback_list () ¤Ï @c NULL ¤Ê¤Î¤Ç¡¢¥×¥í¥°¥é
2016     ¥Þ¦¤ÇÀÕǤ¤ò»ý¤Ã¤Æ, Å¬Àڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Î plist ¤ËÀßÄꤷ¤Ê¤¯¤Æ
2017     ¤Ï¤Ê¤é¤Ê¤¤¡£¤µ¤â¤Ê¤¤¤È¡¢preedit ¥Æ¥­¥¹¥È¤Ê¤É¤Î¥Õ¥£¡¼¥É¥Ð¥Ã¥¯¾ðÊó¤¬
2018     ¥æ¡¼¥¶¤Ëɽ¼¨¤µ¤ì¤Ê¤¤¡£
2019
2020     ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô #minput_driver ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó
2021     ¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
2022
2023     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
2024     ¤Ç»Ï¤Þ¤ë´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤¹¤Ù¤Æ̵»ë¤µ¤ì¤ë¡£  */
2025
2026 MInputDriver minput_default_driver;
2027 /*=*/
2028
2029 /***en
2030     @brief The driver for internal input methods.
2031
2032     The variable #minput_driver is a pointer to the input method
2033     driver that is used by internal input methods.  The macro
2034     M17N_INIT () initializes it to a pointer to #minput_default_driver
2035     (if <m17n.h> is included) or to #minput_gui_driver (if
2036     <m17n-gui.h> is included).  */ 
2037 /***ja
2038     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð.
2039
2040     ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á
2041     ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥íM17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó
2042     ¥¿¤ò #minput_default_driver (<m17n.h> ¤¬´Þ¤Þ¤ì¤ë»þ) ¤Þ¤¿¤Ï 
2043     #minput_gui_driver ( <m17n-gui.h> ¤¬´Þ¤Þ¤ì¤ë»þ) ¤Ë½é´ü²½¤¹¤ë¡£  */ 
2044
2045 MInputDriver *minput_driver;
2046
2047 MSymbol Minput_driver;
2048
2049 /*=*/
2050
2051 /***en
2052     @brief Open an input method.
2053
2054     The minput_open_im () function opens an input method that matches
2055     language $LANGUAGE and name $NAME, and returns a pointer to the
2056     input method object newly allocated.
2057
2058     This function at first decides an driver for the input method as
2059     below.
2060
2061     If $LANGUAGE is not #Mnil, the driver pointed by the variable
2062     #minput_driver is used.
2063
2064     If $LANGUAGE is #Mnil and $NAME has #Minput_driver property, the
2065     driver pointed to by the property value is used to open the input
2066     method.  If $NAME has no such property, @c NULL is returned.
2067
2068     Then, the member MInputDriver::open_im () of the driver is
2069     called.  
2070
2071     $ARG is set in the member @c arg of the structure MInputMethod so
2072     that the driver can refer to it.  */
2073
2074 /***ja
2075     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë.
2076
2077     ´Ø¿ô minput_open_im () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME ¤Ë¹çÃפ¹¤ëÆþ
2078     Îϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¥ª¥Ö¥¸¥§¥¯
2079     ¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
2080     
2081     ¤³¤Î´Ø¿ô¤Ï¡¢¤Þ¤ºÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤ò°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ·èÄꤹ¤ë¡£
2082
2083     $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô #minput_driver ¤Ç»Ø¤µ¤ì¤Æ¤¤¤ë
2084     ¥É¥é¥¤¥Ð¤òÍѤ¤¤ë¡£
2085
2086     $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver ¥×¥í¥Ñ¥Æ¥£¤ò»ý
2087     ¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǻؤµ¤ì¤Æ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþ
2088     Îϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£$NAME ¤Ë¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì
2089     ¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
2090
2091     ¼¡¤¤¤Ç¡¢¥É¥é¥¤¥Ð¤Î¥á¥ó¥Ð MInputDriver::open_im () ¤¬¸Æ¤Ð¤ì¤ë¡£
2092
2093     $ARG ¤Ï¡¢¥É¥é¥¤¥Ð¤¬»²¾È¤Ç¤­¤ë¤è¤¦¤Ë¡¢¹½Â¤ÂΠMInputMethod ¤Î¥á¥ó¥Ð 
2094     @c arg ¤ËÀßÄꤵ¤ì¤ë¡£
2095
2096     @latexonly \IPAlabel{minput_open} @endlatexonly
2097
2098 */
2099
2100 MInputMethod *
2101 minput_open_im (MSymbol language, MSymbol name, void *arg)
2102 {
2103   MInputMethod *im;
2104   MInputDriver *driver;
2105
2106   if (language)
2107     driver = minput_driver;
2108   else
2109     {
2110       driver = (MInputDriver *) msymbol_get (name, Minput_driver);
2111       if (! driver)
2112         MERROR (MERROR_IM, NULL);
2113     }
2114
2115   MSTRUCT_CALLOC (im, MERROR_IM);
2116   im->language = language;
2117   im->name = name;
2118   im->arg = arg;
2119   im->driver = *driver;
2120   if ((*im->driver.open_im) (im) < 0)
2121     {
2122       free (im);
2123       return NULL;
2124     }
2125   return im;
2126 }
2127
2128 /*=*/
2129
2130 /***en
2131     @brief Close an input method.
2132
2133     The minput_close_im () function closes the input method $IM, which
2134     must have been created by minput_open_im ().  */
2135
2136 /***ja
2137     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë.
2138
2139     ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£¤³¤Î
2140     ÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì
2141     ¤Ð¤Ê¤é¤Ê¤¤¡£  */
2142
2143 void
2144 minput_close_im (MInputMethod *im)
2145 {
2146   (*im->driver.close_im) (im);
2147   free (im);
2148 }
2149
2150 /*=*/
2151
2152 /***en
2153     @brief Create an input context.
2154
2155     The minput_create_ic () function creates an input context object
2156     associated with input method $IM, and calls callback functions
2157     corresponding to #Minput_preedit_start, #Minput_status_start, and
2158     #Minput_status_draw in this order.
2159
2160     @return
2161
2162     If an input context is successfully created, minput_create_ic ()
2163     returns a pointer to it.  Otherwise it returns @c NULL.  */
2164
2165 /***ja
2166     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë.
2167
2168     ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯
2169     ¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢ #Minput_preedit_start,
2170     #Minput_status_start, #Minput_status_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø
2171     ¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
2172
2173     @return
2174
2175     ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤¬À¸À®¤µ¤ì¤¿¾ì¹ç¡¢minput_create_ic () ¤Ï¤½¤ÎÆþÎÏ¥³
2176     ¥ó¥Æ¥¯¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
2177       */
2178
2179 MInputContext *
2180 minput_create_ic (MInputMethod *im, void *arg)
2181 {
2182   MInputContext *ic;
2183
2184   MSTRUCT_CALLOC (ic, MERROR_IM);
2185   ic->im = im;
2186   ic->arg = arg;
2187   ic->preedit = mtext ();
2188   ic->candidate_list = NULL;
2189   ic->produced = mtext ();
2190   ic->spot.x = ic->spot.y = 0;
2191   ic->active = 1;
2192   ic->plist = mplist ();
2193   if ((*im->driver.create_ic) (ic) < 0)
2194     {
2195       M17N_OBJECT_UNREF (ic->preedit);
2196       M17N_OBJECT_UNREF (ic->produced);
2197       M17N_OBJECT_UNREF (ic->plist);
2198       free (ic);
2199       return NULL;
2200     };
2201
2202   if (im->driver.callback_list)
2203     {
2204       minput__callback (ic, Minput_preedit_start);
2205       minput__callback (ic, Minput_status_start);
2206       minput__callback (ic, Minput_status_draw);
2207     }
2208
2209   return ic;
2210 }
2211
2212 /*=*/
2213
2214 /***en
2215     @brief Destroy an input context.
2216
2217     The minput_destroy_ic () function destroys the input context $IC,
2218     which must have been created by minput_create_ic ().  It calls
2219     callback functions corresponding to #Minput_preedit_done,
2220     #Minput_status_done, and #Minput_candidates_done in this order.  */
2221
2222 /***ja
2223     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë.
2224
2225     ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£¤³
2226     ¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê
2227     ¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï#Minput_preedit_done,
2228     #Minput_status_done, #Minput_candidates_done ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò
2229     ¤³¤Î½ç¤Ë¸Æ¤Ö¡£
2230   */
2231
2232 void
2233 minput_destroy_ic (MInputContext *ic)
2234 {
2235   if (ic->im->driver.callback_list)
2236     {
2237       minput__callback (ic, Minput_preedit_done);
2238       minput__callback (ic, Minput_status_done);
2239       minput__callback (ic, Minput_candidates_done);
2240     }
2241   (*ic->im->driver.destroy_ic) (ic);
2242   M17N_OBJECT_UNREF (ic->preedit);
2243   M17N_OBJECT_UNREF (ic->produced);
2244   M17N_OBJECT_UNREF (ic->plist);
2245   free (ic);
2246 }
2247
2248 /*=*/
2249
2250 /***en
2251     @brief Filter an input key.
2252
2253     The minput_filter () function filters input key $KEY according to
2254     input context $IC, and calls callback functions corresponding to
2255     #Minput_preedit_draw, #Minput_status_draw, and
2256     #Minput_candidates_draw if the preedit text, the status, and the
2257     current candidate are changed respectively.
2258
2259     @return
2260     If $KEY is filtered out, this function returns 1.  In that case,
2261     the caller should discard the key.  Otherwise, it returns 0, and
2262     the caller should handle the key, for instance, by calling the
2263     function minput_lookup () with the same key.  */
2264
2265 /***ja
2266     @brief ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ë.
2267
2268     ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Ë±þ
2269     ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥­¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½
2270     ¤·¤¿ºÝ¤Ë¤Ï¤½¤ì¤¾¤ì#Minput_preedit_draw, #Minput_status_draw,
2271     #Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£
2272
2273     @return 
2274     $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¸Æ¤Ó
2275     ½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó
2276     ½Ð¤·Â¦¤Ï¡¢¤¿¤È¤¨¤ÐƱ¤¸¥­¡¼¤Ç´Ø¿ô minput_lookup () ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢
2277     ¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£
2278
2279     @latexonly \IPAlabel{minput_filter} @endlatexonly
2280 */
2281
2282 int
2283 minput_filter (MInputContext *ic, MSymbol key, void *arg)
2284 {
2285   int ret;
2286
2287   if (! ic
2288       || ! ic->active)
2289     return 0;
2290   ret = (*ic->im->driver.filter) (ic, key, arg);
2291
2292   if (ic->im->driver.callback_list)
2293     {
2294       if (ic->preedit_changed)
2295         minput__callback (ic, Minput_preedit_draw);
2296       if (ic->status_changed)
2297         minput__callback (ic, Minput_status_draw);
2298       if (ic->candidates_changed)
2299         minput__callback (ic, Minput_candidates_draw);
2300     }
2301   ic->preedit_changed = ic->status_changed = ic->candidates_changed = 0;
2302
2303   return ret;
2304 }
2305
2306 /*=*/
2307
2308 /***en
2309     @brief Lookup a text produced in the input context.
2310
2311     The minput_lookup () function looks up a text in the input context
2312     $IC.  $KEY must be the same one provided to the previous call of
2313     minput_filter ().
2314
2315     If a text was produced by the input method, it is concatenated
2316     to M-text $MT.
2317
2318     This function calls #MInputDriver::lookup .
2319
2320     @return
2321     If $KEY was correctly handled by the input method, this function
2322     returns 0.  Otherwise, returns -1, even in that case, some text
2323     may be produced in $MT.  */
2324
2325 /***ja
2326     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥ÈÃæ¤Î¥Æ¥­¥¹¥È¤Î¸¡º÷.
2327
2328     ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤ò¸¡º÷¤¹
2329     ¤ë¡£$KEY ¤Ï´Ø¿ôminput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î
2330     ¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2331
2332     ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥Æ¥­¥¹¥È¤Ï M-text
2333     $MT ¤ËÏ¢·ë¤µ¤ì¤ë¡£
2334
2335     ¤³¤Î´Ø¿ô¤Ï¡¢#MInputDriver::lookup ¤ò¸Æ¤Ö¡£
2336
2337     @return 
2338     $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤òÊÖ¤¹¡£
2339     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¤Ç¤â $MT ¤Ë²¿¤é¤«¤Î¥Æ¥­¥¹¥È¤¬À¸
2340     À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£
2341
2342     @latexonly \IPAlabel{minput_lookup} @endlatexonly  */
2343
2344 int
2345 minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
2346 {
2347   return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1);
2348 }
2349 /*=*/
2350
2351 /***en
2352     @brief Set the spot of the input context.
2353
2354     The minput_set_spot () function set the spot of input context $IC
2355     to coordinate ($X, $Y ) with the height $ASCENT and $DESCENT .
2356     The semantics of these values depend on the input method driver.
2357     $FONTSIZE specfies the fontsize of a preedit text in 1/10 point.
2358
2359     For instance, an driver designed to work in CUI environment may
2360     use $X and $Y as column and row numbers, and ignore $ASCENT and
2361     $DESCENT .  An driver designed to work on a window system may
2362     treat $X and $Y as pixel offsets relative to the origin of the
2363     client window, and treat $ASCENT and $DESCENT as ascent and
2364     descent pixels of a line at ($X . $Y ).
2365
2366     $MT and $POS is an M-text and a character position at the spot.
2367     $MT may be @c NULL, in which case, the input method cannot get
2368     information about the text around the spot.  */
2369
2370 /***ja
2371     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë
2372
2373     ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂ
2374     É¸ ($X, $Y )¤Ë ¡¢¹â¤µ $ASCENT¡¢ $DESCENT ¤ÇÀßÄꤹ¤ë¡£ ¤³¤ì¤é¤ÎÃͤÎ
2375     °ÕÌ£¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë¡£$FONTSIZE ¤Ïpreedit ¥Æ¥­¥¹¥È
2376     ¤Î¥Õ¥©¥ó¥È¥µ¥¤¥º¤ò 1/10 ¥Ý¥¤¥ó¥Èñ°Ì¤Ç»ØÄꤹ¤ë¡£
2377
2378     ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ë¥É¥é¥¤¥Ð¤Ï $X ¤È $Y ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô¤Î
2379     ÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT ¤È $DESCENT ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿
2380     ¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤΥɥ饤¥Ð¤Ï $X ¤È $Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É¥¦
2381     ¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢
2382     $ASCENT ¤È $DESCENT ¤ò ($X . $Y ) ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯
2383     ¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£
2384
2385     $MT ¤È $POS ¤Ï¤½¤Î¥¹¥Ý¥Ã¥È¤Î M-text ¤Èʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$MT ¤Ï @c
2386     NULL ¤Ç¤â¤è¤¯¡¢¤½¤Î¾ì¹ç¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤Ï¥¹¥Ý¥Ã¥È¼þÊդΥƥ­¥¹¥È¤Ë
2387     ´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£
2388     */
2389
2390 void
2391 minput_set_spot (MInputContext *ic, int x, int y,
2392                  int ascent, int descent, int fontsize,
2393                  MText *mt, int pos)
2394 {
2395   ic->spot.x = x;
2396   ic->spot.y = y;
2397   ic->spot.ascent = ascent;
2398   ic->spot.descent = descent;
2399   ic->spot.fontsize = fontsize;
2400   ic->spot.mt = mt;
2401   ic->spot.pos = pos;
2402   if (ic->im->driver.callback_list)
2403     minput__callback (ic, Minput_set_spot);
2404 }
2405 /*=*/
2406
2407 /***en
2408     @brief Toggle input method.
2409
2410     The minput_toggle () function toggles the input method associated
2411     with the input context $IC.  */
2412 /***ja
2413     @brief ÆþÎϥ᥽¥Ã¥É¤òÀÚÂؤ¨¤ë.
2414
2415     ´Ø¿ô minput_toggle () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ËÂбþÉÕ¤±¤é¤ì¤¿ÆþÎÏ
2416     ¥á¥½¥Ã¥É¤ò¥È¥°¥ë¤¹¤ë¡£
2417     */
2418
2419 void
2420 minput_toggle (MInputContext *ic)
2421 {
2422   if (ic->im->driver.callback_list)
2423     minput__callback (ic, Minput_toggle);
2424   ic->active = ! ic->active;
2425 }
2426
2427 /***en
2428     @brief Reset an input context.
2429
2430     The minput_reset_ic () function resets the input context $IC by
2431     calling a callback functions corresponding to #Minput_reset.  It
2432     actually shifts the state to the initial one, and thus the current
2433     preediting text (if any) is committed.  If necessary, a program
2434     can extract that text by calling minput_lookup () just after the
2435     call of minput_reset_ic ().  In that case, the arguments @c KEY
2436     and @c ARG of minput_lookup () are ignored.  */
2437 /***ja
2438     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ò¥ê¥»¥Ã¥È¤¹¤ë.
2439
2440     ´Ø¿ô minput_reset_ic () ¤Ï #Minput_reset ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô
2441     ¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ò¥ê¥»¥Ã¥È¤¹¤ë¡£¤³¤ì¤Ï¼ÂºÝ¤Ï
2442     ÆþÎϥ᥽¥Ã¥É¤ò½é´ü¾õÂ֤˥·¥Õ¥È¤µ¤»¤ë¡£¤·¤¿¤¬¤Ã¤Æ¡¢¤â¤·¸½ºßÆþÎÏÃæ¤Î
2443     ¥Æ¥­¥¹¥È¤¬¤¢¤ì¤Ð¡¢¤½¤ì¤Ï¥³¥ß¥Ã¥È¤µ¤ì¤ë¡£É¬Íפʤ饢¥×¥ê¥±¡¼¥·¥ç¥ó¥×
2444     ¥í¥°¥é¥à¤Ï minput_lookup () ¤òÆɤó¤Ç¤½¤Î¥Æ¥­¥¹¥È¤ò¼è¤ê½Ð¤»¤ë¡£¤½¤Î
2445     ºÝ¡¢minput_lookup () ¤Î°ú¿ô @c KEY ¤È @c ARG ¤Ï̵»ë¤µ¤ì¤ë¡£ */
2446 void
2447 minput_reset_ic (MInputContext *ic)
2448 {
2449   if (ic->im->driver.callback_list)
2450     minput__callback (ic, Minput_reset);
2451 }
2452
2453
2454 /*** @} */
2455 /*=*/
2456 /*** @addtogroup m17nDebug */
2457 /*=*/
2458 /*** @{  */
2459 /*=*/
2460
2461 /***en
2462     @brief Dump an input method.
2463
2464     The mdebug_dump_im () function prints the input method $IM in a
2465     human readable way to the stderr.  $INDENT specifies how many
2466     columns to indent the lines but the first one.
2467
2468     @return
2469     This function returns $IM.  */
2470 /***ja
2471     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥À¥ó¥×¤¹¤ë.
2472
2473     ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ò stderr ¤Ë¿Í´Ö¤Ë²ÄÆɤÊ
2474     ·Á¤Ç°õºþ¤¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
2475
2476     @return
2477     ¤³¤Î´Ø¿ô¤Ï $IM ¤òÊÖ¤¹¡£  */
2478
2479 MInputMethod *
2480 mdebug_dump_im (MInputMethod *im, int indent)
2481 {
2482   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
2483   char *prefix;
2484
2485   prefix = (char *) alloca (indent + 1);
2486   memset (prefix, 32, indent);
2487   prefix[indent] = '\0';
2488
2489   fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
2490            msymbol_name (im->name));
2491   mdebug_dump_mtext (im_info->title, 0, 0);
2492   if (im->name != Mnil)
2493     {
2494       MPlist *state;
2495
2496       MPLIST_DO (state, im_info->states)
2497         {
2498           fprintf (stderr, "\n%s  ", prefix);
2499           dump_im_state (MPLIST_VAL (state), indent + 2);
2500         }
2501     }
2502   fprintf (stderr, ")");
2503   return im;
2504 }
2505
2506 /*** @} */ 
2507
2508 /*
2509   Local Variables:
2510   coding: euc-japan
2511   End:
2512 */