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