(load_input_method): Don't unref `maps' it it's not created.
[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   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 = ic_info->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)
1505 {
1506   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1507   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1508
1509   MLIST_RESET (ic_info);
1510   if (im_info->states)
1511     ic_info->state = (MIMState *) MPLIST_VAL (im_info->states);
1512   else
1513     ic_info->state = NULL;
1514   ic_info->map = ic_info->state ? ic_info->state->map : NULL;
1515   ic_info->state_key_head = ic_info->key_head = 0;
1516   ic->cursor_pos = ic_info->state_pos = 0;
1517   ic->status = ic_info->state ? ic_info->state->title : NULL;
1518   if (! ic->status)
1519     ic->status = im_info->title;
1520   ic->candidate_list = NULL;
1521   ic->candidate_show = 0;
1522   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 1;
1523   if (ic_info->map && ic_info->map->map_actions)
1524     take_action_list (ic, ic_info->map->map_actions);
1525 }
1526
1527 static int
1528 open_im (MInputMethod *im)
1529 {
1530   MDatabase *mdb;
1531   MInputMethodInfo *im_info;
1532   MPlist *plist;
1533   int result;
1534
1535   mdb = mdatabase_find (Minput_method, im->language, im->name, Mnil);
1536   if (! mdb)
1537     return -1;
1538   plist = mdatabase_load (mdb);
1539   if (! plist)
1540     MERROR (MERROR_IM, -1);
1541   MSTRUCT_CALLOC (im_info, MERROR_IM);
1542   im->info = im_info;
1543   result = load_input_method (im->language, im->name, plist, im_info);
1544   M17N_OBJECT_UNREF (plist);
1545   if (result < 0)
1546     MERROR (MERROR_IM, -1);
1547   return 0;
1548 }
1549
1550 static void
1551 close_im (MInputMethod *im)
1552 {
1553   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
1554   MPlist *plist;
1555
1556   if (im_info->title)
1557     M17N_OBJECT_UNREF (im_info->title);
1558   if (im_info->states)
1559     {
1560       MPLIST_DO (plist, im_info->states)
1561         {
1562           MIMState *state = (MIMState *) MPLIST_VAL (plist);
1563
1564           if (state->title)
1565             M17N_OBJECT_UNREF (state->title);
1566           if (state->map)
1567             free_map (state->map);
1568           free (state);
1569         }
1570       M17N_OBJECT_UNREF (im_info->states);
1571     }
1572
1573   if (im_info->macros)
1574     {
1575       MPLIST_DO (plist, im_info->macros)
1576         M17N_OBJECT_UNREF (MPLIST_VAL (plist)); 
1577       M17N_OBJECT_UNREF (im_info->macros);
1578     }
1579
1580   if (im_info->externals)
1581     {
1582       MPLIST_DO (plist, im_info->externals)
1583         {
1584           MIMExternalModule *external = MPLIST_VAL (plist);
1585
1586           dlclose (external->handle);
1587           M17N_OBJECT_UNREF (external->func_list);
1588           free (external);
1589           MPLIST_KEY (plist) = Mt;
1590         }
1591       M17N_OBJECT_UNREF (im_info->externals);
1592     }
1593   free (im_info);
1594   im->info = NULL;
1595 }
1596
1597
1598 static int
1599 create_ic (MInputContext *ic)
1600 {
1601   MInputMethod *im = ic->im;
1602   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
1603   MInputContextInfo *ic_info;
1604
1605   if (ic->info)
1606     ic_info = (MInputContextInfo *) ic->info;
1607   else
1608     {
1609       MSTRUCT_CALLOC (ic_info, MERROR_IM);
1610       ic->info = ic_info;
1611     }
1612   MLIST_INIT1 (ic_info, keys, 8);
1613   ic_info->markers = mplist ();
1614   ic_info->vars = mplist ();
1615   ic_info->preedit_saved = mtext ();
1616   if (im_info->externals)
1617     {
1618       MPlist *func_args = mplist (), *plist;
1619
1620       mplist_add (func_args, Mt, ic);
1621       MPLIST_DO (plist, im_info->externals)
1622         {
1623           MIMExternalModule *external = MPLIST_VAL (plist);
1624           MIMExternalFunc func
1625             = (MIMExternalFunc) mplist_get (external->func_list, Minit);
1626
1627           if (func)
1628             (func) (func_args);
1629         }
1630       M17N_OBJECT_UNREF (func_args);
1631     }
1632   reset_ic (ic);
1633   return 0;
1634 }
1635
1636 static void
1637 destroy_ic (MInputContext *ic)
1638 {
1639   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1640   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1641
1642   if (im_info->externals)
1643     {
1644       MPlist *func_args = mplist (), *plist;
1645
1646       mplist_add (func_args, Mt, ic);
1647       MPLIST_DO (plist, im_info->externals)
1648         {
1649           MIMExternalModule *external = MPLIST_VAL (plist);
1650           MIMExternalFunc func
1651             = (MIMExternalFunc) mplist_get (external->func_list, Mfini);
1652
1653           if (func)
1654             (func) (func_args);
1655         }
1656       M17N_OBJECT_UNREF (func_args);
1657     }
1658   MLIST_FREE1 (ic_info, keys);
1659   M17N_OBJECT_UNREF (ic_info->preedit_saved);
1660   M17N_OBJECT_UNREF (ic_info->markers);
1661   M17N_OBJECT_UNREF (ic_info->vars);
1662   free (ic->info);
1663 }
1664
1665
1666 /** Handle the input key KEY in the current state and map of IC->info.
1667     If KEY is handled but no text is produced, return 0, otherwise
1668     return 1.
1669
1670     Ignore ARG.  */
1671
1672 static int
1673 filter (MInputContext *ic, MSymbol key, void *arg)
1674 {
1675   MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
1676   MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
1677   int i = 0;
1678
1679   if (! ic_info->state)
1680     {
1681       ic_info->key_unhandled = 1;
1682       return 0;
1683     }
1684   mtext_reset (ic->produced);
1685   ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
1686   MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
1687   ic_info->key_unhandled = 0;
1688   do {
1689     if (handle_key (ic) < 0)
1690       {
1691         /* KEY was not handled.  Reset the status and break the
1692            loop.  */
1693         reset_ic (ic);
1694         /* This forces returning 1.  */
1695         ic_info->key_unhandled = 1;
1696         break;
1697       }
1698     if (i++ == 100)
1699       {
1700         mdebug_hook ();
1701         reset_ic (ic);
1702         ic_info->key_unhandled = 1;
1703         break;
1704       }
1705     /* Break the loop if all keys were handled.  */
1706   } while (ic_info->key_head < ic_info->used);
1707
1708   /* If the current map is the root of the initial state, we should
1709      produce any preedit text in ic->produced.  */
1710   if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map
1711       && mtext_nchars (ic->preedit) > 0)
1712     shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name);
1713
1714   if (mtext_nchars (ic->produced) > 0)
1715     {
1716       MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
1717
1718       if (lang != Mnil)
1719         mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
1720                         Mlanguage, ic->im->language);
1721     }
1722
1723   return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
1724 }
1725
1726
1727 /** Return 1 if the last event or key was not handled, otherwise
1728     return 0.
1729
1730     There is no need of looking up because ic->produced should already
1731     contain the produced text (if any).
1732
1733     Ignore KEY.  */
1734
1735 static int
1736 lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
1737 {
1738   mtext_cat (mt, ic->produced);
1739   mtext_reset (ic->produced);
1740   return (((MInputContextInfo *) ic->info)->key_unhandled ? -1 : 0);
1741 }
1742
1743 /* Support functions for mdebug_dump_im.  */
1744
1745 static void
1746 dump_im_map (MPlist *map_list, int indent)
1747 {
1748   char *prefix;
1749   MSymbol key = MPLIST_KEY (map_list);
1750   MIMMap *map = (MIMMap *) MPLIST_VAL (map_list);
1751
1752   prefix = (char *) alloca (indent + 1);
1753   memset (prefix, 32, indent);
1754   prefix[indent] = '\0';
1755
1756   fprintf (stderr, "(\"%s\" ", msymbol_name (key));
1757   if (map->map_actions)
1758     mdebug_dump_plist (map->map_actions, indent + 2);
1759   if (map->submaps)
1760     {
1761       MPLIST_DO (map_list, map->submaps)
1762         {
1763           fprintf (stderr, "\n%s  ", prefix);
1764           dump_im_map (map_list, indent + 2);
1765         }
1766     }
1767   if (map->branch_actions)
1768     {
1769       fprintf (stderr, "\n%s  (branch\n%s    ", prefix, prefix);
1770       mdebug_dump_plist (map->branch_actions, indent + 4);
1771       fprintf (stderr, ")");      
1772     }
1773   fprintf (stderr, ")");
1774 }
1775
1776
1777 static void
1778 dump_im_state (MIMState *state, int indent)
1779 {
1780   char *prefix;
1781   MPlist *map_list;
1782
1783   prefix = (char *) alloca (indent + 1);
1784   memset (prefix, 32, indent);
1785   prefix[indent] = '\0';
1786
1787   fprintf (stderr, "(%s", msymbol_name (state->name));
1788   if (state->map->submaps)
1789     {
1790       MPLIST_DO (map_list, state->map->submaps)
1791         {
1792           fprintf (stderr, "\n%s  ", prefix);
1793           dump_im_map (map_list, indent + 2);
1794         }
1795     }
1796   fprintf (stderr, ")");
1797 }
1798
1799 \f
1800
1801 int
1802 minput__init ()
1803 {
1804   char *key_names[32]
1805     = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1806         "BackSpace", "Tab", "Linefeed", "Clear", NULL, "Return", NULL, NULL,
1807         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1808         NULL, NULL, NULL, "Escape", NULL, NULL, NULL, NULL };
1809   char buf[6], buf2[256];
1810   int i;
1811
1812   Minput_method = msymbol ("input-method");
1813   Minput_driver = msymbol ("input-driver");
1814   Mtitle = msymbol ("title");
1815   Mmacro = msymbol ("macro");
1816   Mmodule = msymbol ("module");
1817   Mmap = msymbol ("map");
1818   Mstate = msymbol ("state");
1819   Minsert = msymbol ("insert");
1820   Mdelete = msymbol ("delete");
1821   Mmove = msymbol ("move");
1822   Mmark = msymbol ("mark");
1823   Mpushback = msymbol ("pushback");
1824   Mundo = msymbol ("undo");
1825   Mcall = msymbol ("call");
1826   Mshift = msymbol ("shift");
1827   Mselect = msymbol ("select");
1828   Mshow = msymbol ("show");
1829   Mhide = msymbol ("hide");
1830   Mset = msymbol ("set");
1831   Madd = msymbol ("add");
1832   Msub = msymbol ("sub");
1833   Mmul = msymbol ("mul");
1834   Mdiv = msymbol ("div");
1835   Mequal = msymbol ("=");
1836   Mless = msymbol ("<");
1837   Mgreater = msymbol (">");
1838
1839   Minput_preedit_start = msymbol ("input-preedit-start");
1840   Minput_preedit_done = msymbol ("input-preedit-done");
1841   Minput_preedit_draw = msymbol ("input-preedit-draw");
1842   Minput_status_start = msymbol ("input-status-start");
1843   Minput_status_done = msymbol ("input-status-done");
1844   Minput_status_draw = msymbol ("input-status-draw");
1845   Minput_candidates_start = msymbol ("input-candidates-start");
1846   Minput_candidates_done = msymbol ("input-candidates-done");
1847   Minput_candidates_draw = msymbol ("input-candidates-draw");
1848   Minput_set_spot = msymbol ("input-set-spot");
1849   Minput_toggle = msymbol ("input-toggle");
1850
1851   Mcandidate_list = msymbol_as_managing_key ("  candidate-list");
1852   Mcandidate_index = msymbol ("  candidate-index");
1853
1854   Minit = msymbol ("init");
1855   Mfini = msymbol ("fini");
1856
1857   M_key_alias = msymbol ("  key-alias");
1858
1859   buf[0] = 'C';
1860   buf[1] = '-';
1861   buf[3] = '\0';
1862   for (i = 0, buf[2] = '@'; i < ' '; i++, buf[2]++)
1863     {
1864       one_char_symbol[i] = msymbol (buf);
1865       if (key_names[i])
1866         msymbol_put (one_char_symbol[i], M_key_alias,  msymbol (key_names[i]));
1867     }
1868   for (buf[2] = i; i < 127; i++, buf[2]++)
1869     one_char_symbol[i] = msymbol (buf + 2);
1870   one_char_symbol[i++] = msymbol ("Delete");
1871   buf[2] = 'M';
1872   buf[3] = '-';
1873   buf[5] = '\0';
1874   buf2[0] = 'M';
1875   buf2[1] = '-';
1876   for (buf[4] = '@'; i < 160; i++, buf[4]++)
1877     {
1878       one_char_symbol[i] = msymbol (buf);
1879       if (key_names[i - 128])
1880         {
1881           strcpy (buf2 + 2, key_names[i - 128]);
1882           msymbol_put (one_char_symbol[i], M_key_alias,  msymbol (buf2));
1883         }
1884     }
1885   for (buf[4] = i - 128; i < 255; i++, buf[4]++)
1886     one_char_symbol[i] = msymbol (buf + 2);
1887   one_char_symbol[i] = msymbol ("M-Delete");
1888
1889   minput_default_driver.open_im = open_im;
1890   minput_default_driver.close_im = close_im;
1891   minput_default_driver.create_ic = create_ic;
1892   minput_default_driver.destroy_ic = destroy_ic;
1893   minput_default_driver.filter = filter;
1894   minput_default_driver.lookup = lookup;
1895   minput_default_driver.callback_list = NULL;
1896   minput_driver = &minput_default_driver;
1897   return 0;
1898 }
1899
1900 void
1901 minput__fini ()
1902 {
1903   if (minput_default_driver.callback_list)
1904     {
1905       M17N_OBJECT_UNREF (minput_default_driver.callback_list);
1906       minput_default_driver.callback_list = NULL;
1907     }
1908   if (minput_driver->callback_list)
1909     {
1910       M17N_OBJECT_UNREF (minput_driver->callback_list);
1911       minput_driver->callback_list = NULL;
1912     }
1913 }
1914
1915 void
1916 minput__callback (MInputContext *ic, MSymbol command)
1917 {
1918   if (ic->im->driver.callback_list)
1919     {
1920       MInputCallbackFunc func
1921         = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list,
1922                                            command);
1923
1924       if (func)
1925         (func) (ic, command);
1926     }
1927 }
1928
1929 MSymbol
1930 minput__char_to_key (int c)
1931 {
1932   if (c < 0 || c >= 0x100)
1933     return Mnil;
1934
1935   return one_char_symbol[c];
1936 }
1937
1938 /*** @} */
1939 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
1940
1941 \f
1942 /* External API */
1943
1944 /*** @addtogroup m17nInputMethod */
1945 /*** @{ */
1946 /*=*/
1947
1948 /***en
1949     @name Variables: Predefined symbols for callback commands.
1950
1951     These are the predefined symbols that are used as the @c COMMAND
1952     argument of callback functions of an input method driver (see
1953     #MInputDriver::callback_list ).  */ 
1954 /***ja
1955     @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
1956
1957     ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Î¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ë¤ª¤¤¤Æ @c COMMAND °ú¿ô¤È¤·
1958     ¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë (#MInputDriver::callback_list »²¾È)¡£
1959       */ 
1960 /*** @{ */ 
1961 /*=*/
1962
1963 MSymbol Minput_preedit_start;
1964 MSymbol Minput_preedit_done;
1965 MSymbol Minput_preedit_draw;
1966 MSymbol Minput_status_start;
1967 MSymbol Minput_status_done;
1968 MSymbol Minput_status_draw;
1969 MSymbol Minput_candidates_start;
1970 MSymbol Minput_candidates_done;
1971 MSymbol Minput_candidates_draw;
1972 MSymbol Minput_set_spot;
1973 MSymbol Minput_toggle;
1974 /*** @} */
1975 /*=*/
1976
1977 /***en
1978     @brief The default driver for internal input methods.
1979
1980     The variable #minput_default_driver is the default driver for
1981     internal input methods.
1982
1983     The member MInputDriver::open_im () searches the m17n database for
1984     an input method that matches the tag \< #Minput_method, $LANGUAGE,
1985     $NAME\> and loads it.
1986
1987     The member MInputDriver::callback_list () is @c NULL.  Thus, it is
1988     programmers responsibility to set it to a plist of proper callback
1989     functions.  Otherwise, no feedback information (e.g. preedit text)
1990     can be shown to users.
1991
1992     The macro M17N_INIT () sets the variable #minput_driver to the
1993     pointer to this driver so that all internal input methods use it.
1994
1995     Therefore, unless @c minput_driver is set differently, the driver
1996     dependent arguments $ARG of the functions whose name begin with
1997     "minput_" are all ignored.  */
1998
1999 /***ja
2000     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð.
2001
2002     ÆþÎϥɥ饤¥Ð #minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë
2003     ¥È¤Î¥É¥é¥¤¥Ð¤Ç¤¢¤ë¡£
2004
2005     ¥á¥ó¥Ð MInputDriver::open_im () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é¥¿¥° 
2006     \< #Minput_method, $LANGUAGE, $NAME\> ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤òõ¤·¡¢
2007     ¤½¤ì¤ò¥í¡¼¥É¤¹¤ë¡£
2008
2009     ¥á¥ó¥Ð MInputDriver::callback_list () ¤Ï @c NULL ¤Ê¤Î¤Ç¡¢¥×¥í¥°¥é
2010     ¥Þ¦¤ÇÀÕǤ¤ò»ý¤Ã¤Æ, Å¬Àڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Î plist ¤ËÀßÄꤷ¤Ê¤¯¤Æ
2011     ¤Ï¤Ê¤é¤Ê¤¤¡£¤µ¤â¤Ê¤¤¤È¡¢preedit ¥Æ¥­¥¹¥È¤Ê¤É¤Î¥Õ¥£¡¼¥É¥Ð¥Ã¥¯¾ðÊó¤¬
2012     ¥æ¡¼¥¶¤Ëɽ¼¨¤µ¤ì¤Ê¤¤¡£
2013
2014     ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô #minput_driver ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó
2015     ¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
2016
2017     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
2018     ¤Ç»Ï¤Þ¤ë´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤¹¤Ù¤Æ̵»ë¤µ¤ì¤ë¡£  */
2019
2020 MInputDriver minput_default_driver;
2021 /*=*/
2022
2023 /***en
2024     @brief The driver for internal input methods.
2025
2026     The variable #minput_driver is a pointer to the input method
2027     driver that is used by internal input methods.  The macro
2028     M17N_INIT () initializes it to a pointer to #minput_default_driver
2029     (if <m17n.h> is included) or to #minput_gui_driver (if
2030     <m17n-gui.h> is included).  */ 
2031 /***ja
2032     @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð.
2033
2034     ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á
2035     ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥íM17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó
2036     ¥¿¤ò #minput_default_driver (<m17n.h> ¤¬´Þ¤Þ¤ì¤ë»þ) ¤Þ¤¿¤Ï 
2037     #minput_gui_driver ( <m17n-gui.h> ¤¬´Þ¤Þ¤ì¤ë»þ) ¤Ë½é´ü²½¤¹¤ë¡£  */ 
2038
2039 MInputDriver *minput_driver;
2040
2041 MSymbol Minput_driver;
2042
2043 /*=*/
2044
2045 /***en
2046     @brief Open an input method.
2047
2048     The minput_open_im () function opens an input method that matches
2049     language $LANGUAGE and name $NAME, and returns a pointer to the
2050     input method object newly allocated.
2051
2052     This function at first decides an driver for the input method as
2053     below.
2054
2055     If $LANGUAGE is not #Mnil, the driver pointed by the variable
2056     #minput_driver is used.
2057
2058     If $LANGUAGE is #Mnil and $NAME has #Minput_driver property, the
2059     driver pointed to by the property value is used to open the input
2060     method.  If $NAME has no such property, @c NULL is returned.
2061
2062     Then, the member MInputDriver::open_im () of the driver is
2063     called.  
2064
2065     $ARG is set in the member @c arg of the structure MInputMethod so
2066     that the driver can refer to it.  */
2067
2068 /***ja
2069     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë.
2070
2071     ´Ø¿ô minput_open_im () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME ¤Ë¹çÃפ¹¤ëÆþ
2072     Îϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¥ª¥Ö¥¸¥§¥¯
2073     ¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
2074     
2075     ¤³¤Î´Ø¿ô¤Ï¡¢¤Þ¤ºÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤ò°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ·èÄꤹ¤ë¡£
2076
2077     $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô #minput_driver ¤Ç»Ø¤µ¤ì¤Æ¤¤¤ë
2078     ¥É¥é¥¤¥Ð¤òÍѤ¤¤ë¡£
2079
2080     $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver ¥×¥í¥Ñ¥Æ¥£¤ò»ý
2081     ¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǻؤµ¤ì¤Æ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþ
2082     Îϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£$NAME ¤Ë¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì
2083     ¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
2084
2085     ¼¡¤¤¤Ç¡¢¥É¥é¥¤¥Ð¤Î¥á¥ó¥Ð MInputDriver::open_im () ¤¬¸Æ¤Ð¤ì¤ë¡£
2086
2087     $ARG ¤Ï¡¢¥É¥é¥¤¥Ð¤¬»²¾È¤Ç¤­¤ë¤è¤¦¤Ë¡¢¹½Â¤ÂΠMInputMethod ¤Î¥á¥ó¥Ð 
2088     @c arg ¤ËÀßÄꤵ¤ì¤ë¡£
2089
2090     @latexonly \IPAlabel{minput_open} @endlatexonly
2091
2092 */
2093
2094 MInputMethod *
2095 minput_open_im (MSymbol language, MSymbol name, void *arg)
2096 {
2097   MInputMethod *im;
2098   MInputDriver *driver;
2099
2100   if (language)
2101     driver = minput_driver;
2102   else
2103     {
2104       driver = (MInputDriver *) msymbol_get (name, Minput_driver);
2105       if (! driver)
2106         MERROR (MERROR_IM, NULL);
2107     }
2108
2109   MSTRUCT_CALLOC (im, MERROR_IM);
2110   im->language = language;
2111   im->name = name;
2112   im->arg = arg;
2113   im->driver = *driver;
2114   if ((*im->driver.open_im) (im) < 0)
2115     {
2116       free (im);
2117       return NULL;
2118     }
2119   return im;
2120 }
2121
2122 /*=*/
2123
2124 /***en
2125     @brief Close an input method.
2126
2127     The minput_close_im () function closes the input method $IM, which
2128     must have been created by minput_open_im ().  */
2129
2130 /***ja
2131     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë.
2132
2133     ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£¤³¤Î
2134     ÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì
2135     ¤Ð¤Ê¤é¤Ê¤¤¡£  */
2136
2137 void
2138 minput_close_im (MInputMethod *im)
2139 {
2140   (*im->driver.close_im) (im);
2141   free (im);
2142 }
2143
2144 /*=*/
2145
2146 /***en
2147     @brief Create an input context.
2148
2149     The minput_create_ic () function creates an input context object
2150     associated with input method $IM, and calls callback functions
2151     corresponding to #Minput_preedit_start, #Minput_status_start, and
2152     #Minput_status_draw in this order.
2153
2154     @return
2155
2156     If an input context is successfully created, minput_create_ic ()
2157     returns a pointer to it.  Otherwise it returns @c NULL.  */
2158
2159 /***ja
2160     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë.
2161
2162     ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯
2163     ¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢ #Minput_preedit_start,
2164     #Minput_status_start, #Minput_status_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø
2165     ¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
2166
2167     @return
2168
2169     ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤¬À¸À®¤µ¤ì¤¿¾ì¹ç¡¢minput_create_ic () ¤Ï¤½¤ÎÆþÎÏ¥³
2170     ¥ó¥Æ¥¯¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
2171       */
2172
2173 MInputContext *
2174 minput_create_ic (MInputMethod *im, void *arg)
2175 {
2176   MInputContext *ic;
2177
2178   MSTRUCT_CALLOC (ic, MERROR_IM);
2179   ic->im = im;
2180   ic->arg = arg;
2181   ic->preedit = mtext ();
2182   ic->candidate_list = NULL;
2183   ic->produced = mtext ();
2184   ic->spot.x = ic->spot.y = 0;
2185   ic->active = 1;
2186   ic->plist = mplist ();
2187   if ((*im->driver.create_ic) (ic) < 0)
2188     {
2189       M17N_OBJECT_UNREF (ic->preedit);
2190       M17N_OBJECT_UNREF (ic->produced);
2191       M17N_OBJECT_UNREF (ic->plist);
2192       free (ic);
2193       return NULL;
2194     };
2195
2196   if (im->driver.callback_list)
2197     {
2198       minput__callback (ic, Minput_preedit_start);
2199       minput__callback (ic, Minput_status_start);
2200       minput__callback (ic, Minput_status_draw);
2201     }
2202
2203   return ic;
2204 }
2205
2206 /*=*/
2207
2208 /***en
2209     @brief Destroy an input context.
2210
2211     The minput_destroy_ic () function destroys the input context $IC,
2212     which must have been created by minput_create_ic ().  It calls
2213     callback functions corresponding to #Minput_preedit_done,
2214     #Minput_status_done, and #Minput_candidates_done in this order.  */
2215
2216 /***ja
2217     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë.
2218
2219     ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£¤³
2220     ¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê
2221     ¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï#Minput_preedit_done,
2222     #Minput_status_done, #Minput_candidates_done ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò
2223     ¤³¤Î½ç¤Ë¸Æ¤Ö¡£
2224   */
2225
2226 void
2227 minput_destroy_ic (MInputContext *ic)
2228 {
2229   if (ic->im->driver.callback_list)
2230     {
2231       minput__callback (ic, Minput_preedit_done);
2232       minput__callback (ic, Minput_status_done);
2233       minput__callback (ic, Minput_candidates_done);
2234     }
2235   (*ic->im->driver.destroy_ic) (ic);
2236   M17N_OBJECT_UNREF (ic->preedit);
2237   M17N_OBJECT_UNREF (ic->produced);
2238   M17N_OBJECT_UNREF (ic->plist);
2239   free (ic);
2240 }
2241
2242 /*=*/
2243
2244 /***en
2245     @brief Filter an input key.
2246
2247     The minput_filter () function filters input key $KEY according to
2248     input context $IC, and calls callback functions corresponding to
2249     #Minput_preedit_draw, #Minput_status_draw, and
2250     #Minput_candidates_draw if the preedit text, the status, and the
2251     current candidate are changed respectively.
2252
2253     @return
2254     If $KEY is filtered out, this function returns 1.  In that case,
2255     the caller should discard the key.  Otherwise, it returns 0, and
2256     the caller should handle the key, for instance, by calling the
2257     function minput_lookup () with the same key.  */
2258
2259 /***ja
2260     @brief ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ë.
2261
2262     ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Ë±þ
2263     ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥­¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½
2264     ¤·¤¿ºÝ¤Ë¤Ï¤½¤ì¤¾¤ì#Minput_preedit_draw, #Minput_status_draw,
2265     #Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£
2266
2267     @return 
2268     $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¸Æ¤Ó
2269     ½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó
2270     ½Ð¤·Â¦¤Ï¡¢¤¿¤È¤¨¤ÐƱ¤¸¥­¡¼¤Ç´Ø¿ô minput_lookup () ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢
2271     ¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£
2272
2273     @latexonly \IPAlabel{minput_filter} @endlatexonly
2274 */
2275
2276 int
2277 minput_filter (MInputContext *ic, MSymbol key, void *arg)
2278 {
2279   int ret;
2280
2281   if (! ic
2282       || ! ic->active)
2283     return 0;
2284   ret = (*ic->im->driver.filter) (ic, key, arg);
2285
2286   if (ic->im->driver.callback_list)
2287     {
2288       if (ic->preedit_changed)
2289         minput__callback (ic, Minput_preedit_draw);
2290       if (ic->status_changed)
2291         minput__callback (ic, Minput_status_draw);
2292       if (ic->candidates_changed)
2293         minput__callback (ic, Minput_candidates_draw);
2294       ic->preedit_changed = ic->status_changed = ic->candidates_changed = 0;
2295     }
2296
2297   return ret;
2298 }
2299
2300 /*=*/
2301
2302 /***en
2303     @brief Lookup a text produced in the input context.
2304
2305     The minput_lookup () function looks up a text in the input context
2306     $IC.  $KEY must be the same one provided to the previous call of
2307     minput_filter ().
2308
2309     If a text was produced by the input method, it is concatenated
2310     to M-text $MT.
2311
2312     This function calls #MInputDriver::lookup .
2313
2314     @return
2315     If $KEY was correctly handled by the input method, this function
2316     returns 0.  Otherwise, returns -1, even in that case, some text
2317     may be produced in $MT.  */
2318
2319 /***ja
2320     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥ÈÃæ¤Î¥Æ¥­¥¹¥È¤Î¸¡º÷.
2321
2322     ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤ò¸¡º÷¤¹
2323     ¤ë¡£$KEY ¤Ï´Ø¿ôminput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î
2324     ¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
2325
2326     ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥Æ¥­¥¹¥È¤Ï M-text
2327     $MT ¤ËÏ¢·ë¤µ¤ì¤ë¡£
2328
2329     ¤³¤Î´Ø¿ô¤Ï¡¢#MInputDriver::lookup ¤ò¸Æ¤Ö¡£
2330
2331     @return 
2332     $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤òÊÖ¤¹¡£
2333     ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¤Ç¤â $MT ¤Ë²¿¤é¤«¤Î¥Æ¥­¥¹¥È¤¬À¸
2334     À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£
2335
2336     @latexonly \IPAlabel{minput_lookup} @endlatexonly  */
2337
2338 int
2339 minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
2340 {
2341   return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1);
2342 }
2343 /*=*/
2344
2345 /***en
2346     @brief Set the spot of the input context.
2347
2348     The minput_set_spot () function set the spot of input context $IC
2349     to coordinate ($X, $Y ) with the height $ASCENT and $DESCENT .
2350     The semantics of these values depend on the input method driver.
2351     $FONTSIZE specfies the fontsize of a preedit text in 1/10 point.
2352
2353     For instance, an driver designed to work in CUI environment may
2354     use $X and $Y as column and row numbers, and ignore $ASCENT and
2355     $DESCENT .  An driver designed to work on a window system may
2356     treat $X and $Y as pixel offsets relative to the origin of the
2357     client window, and treat $ASCENT and $DESCENT as ascent and
2358     descent pixels of a line at ($X . $Y ).
2359
2360     $MT and $POS is an M-text and a character position at the spot.
2361     $MT may be @c NULL, in which case, the input method cannot get
2362     information about the text around the spot.  */
2363
2364 /***ja
2365     @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë
2366
2367     ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂ
2368     É¸ ($X, $Y )¤Ë ¡¢¹â¤µ $ASCENT¡¢ $DESCENT ¤ÇÀßÄꤹ¤ë¡£ ¤³¤ì¤é¤ÎÃͤÎ
2369     °ÕÌ£¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë¡£$FONTSIZE ¤Ïpreedit ¥Æ¥­¥¹¥È
2370     ¤Î¥Õ¥©¥ó¥È¥µ¥¤¥º¤ò 1/10 ¥Ý¥¤¥ó¥Èñ°Ì¤Ç»ØÄꤹ¤ë¡£
2371
2372     ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ë¥É¥é¥¤¥Ð¤Ï $X ¤È $Y ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô¤Î
2373     ÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT ¤È $DESCENT ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿
2374     ¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤΥɥ饤¥Ð¤Ï $X ¤È $Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É¥¦
2375     ¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢
2376     $ASCENT ¤È $DESCENT ¤ò ($X . $Y ) ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯
2377     ¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£
2378
2379     $MT ¤È $POS ¤Ï¤½¤Î¥¹¥Ý¥Ã¥È¤Î M-text ¤Èʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$MT ¤Ï @c
2380     NULL ¤Ç¤â¤è¤¯¡¢¤½¤Î¾ì¹ç¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤Ï¥¹¥Ý¥Ã¥È¼þÊդΥƥ­¥¹¥È¤Ë
2381     ´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£
2382     */
2383
2384 void
2385 minput_set_spot (MInputContext *ic, int x, int y,
2386                  int ascent, int descent, int fontsize,
2387                  MText *mt, int pos)
2388 {
2389   ic->spot.x = x;
2390   ic->spot.y = y;
2391   ic->spot.ascent = ascent;
2392   ic->spot.descent = descent;
2393   ic->spot.fontsize = fontsize;
2394   ic->spot.mt = mt;
2395   ic->spot.pos = pos;
2396   if (ic->im->driver.callback_list)
2397     minput__callback (ic, Minput_set_spot);
2398 }
2399 /*=*/
2400
2401 /***en
2402     @brief Toggle input method.
2403
2404     The minput_toggle () function toggles the input method associated
2405     with the input context $IC.  */
2406 /***ja
2407     @brief ÆþÎϥ᥽¥Ã¥É¤òÀÚÂؤ¨¤ë.
2408
2409     ´Ø¿ô minput_toggle () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ËÂбþÉÕ¤±¤é¤ì¤¿ÆþÎÏ
2410     ¥á¥½¥Ã¥É¤ò¥È¥°¥ë¤¹¤ë¡£
2411     */
2412
2413 void
2414 minput_toggle (MInputContext *ic)
2415 {
2416   if (ic->im->driver.callback_list)
2417     minput__callback (ic, Minput_toggle);
2418   ic->active = ! ic->active;
2419 }
2420
2421
2422 /*** @} */
2423 /*=*/
2424 /*** @addtogroup m17nDebug */
2425 /*=*/
2426 /*** @{  */
2427 /*=*/
2428
2429 /***en
2430     @brief Dump an input method.
2431
2432     The mdebug_dump_im () function prints the input method $IM in a
2433     human readable way to the stderr.  $INDENT specifies how many
2434     columns to indent the lines but the first one.
2435
2436     @return
2437     This function returns $IM.  */
2438 /***ja
2439     @brief ÆþÎϥ᥽¥Ã¥É¤ò¥À¥ó¥×¤¹¤ë.
2440
2441     ´Ø¿ô mdebug_dump_im () ¤ÏÆþÎϥ᥽¥Ã¥É $IM ¤ò stderr ¤Ë¿Í´Ö¤Ë²ÄÆɤÊ
2442     ·Á¤Ç°õºþ¤¹¤ë¡£$INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
2443
2444     @return
2445     ¤³¤Î´Ø¿ô¤Ï $IM ¤òÊÖ¤¹¡£  */
2446
2447 MInputMethod *
2448 mdebug_dump_im (MInputMethod *im, int indent)
2449 {
2450   MInputMethodInfo *im_info = (MInputMethodInfo *) im->info;
2451   char *prefix;
2452
2453   prefix = (char *) alloca (indent + 1);
2454   memset (prefix, 32, indent);
2455   prefix[indent] = '\0';
2456
2457   fprintf (stderr, "(input-method %s %s ", msymbol_name (im->language),
2458            msymbol_name (im->name));
2459   mdebug_dump_mtext (im_info->title, 0, 0);
2460   if (im->name != Mnil)
2461     {
2462       MPlist *state;
2463
2464       MPLIST_DO (state, im_info->states)
2465         {
2466           fprintf (stderr, "\n%s  ", prefix);
2467           dump_im_state (MPLIST_VAL (state), indent + 2);
2468         }
2469     }
2470   fprintf (stderr, ")");
2471   return im;
2472 }
2473
2474 /*** @} */ 
2475
2476 /*
2477   Local Variables:
2478   coding: euc-japan
2479   End:
2480 */