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