2c1ac4264a5433e28fb9cecca52e73753ddb7aaa
[m17n/m17n-lib.git] / src / input-gui.c
1 /* input-gui.c -- gui-based input method module.
2    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
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., 51 Franklin Street, Fifth Floor,
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nInputMethodWin
25     @brief Input method support on window systems.
26
27     The input driver @c minput_gui_driver is provided for internal
28     input methods that is useful on window systems.  It displays
29     preedit text and status text at the inputting spot.  See the
30     documentation of @c minput_gui_driver for more details.
31
32     In the m17n-X library, the foreign input method of name @c Mxim is
33     provided.  It uses XIM (X Input Method) as a background input
34     engine.  The symbol @c Mxim has a property @c Minput_driver whose
35     value is a pointer to the input driver @c minput_xim_driver.  See
36     the documentation of @c minput_xim_driver for more details.  */
37
38 /***ja
39     @addtogroup m17nInputMethodWin
40     @brief ¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à¾å¤ÎÆþÎϥ᥽¥Ã¥É¤Î¥µ¥Ý¡¼¥È.
41
42     ÆþÎϥɥ饤¥Ð @c minput_gui_driver ¤Ï¡¢
43     ¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à¾å¤ÇÍѤ¤¤é¤ì¤ëÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤Ç¤¢¤ë¡£
44     ¤³¤Î¥É¥é¥¤¥Ð¤ÏÆþÎÏ¥¹¥Ý¥Ã¥È¤Ë preedit ¥Æ¥­¥¹¥È¤È status 
45     ¥Æ¥­¥¹¥È¤òɽ¼¨¤¹¤ë¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï @c minput_gui_driver ¤ÎÀâÌÀ¤ò»²¾È¤Î¤³¤È¡£
46
47     m17n-X ¥é¥¤¥Ö¥é¥ê¤Ï¡¢@c Mxim ¤È¸À¤¦Ì¾Á°¤ò»ý¤Ä³°ÉôÆþÎϥ᥽¥Ã¥É¤òÄ󶡤·¤Æ¤¤¤ë¡£¤³¤ì¤Ï 
48     XIM (X Input Method) ¤ò¥Ð¥Ã¥¯¥°¥é¥¦¥ó¥É¤ÎÆþÎÏ¥¨¥ó¥¸¥ó¤È¤·¤ÆÍøÍѤ¹¤ë¡£¥·¥ó¥Ü¥ë
49     @c Mxim ¤Ï @c Minput_driver ¤È¤¤¤¦¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ã¤Æ¤ª¤ê¡¢¤½¤ÎÃͤÏÆþÎϥɥ饤¥Ð 
50     @c minput_xim_driver ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£ ¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï 
51     @c minput_xim_driver ¤ÎÀâÌÀ¤ò»²¾È¤Î¤³¤È¡£  */
52
53 /*=*/
54
55 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
56 /*** @addtogroup m17nInternal
57      @{ */
58
59 #include <string.h>
60 #include <ctype.h>
61
62 #include "config.h"
63 #include "m17n-gui.h"
64 #include "m17n-misc.h"
65 #include "internal.h"
66 #include "internal-gui.h"
67 #include "input.h"
68
69 typedef struct
70 {
71   MDrawWindow win;
72   MDrawMetric geometry;
73   MDrawControl control;
74   int mapped;
75 } MInputGUIWinInfo;
76
77 typedef struct
78 {
79   MInputContextInfo *ic_info;
80
81   MFrame *frame;
82   /* <geometry>.x and <geometry>.y are not used.  */
83   MInputGUIWinInfo client;
84   /* In the following members, <geometry> is relative to <client>.  */
85   MInputGUIWinInfo focus;
86   MInputGUIWinInfo preedit;
87   MInputGUIWinInfo status;
88   MInputGUIWinInfo candidates;
89 } MInputGUIContextInfo;
90
91 static MFace *status_face;
92 static MFaceBoxProp face_box_prop;
93
94 static int
95 win_create_ic (MInputContext *ic)
96 {
97   MInputGUIContextInfo *win_ic_info;
98   MInputGUIArgIC *win_info = (MInputGUIArgIC *) ic->arg;
99   MFrame *frame = win_info->frame;
100
101   if ((*minput_default_driver.create_ic) (ic) < 0)
102     return -1;
103
104   MSTRUCT_CALLOC (win_ic_info, MERROR_IM);
105   win_ic_info->ic_info = (MInputContextInfo *) ic->info;
106   win_ic_info->frame = frame;
107   win_ic_info->client.win = win_info->client;
108   (*frame->driver->window_geometry) (frame, win_info->client, win_info->client,
109                          &win_ic_info->client.geometry);
110   win_ic_info->focus.win = win_info->focus;
111   (*frame->driver->window_geometry) (frame, win_info->focus, win_info->client,
112                          &win_ic_info->focus.geometry);
113
114   win_ic_info->preedit.win = (*frame->driver->create_window) (frame, win_info->client);
115   win_ic_info->preedit.control.two_dimensional = 1;
116   win_ic_info->preedit.control.as_image = 0;
117   win_ic_info->preedit.control.with_cursor = 1;
118   win_ic_info->preedit.control.cursor_width = 1;
119   win_ic_info->preedit.control.enable_bidi = 1;
120   win_ic_info->preedit.geometry.x = -1;
121   win_ic_info->preedit.geometry.y = -1;
122
123   win_ic_info->status.win = (*frame->driver->create_window) (frame, win_info->client);
124   win_ic_info->status.control.as_image = 1;
125   win_ic_info->status.control.enable_bidi = 1;
126
127   win_ic_info->candidates.win = (*frame->driver->create_window) (frame, win_info->client);
128   win_ic_info->candidates.control.as_image = 1;
129
130   ic->info = win_ic_info;
131
132   return 0;
133 }
134
135 static void
136 win_destroy_ic (MInputContext *ic)
137 {
138   MInputGUIContextInfo *win_ic_info = (MInputGUIContextInfo *) ic->info;
139   MInputContextInfo *ic_info = (MInputContextInfo *) win_ic_info->ic_info;
140   MFrame *frame = win_ic_info->frame;
141
142   (*frame->driver->destroy_window) (frame, win_ic_info->preedit.win);
143   (*frame->driver->destroy_window) (frame, win_ic_info->status.win);
144   (*frame->driver->destroy_window) (frame, win_ic_info->candidates.win);
145   ic->info = ic_info;
146   (*minput_default_driver.destroy_ic) (ic);
147   free (win_ic_info);
148 }
149
150 static int
151 win_filter (MInputContext *ic, MSymbol key, void *arg)
152 {
153   MInputGUIContextInfo *win_ic_info = (MInputGUIContextInfo *) ic->info;
154   MInputContextInfo *ic_info = (MInputContextInfo *) win_ic_info->ic_info;
155   int ret;
156
157   if (! ic
158       || ! ic->active)
159     return 0;
160
161   if (key == Mnil && arg)
162     {
163       key = minput_event_to_key (win_ic_info->frame, arg);
164       if (key == Mnil)
165         return 1;
166     }
167   ic->info = ic_info;
168   ret = (*minput_default_driver.filter) (ic, key, arg);
169   ic->info = win_ic_info;
170   return ret;
171 }
172
173 static void
174 adjust_window_and_draw (MFrame *frame, MInputContext *ic, MText *mt, int type)
175 {
176   MInputGUIContextInfo *win_ic_info = (MInputGUIContextInfo *) ic->info;
177   MDrawControl *control;
178   MDrawWindow win;
179   MDrawMetric *geometry, physical, logical;
180   int xoff = win_ic_info->focus.geometry.x;
181   int yoff = win_ic_info->focus.geometry.y;
182   int x0, x1, y0, y1;
183   int len = mtext_nchars (mt);
184
185   if (type == 0)
186     {
187       win = win_ic_info->preedit.win;
188       control = &win_ic_info->preedit.control;
189       geometry = &win_ic_info->preedit.geometry;
190       len++;
191     }
192   else if (type == 1)
193     {
194       win = win_ic_info->status.win;
195       control = &win_ic_info->status.control;
196       geometry = &win_ic_info->status.geometry;
197     }
198   else
199     {
200       win = win_ic_info->candidates.win;
201       control = &win_ic_info->candidates.control;
202       geometry = &win_ic_info->candidates.geometry;
203     }
204
205   mdraw_text_extents (frame, mt, 0, len, control, &physical, &logical, NULL);
206   x0 = physical.x, x1 = x0 + physical.width;
207   y0 = physical.y, y1 = y0 + physical.height;
208   if (x0 > logical.x)
209     x0 = logical.x;
210   if (x1 < logical.x + logical.width)
211     x1 = logical.x + logical.width;
212   if (y0 > logical.y)
213     y0 = logical.y;
214   if (y1 < logical.y + logical.height)
215     y1 = logical.y + logical.height;
216   physical.width = x1 - x0;
217   physical.height = y1 - y0;
218   physical.x = xoff + ic->spot.x;
219   if (physical.x + physical.width > win_ic_info->client.geometry.width)
220     physical.x = win_ic_info->client.geometry.width - physical.width;
221   if (type == 0)
222     {
223       if (len <= 1)
224         {
225           physical.height = physical.width = 1;
226           physical.x = physical.y = -1;
227         }
228       else
229         {
230           if (y0 > - ic->spot.ascent)
231             {
232               physical.height += y0 + ic->spot.ascent;
233               y0 = - ic->spot.ascent;
234             }
235           if (y1 < ic->spot.descent)
236             {
237               physical.height += ic->spot.descent - y1;
238             }
239           physical.y = yoff + ic->spot.y + y0;
240         }
241     }
242   else if (type == 1)
243     {
244       physical.y = yoff + ic->spot.y + ic->spot.descent + 2;
245       if (physical.y + physical.height > win_ic_info->client.geometry.height
246           && yoff + ic->spot.y - ic->spot.ascent - 2 - physical.height >= 0)
247         physical.y = yoff + ic->spot.y - ic->spot.ascent - 2 - physical.height;
248     }
249   else
250     {
251       if (win_ic_info->status.mapped)
252         {
253           /* We assume that status is already drawn.  */
254           if (win_ic_info->status.geometry.y < yoff + ic->spot.y)
255             /* As there was no lower room for status, candidates must also
256                be drawn upper.  */
257             physical.y = win_ic_info->status.geometry.y - 1 - physical.height;
258           else
259             {
260               /* There was a lower room for status.  */
261               physical.y = (win_ic_info->status.geometry.y
262                             + win_ic_info->status.geometry.height
263                             + 1);
264               if (physical.y + physical.height
265                   > win_ic_info->client.geometry.height)
266                 /* But not for candidates.  */
267                 physical.y = (yoff + ic->spot.y - ic->spot.ascent - 1
268                               - physical.height);
269             }
270         }
271       else
272         {
273           physical.y = yoff + ic->spot.y + ic->spot.descent + 2;
274           if ((physical.y + physical.height
275                > win_ic_info->client.geometry.height)
276               && (yoff + ic->spot.y - ic->spot.ascent - 2 - physical.height
277                   >= 0))
278             physical.y = (yoff + ic->spot.y - ic->spot.ascent - 2
279                           - physical.height);
280         }
281     }
282
283   (*frame->driver->adjust_window) (frame, win, geometry, &physical);
284   mdraw_text_with_control (frame, win, -x0, -y0, mt, 0, len, control);
285 }
286
287 static void
288 win_callback (MInputContext *ic, MSymbol command)
289 {
290   MInputGUIContextInfo *win_ic_info = (MInputGUIContextInfo *) ic->info;
291   MFrame *frame = win_ic_info->frame;
292
293   if (command == Minput_preedit_draw)
294     {
295       MText *mt;
296       MFace *face = mface ();
297
298       if (! win_ic_info->preedit.mapped)
299         {
300           (*frame->driver->map_window) (frame, win_ic_info->preedit.win);
301           win_ic_info->preedit.mapped = 1;
302         }
303       win_ic_info->preedit.control.cursor_pos = ic->cursor_pos;
304       if (ic->spot.fontsize)
305         mface_put_prop (face, Msize, (void *) ic->spot.fontsize);
306       mface_merge (face, mface_underline);
307       mtext_push_prop (ic->preedit, 0, mtext_nchars (ic->preedit),
308                        Mface, face);
309       M17N_OBJECT_UNREF (face);
310       if (ic->im->language != Mnil)
311         mtext_put_prop (ic->preedit, 0, mtext_nchars (ic->preedit), Mlanguage,
312                         ic->im->language);
313       if (ic->candidate_list && ic->candidate_show)
314         mtext_push_prop (ic->preedit, ic->candidate_from, ic->candidate_to,
315                          Mface, mface_reverse_video);
316       if (mtext_nchars (ic->produced) == 0)
317         mt = ic->preedit;
318       else
319         {
320           mt = mtext_dup (ic->produced);
321           mtext_cat (mt, ic->preedit);
322           win_ic_info->preedit.control.cursor_pos
323             += mtext_nchars (ic->produced);
324         }
325       adjust_window_and_draw (frame, ic, mt, 0);
326       if (ic->candidate_list)
327         mtext_pop_prop (ic->preedit, 0, mtext_nchars (ic->preedit), Mface);
328       mtext_pop_prop (ic->preedit, 0, mtext_nchars (ic->preedit), Mface);
329       if (mtext_nchars (ic->produced) != 0)
330         M17N_OBJECT_UNREF (mt);
331     }
332   else if (command == Minput_status_draw)
333     {
334       if (! win_ic_info->client.win)
335         return;
336       mtext_put_prop (ic->status, 0, mtext_nchars (ic->status), Mface,
337                       status_face);
338       if (ic->im->language != Mnil)
339         mtext_put_prop (ic->status, 0, mtext_nchars (ic->status), Mlanguage,
340                         ic->im->language);
341       adjust_window_and_draw (frame, ic, ic->status, 1);
342     }
343   else if (command == Minput_candidates_draw)
344     {
345       MPlist *group;
346       MText *mt;
347       int i, len;
348       int from, to;
349
350       if (! ic->candidate_list || ! ic->candidate_show)
351         {
352           if (win_ic_info->candidates.mapped)
353             {
354               (*frame->driver->unmap_window) (frame, win_ic_info->candidates.win);
355               win_ic_info->candidates.mapped = 0;
356             }
357           return;
358         }
359
360       if (! win_ic_info->candidates.mapped)
361         {
362           (*frame->driver->map_window) (frame, win_ic_info->candidates.win);
363           win_ic_info->candidates.mapped = 1;
364         }
365
366       i = 0;
367       group = ic->candidate_list;
368       while (1)
369         {
370           if (mplist_key (group) == Mtext)
371             len = mtext_len (mplist_value (group));
372           else
373             len = mplist_length (mplist_value (group));
374           if (i + len > ic->candidate_index)
375             break;
376           i += len;
377           group = mplist_next (group);
378         }
379
380       mt = mtext ();
381       if (mplist_key (group) == Mtext)
382         {
383           MText *candidates = (MText *) mplist_value (group);
384
385           from = (ic->candidate_index - i) * 2 + 1;
386           to = from + 1;
387           for (i = 0; i < len; i++)
388             {
389               mtext_cat_char (mt, ' ');
390               mtext_cat_char (mt, mtext_ref_char (candidates, i));
391             }
392         }
393       else
394         {
395           MPlist *pl;
396
397           for (pl = (MPlist *) mplist_value (group);
398                i < ic->candidate_index && mplist_key (pl) != Mnil;
399                i++, pl = mplist_next (pl))
400             {
401               mtext_cat_char (mt, ' ');
402               mtext_cat (mt, (MText *) mplist_value (pl));
403             }
404           from = mtext_nchars (mt) + 1;
405           to = from + mtext_nchars ((MText *) mplist_value (pl));
406           for (; mplist_key (pl) != Mnil; pl = mplist_next (pl))
407             {
408               mtext_cat_char (mt, ' ');
409               mtext_cat (mt, (MText *) mplist_value (pl));
410             }
411         }
412       mtext_cat_char (mt, ' ');
413       mtext_push_prop (mt, 0, mtext_nchars (mt), Mface, status_face);
414       mtext_push_prop (mt, from, to, Mface, mface_reverse_video);
415       if (ic->im->language != Mnil)
416         mtext_put_prop (mt, 0, mtext_nchars (mt), Mlanguage, ic->im->language);
417       adjust_window_and_draw (frame, ic, mt, 2);
418       M17N_OBJECT_UNREF (mt);
419     }
420   else if (command == Minput_set_spot)
421     {
422       minput_callback (ic, Minput_preedit_draw);
423       minput_callback (ic, Minput_status_draw);
424       minput_callback (ic, Minput_candidates_draw);
425     }
426   else if (command == Minput_toggle)
427     {
428       if (ic->active)
429         {
430           minput_callback (ic, Minput_preedit_done);
431           minput_callback (ic, Minput_status_done);
432           minput_callback (ic, Minput_candidates_done);
433         }
434       else
435         {
436           minput_callback (ic, Minput_preedit_start);
437           minput_callback (ic, Minput_status_start);
438           minput_callback (ic, Minput_candidates_start);
439         }
440     }
441   else if (command == Minput_preedit_start)
442     {
443     }
444   else if (command == Minput_preedit_done)
445     {
446       if (win_ic_info->preedit.mapped)
447         {
448           (*frame->driver->unmap_window) (frame, win_ic_info->preedit.win);
449           win_ic_info->preedit.mapped = 0;
450         }
451     }
452   else if (command == Minput_status_start)
453     {
454       if (! win_ic_info->status.mapped)
455         {
456           (*frame->driver->map_window) (frame, win_ic_info->status.win);
457           win_ic_info->status.mapped = 1;
458         }
459     }
460   else if (command == Minput_status_done)
461     {
462       if (win_ic_info->status.mapped)
463         {
464           (*frame->driver->unmap_window) (frame, win_ic_info->status.win);
465           win_ic_info->status.mapped = 0;
466         }
467     }
468   else if (command == Minput_candidates_start)
469     {
470       if (! win_ic_info->candidates.mapped)
471         {
472           (*frame->driver->map_window) (frame, win_ic_info->candidates.win);
473           win_ic_info->candidates.mapped = 1;
474         }
475     }
476   else if (command == Minput_candidates_done)
477     {
478       if (win_ic_info->candidates.mapped)
479         {
480           (*frame->driver->unmap_window) (frame, win_ic_info->candidates.win);
481           win_ic_info->candidates.mapped = 0;
482         }
483     }
484   else if (command == Minput_reset)
485     {
486       MInputCallbackFunc func;
487
488       if (minput_default_driver.callback_list
489           && (func = ((MInputCallbackFunc)
490                       mplist_get_func (minput_default_driver.callback_list,
491                                        Minput_reset))))
492         {
493           MInputContextInfo *ic_info
494             = (MInputContextInfo *) win_ic_info->ic_info;
495           ic->info = ic_info;
496           (func) (ic, Minput_reset);
497           ic->info = win_ic_info;
498         }
499       if (ic->preedit_changed)
500         minput_callback (ic, Minput_preedit_draw);
501       if (ic->status_changed)
502         minput_callback (ic, Minput_status_draw);
503       if (ic->candidates_changed)
504         minput_callback (ic, Minput_candidates_draw);
505     }
506 }
507
508 static int
509 win_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
510 {
511   MInputGUIContextInfo *win_ic_info = (MInputGUIContextInfo *) ic->info;
512   MInputContextInfo *ic_info = (MInputContextInfo *) win_ic_info->ic_info;
513   int ret;
514
515   ic->info = ic_info;
516   ret = (*minput_default_driver.lookup) (ic, key, arg, mt);
517   ic->info = win_ic_info;
518   return ret;
519 }
520
521 \f
522
523 int
524 minput__win_init ()
525 {
526   minput_gui_driver = minput_default_driver;
527
528   minput_gui_driver.create_ic = win_create_ic;
529   minput_gui_driver.destroy_ic = win_destroy_ic;
530   minput_gui_driver.filter = win_filter;
531   minput_gui_driver.lookup = win_lookup;
532   {
533     MPlist *plist = mplist ();
534
535     minput_gui_driver.callback_list = plist;
536     mplist_put_func (plist, Minput_preedit_start, M17N_FUNC (win_callback));
537     mplist_put_func (plist, Minput_preedit_draw, M17N_FUNC (win_callback));
538     mplist_put_func (plist, Minput_preedit_done, M17N_FUNC (win_callback));
539     mplist_put_func (plist, Minput_status_start, M17N_FUNC (win_callback));
540     mplist_put_func (plist, Minput_status_draw, M17N_FUNC (win_callback));
541     mplist_put_func (plist, Minput_status_done, M17N_FUNC (win_callback));
542     mplist_put_func (plist, Minput_candidates_start, M17N_FUNC (win_callback));
543     mplist_put_func (plist, Minput_candidates_draw, M17N_FUNC (win_callback));
544     mplist_put_func (plist, Minput_candidates_done, M17N_FUNC (win_callback));
545     mplist_put_func (plist, Minput_set_spot, M17N_FUNC (win_callback));
546     mplist_put_func (plist, Minput_toggle, M17N_FUNC (win_callback));
547     mplist_put_func (plist, Minput_reset, M17N_FUNC (win_callback));
548   }
549 #if 0
550   /* This will make the caller of minput_method_open() pazzled.  */
551   minput_driver = &minput_gui_driver;
552 #endif
553
554   face_box_prop.width = 1;
555   face_box_prop.color_top = face_box_prop.color_left
556     = face_box_prop.color_bottom = face_box_prop.color_right
557     = msymbol ("black");
558   face_box_prop.inner_hmargin = face_box_prop.inner_vmargin = 2;
559   face_box_prop.outer_hmargin = face_box_prop.outer_vmargin = 1;
560   status_face = mface ();
561   mface_put_prop (status_face, Mbox, &face_box_prop);
562
563   return 0;
564 }
565
566 void
567 minput__win_fini ()
568 {
569   M17N_OBJECT_UNREF (status_face);
570   if (minput_gui_driver.callback_list)
571     {
572       M17N_OBJECT_UNREF (minput_gui_driver.callback_list);
573       minput_gui_driver.callback_list = NULL;
574     }
575 }
576
577 /*** @} */
578 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
579
580 \f
581 /* External API */
582
583 /*** @addtogroup m17nInputMethodWin */
584 /*** @{ */
585
586 /*=*/
587 /***en
588     @brief Input driver for internal input methods on window systems.
589
590     The input driver @c minput_gui_driver is for internal input
591     methods to be used on window systems.
592
593     It creates sub-windows for a preedit text and a status text, and
594     displays them at the input spot set by the function
595     minput_set_spot ().
596
597     The macro M17N_INIT () set the variable @c minput_driver to the
598     pointer to this driver so that all internal input methods use it.
599
600     Therefore, unless @c minput_driver is changed from the default,
601     the driver dependent arguments to the functions whose name begin
602     with minput_ must are treated as follows.
603
604     The argument $ARG of the function minput_open_im () is ignored.
605
606     The argument $ARG of the function minput_create_ic () must be a
607     pointer to the structure @c MInputGUIArgIC.  See the documentation
608     of @c MInputGUIArgIC for more details.
609
610     If the argument $KEY of function minput_filter () is @c Mnil, the
611     argument $ARG must be a pointer to the object of type @c XEvent.
612     In that case, $KEY is generated from $ARG.
613
614     The argument $ARG of the function minput_lookup () must be the
615     same one as that of the function minput_filter (). */
616
617 /***ja
618     @brief ¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à¤ÎÆâÉôÆþÎϥ᥽¥Ã¥ÉÍÑÆþÎϥɥ饤¥Ð.
619
620     ÆþÎϥɥ饤¥Ð @c minput_gui_driver
621     ¤Ï¡¢¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à¾å¤ÇÍѤ¤¤é¤ì¤ëÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð¤Ç¤¢¤ë¡£
622
623     ¤³¤Î¥É¥é¥¤¥Ð¤Ï¡¢´Ø¿ô minput_set_spot () ¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤¿ÆþÎÏ¥¹¥Ý¥Ã¥È¤Ë
624     preedit ¥Æ¥­¥¹¥ÈÍѤΥµ¥Ö¥¦¥£¥ó¥É¥¦¤È status 
625     ¥Æ¥­¥¹¥ÈÍѤΥµ¥Ö¥¦¥£¥ó¥É¥¦¤òºî¤ê¡¢¤½¤ì¤¾¤ì¤òɽ¼¨¤¹¤ë¡£
626
627     ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô @c minput_driver 
628     ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
629
630     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
631     ¤Ç»Ï¤Þ¤ë̾Á°¤ò»ý¤Ä´Ø¿ô¤Î°ú¿ô¤Î¤¦¤Á¥É¥é¥¤¥Ð°Í¸¤Î¤â¤Î¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£
632
633     ´Ø¿ô minput_open_im () ¤Î°ú¿ô $ARG ¤Ï̵»ë¤µ¤ì¤ë¡£
634
635     ´Ø¿ô minput_create_ic () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ@c MInputGUIArgIC 
636     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï @c MInputGUIArgIC 
637     ¤ÎÀâÌÀ¤ò»²¾È¤Î¤³¤È¡£
638
639     ´Ø¿ô minput_filter () ¤Î°ú¿ô $ARG ¤¬ @c Mnil ¤Î¾ì¹ç¡¢ $ARG ¤Ï @c
640     XEvent ·¿¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç 
641     $KEY ¤Ï $ARG ¤«¤éÀ¸À®¤µ¤ì¤ë¡£
642
643     ´Ø¿ô minput_lookup () ¤Î°ú¿ô $ARG ¤Ï´Ø¿ô minput_filter () ¤Î°ú¿ô 
644     $ARG ¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ */
645
646 MInputDriver minput_gui_driver;
647
648 /*=*/
649
650 /***en
651     @brief Symbol of the name "xim".
652
653     The variable Mxim is a symbol of name "xim".  It is a name of the
654     input method driver #minput_xim_driver.  */ 
655 /***ja
656     @brief "xim"¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë .
657
658     ÊÑ¿ô Mxim ¤Ï"xim"¤ò̾Á°¤È¤·¤Æ»ý¤Ä¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£"xim" 
659     ¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð #minput_xim_driver ¤Î̾Á°¤Ç¤¢¤ë¡£  */ 
660
661 MSymbol Mxim;
662
663 /*=*/
664
665 /***en
666     @brief Convert an event to an input key.
667
668     The minput_event_to_key () function returns the input key
669     corresponding to event $EVENT on $FRAME by a window system
670     dependent manner.
671
672     In the m17n-X library, $EVENT must be a pointer to the structure
673     @c XKeyEvent, and it is handled as below.
674
675     At first, the keysym name of $EVENT is acquired by the function @c
676     XKeysymToString.  Then, the name is modified as below.
677
678     If the name is one of "a" .. "z" and $EVENT has a Shift modifier,
679     the name is converted to "A" .. "Z" respectively, and the Shift
680     modifier is cleared.
681
682     If the name is one byte length and $EVENT has a Control modifier,
683     the byte is bitwise anded by 0x1F and the Control modifier is
684     cleared.
685
686     If $EVENT still has modifiers, the name is preceded by "S-"
687     (Shift), "C-" (Control), "M-" (Meta), "A-" (Alt), "s-" (Super),
688     and/or "H-" (Hyper) in this order.
689
690     For instance, if the keysym name is "a" and the event has Shift,
691     Meta, and Hyper modifiers, the resulting name is "M-H-A".
692
693     At last, a symbol who has the name is returned.  */
694
695 /***ja
696     @brief ¥¤¥Ù¥ó¥È¤òÆþÎÏ¥­¡¼¤ËÊÑ´¹¤¹¤ë.
697
698     ´Ø¿ô minput_event_to_key () ¤Ï¡¢$FRAME ¤Î¥¤¥Ù¥ó¥È $EVENT 
699     ¤ËÂбþ¤¹¤ëÆþÎÏ¥­¡¼¤òÊÖ¤¹¡£¤³¤³¤Ç¤Î¡ÖÂбþ¡×¤Ï¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à¤Ë°Í¸¤¹¤ë¡£
700
701     m17n-X ¥é¥¤¥Ö¥é¥ê¤Î¾ì¹ç¤Ë¤Ï¡¢$EVENT ¤Ï ¹½Â¤ÂΠ@c XKeyEvent 
702     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ê¡¢¼¡¤Î¤è¤¦¤Ë½èÍý¤µ¤ì¤ë¡£
703
704     ¤Þ¤º¡¢´Ø¿ô @c XKeysymToString ¤Ë¤è¤Ã¤Æ¡¢$EVENT ¤Î keysym 
705     Ì¾¤ò¼èÆÀ¤·¡¢¼¡¤¤¤Ç°Ê²¼¤ÎÊѹ¹¤ò²Ã¤¨¤ë¡£
706
707     Ì¾Á°¤¬ "a" .. "z" ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤Ã¤Æ $EVENT ¤Ë Shift 
708     ¥â¥Ç¥£¥Õ¥¡¥¤¥¢¤¬¤¢¤ì¤Ð¡¢Ì¾Á°¤Ï¤½¤ì¤¾¤ì "A" .. "Z" ¤ËÊÑ´¹¤µ¤ì¡¢Shift 
709     ¥â¥Ç¥£¥Õ¥¡¥¤¥¢¤Ï¼è¤ê½ü¤«¤ì¤ë¡£
710
711     Ì¾Á°¤¬£±¥Ð¥¤¥ÈŤǠ$EVENT ¤Ë Control ¥â¥Ç¥£¥Õ¥¡¥¤¥¢¤¬¤¢¤ì¤Ð¡¢Ì¾Á°¤È
712     0x1F ¤È¤ò¥Ó¥Ã¥Èñ°Ì¤Ç and ±é»»¤·¡¢Control ¥â¥Ç¥£¥Õ¥¡¥¤¥¢¤Ï¼è¤ê½ü¤«¤ì¤ë¡£
713
714     ¤½¤ì¤Ç¤â $EVENT ¤Ë¤Þ¤À¥â¥Ç¥£¥Õ¥¡¥¤¥¢¤¬¤¢¤ì¤Ð¡¢Ì¾Á°¤ÎÁ°¤Ë¤½¤ì¤¾¤ì
715     "S-" (Shift), "C-" (Control), "M-" (Meta), "A-" (Alt), "s-"
716     (Super), "H-" (Hyper)¤¬¤³¤Î½çÈÖ¤ÇÉÕ¤¯¡£
717     
718     ¤¿¤È¤¨¤Ð¡¢keysym Ì¾¤¬ "a" ¤Ç¥¤¥Ù¥ó¥È¤¬ Shift, Meta, and Hyper 
719     ¥â¥Ç¥£¥Õ¥¡¥¤¥¢¤ò»ý¤Æ¤Ð¡¢ÆÀ¤é¤ì¤ë̾Á°¤Ï "M-H-A" ¤Ç¤¢¤ë¡£
720
721     ºÇ¸å¤Ë¤½¤Î̾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë¤òÊÖ¤¹¡£*/
722
723
724 MSymbol
725 minput_event_to_key (MFrame *frame, void *event)
726 {
727   int modifiers;
728   MSymbol key;
729   char *name, *str;
730
731   M_CHECK_READABLE (frame, MERROR_IM, Mnil);
732   key = (*frame->driver->parse_event) (frame, event, &modifiers);
733   if (! modifiers)
734     return key;
735
736   name = msymbol_name (key);
737   str = alloca (strlen (name) + 2 * 6 + 1);
738   str[0] = '\0';
739   if (modifiers & MINPUT_KEY_SHIFT_MODIFIER)
740     strcat (str, "S-");
741   if (modifiers & MINPUT_KEY_CONTROL_MODIFIER)
742     strcat (str, "C-");
743   if (modifiers & MINPUT_KEY_META_MODIFIER)
744     strcat (str, "M-");
745   if (modifiers & MINPUT_KEY_ALT_MODIFIER)
746     strcat (str, "A-");
747   if (modifiers & MINPUT_KEY_SUPER_MODIFIER)
748     strcat (str, "s-");
749   if (modifiers & MINPUT_KEY_HYPER_MODIFIER)
750     strcat (str, "H-");
751   strcat (str, name);
752
753   return msymbol (str);
754 }
755
756 /*** @} */
757
758 /*
759   Local Variables:
760   coding: euc-japan
761   End:
762 */