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