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