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