*** empty log message ***
[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 detail.
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 detail.  */
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 "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   mwin__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   mwin__window_geometry (frame, win_info->focus, win_info->client,
112                          &win_ic_info->focus.geometry);
113
114   win_ic_info->preedit.win = mwin__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 = mwin__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 = mwin__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
141   mwin__destroy_window (win_ic_info->frame, win_ic_info->preedit.win);
142   mwin__destroy_window (win_ic_info->frame, win_ic_info->status.win);
143   mwin__destroy_window (win_ic_info->frame, win_ic_info->candidates.win);
144   ic->info = ic_info;
145   (*minput_default_driver.destroy_ic) (ic);
146   free (win_ic_info);
147 }
148
149 static int
150 win_filter (MInputContext *ic, MSymbol key, void *arg)
151 {
152   MInputGUIContextInfo *win_ic_info = (MInputGUIContextInfo *) ic->info;
153   MInputContextInfo *ic_info = (MInputContextInfo *) win_ic_info->ic_info;
154   int ret;
155
156   if (! ic
157       || ! ic->active)
158     return 0;
159
160   if (key == Mnil)
161     {
162       if (! arg)
163         return 0;
164       key = minput_event_to_key (win_ic_info->frame, arg);
165       if (key == Mnil)
166         return 1;
167     }
168   ic->info = ic_info;
169   ret = (*minput_default_driver.filter) (ic, key, arg);
170   ic->info = win_ic_info;
171   return ret;
172 }
173
174 static void
175 adjust_window_and_draw (MFrame *frame, MInputContext *ic, MText *mt, int type)
176 {
177   MInputGUIContextInfo *win_ic_info = (MInputGUIContextInfo *) ic->info;
178   MDrawControl *control;
179   MDrawWindow win;
180   MDrawMetric *geometry, physical, logical;
181   int xoff = win_ic_info->focus.geometry.x;
182   int yoff = win_ic_info->focus.geometry.y;
183   int x0, x1, y0, y1;
184   int len = mtext_nchars (mt);
185
186   if (type == 0)
187     {
188       win = win_ic_info->preedit.win;
189       control = &win_ic_info->preedit.control;
190       geometry = &win_ic_info->preedit.geometry;
191       len++;
192     }
193   else if (type == 1)
194     {
195       win = win_ic_info->status.win;
196       control = &win_ic_info->status.control;
197       geometry = &win_ic_info->status.geometry;
198     }
199   else
200     {
201       win = win_ic_info->candidates.win;
202       control = &win_ic_info->candidates.control;
203       geometry = &win_ic_info->candidates.geometry;
204     }
205
206   mdraw_text_extents (frame, mt, 0, len, control, &physical, &logical, NULL);
207   x0 = physical.x, x1 = x0 + physical.width;
208   y0 = physical.y, y1 = y0 + physical.height;
209   if (x0 > logical.x)
210     x0 = logical.x;
211   if (x1 < logical.x + logical.width)
212     x1 = logical.x + logical.width;
213   if (y0 > logical.y)
214     y0 = logical.y;
215   if (y1 < logical.y + logical.height)
216     y1 = logical.y + logical.height;
217   physical.width = x1 - x0;
218   physical.height = y1 - y0;
219   physical.x = xoff + ic->spot.x;
220   if (physical.x + physical.width > win_ic_info->client.geometry.width)
221     physical.x = win_ic_info->client.geometry.width - physical.width;
222   if (type == 0)
223     {
224       if (len <= 1)
225         {
226           physical.height = physical.width = 1;
227           physical.x = physical.y = -1;
228         }
229       else
230         {
231           if (y0 > - ic->spot.ascent)
232             {
233               physical.height += y0 + ic->spot.ascent;
234               y0 = - ic->spot.ascent;
235             }
236           if (y1 < ic->spot.descent)
237             {
238               physical.height += ic->spot.descent - y1;
239             }
240           physical.y = yoff + ic->spot.y + y0;
241         }
242     }
243   else if (type == 1)
244     {
245       physical.y = yoff + ic->spot.y + ic->spot.descent + 2;
246       if (physical.y + physical.height > win_ic_info->client.geometry.height
247           && yoff + ic->spot.y - ic->spot.ascent - 2 - physical.height >= 0)
248         physical.y = yoff + ic->spot.y - ic->spot.ascent - 2 - physical.height;
249     }
250   else
251     {
252       if (win_ic_info->status.mapped)
253         {
254           /* We assume that status is already drawn.  */
255           if (win_ic_info->status.geometry.y < yoff + ic->spot.y)
256             /* As there was no lower room for status, candidates must also
257                be drawn upper.  */
258             physical.y = win_ic_info->status.geometry.y - 1 - physical.height;
259           else
260             {
261               /* There was a lower room for status.  */
262               physical.y = (win_ic_info->status.geometry.y
263                             + win_ic_info->status.geometry.height
264                             + 1);
265               if (physical.y + physical.height
266                   > win_ic_info->client.geometry.height)
267                 /* But not for candidates.  */
268                 physical.y = (yoff + ic->spot.y - ic->spot.ascent - 1
269                               - physical.height);
270             }
271         }
272       else
273         {
274           physical.y = yoff + ic->spot.y + ic->spot.descent + 2;
275           if ((physical.y + physical.height
276                > win_ic_info->client.geometry.height)
277               && (yoff + ic->spot.y - ic->spot.ascent - 2 - physical.height
278                   >= 0))
279             physical.y = (yoff + ic->spot.y - ic->spot.ascent - 2
280                           - physical.height);
281         }
282     }
283
284   mwin__adjust_window (frame, win, geometry, &physical);
285   mdraw_text_with_control (frame, win, -x0, -y0, mt, 0, len, control);
286 }
287
288 static void
289 win_callback (MInputContext *ic, MSymbol command)
290 {
291   MInputGUIContextInfo *win_ic_info = (MInputGUIContextInfo *) ic->info;
292   MFrame *frame = win_ic_info->frame;
293
294   if (command == Minput_preedit_draw)
295     {
296       MText *mt;
297       MFace *face = mface ();
298
299       if (! win_ic_info->preedit.mapped)
300         {
301           mwin__map_window (frame, win_ic_info->preedit.win);
302           win_ic_info->preedit.mapped = 1;
303         }
304       win_ic_info->preedit.control.cursor_pos = ic->cursor_pos;
305       if (ic->spot.fontsize)
306         mface_put_prop (face, Msize, (void *) ic->spot.fontsize);
307       mface_merge (face, mface_underline);
308       mtext_push_prop (ic->preedit, 0, mtext_nchars (ic->preedit),
309                        Mface, face);
310       M17N_OBJECT_UNREF (face);
311       if (ic->im->language != Mnil)
312         mtext_put_prop (ic->preedit, 0, mtext_nchars (ic->preedit), Mlanguage,
313                         ic->im->language);
314       if (ic->candidate_list)
315         mtext_push_prop (ic->preedit, ic->candidate_from, ic->candidate_to,
316                          Mface, mface_reverse_video);
317       if (mtext_nchars (ic->produced) == 0)
318         mt = ic->preedit;
319       else
320         {
321           mt = mtext_dup (ic->produced);
322           mtext_cat (mt, ic->preedit);
323           win_ic_info->preedit.control.cursor_pos
324             += mtext_nchars (ic->produced);
325         }
326       adjust_window_and_draw (frame, ic, mt, 0);
327       if (ic->candidate_list)
328         mtext_pop_prop (ic->preedit, 0, mtext_nchars (ic->preedit), Mface);
329       mtext_pop_prop (ic->preedit, 0, mtext_nchars (ic->preedit), Mface);
330       if (mtext_nchars (ic->produced) != 0)
331         M17N_OBJECT_UNREF (mt);
332     }
333   else if (command == Minput_status_draw)
334     {
335       if (! win_ic_info->client.win)
336         return;
337       mtext_put_prop (ic->status, 0, mtext_nchars (ic->status), Mface,
338                       status_face);
339       if (ic->im->language != Mnil)
340         mtext_put_prop (ic->status, 0, mtext_nchars (ic->status), Mlanguage,
341                         ic->im->language);
342       adjust_window_and_draw (frame, ic, ic->status, 1);
343     }
344   else if (command == Minput_candidates_draw)
345     {
346       MPlist *group;
347       MText *mt;
348       int i, len;
349       int from, to;
350
351       if (! ic->candidate_list || ! ic->candidate_show)
352         {
353           if (win_ic_info->candidates.mapped)
354             {
355               mwin__unmap_window (frame, win_ic_info->candidates.win);
356               win_ic_info->candidates.mapped = 0;
357             }
358           return;
359         }
360
361       if (! win_ic_info->candidates.mapped)
362         {
363           mwin__map_window (frame, win_ic_info->candidates.win);
364           win_ic_info->candidates.mapped = 1;
365         }
366
367       i = 0;
368       group = ic->candidate_list;
369       while (1)
370         {
371           if (mplist_key (group) == Mtext)
372             len = mtext_len (mplist_value (group));
373           else
374             len = mplist_length (mplist_value (group));
375           if (i + len > ic->candidate_index)
376             break;
377           i += len;
378           group = mplist_next (group);
379         }
380
381       mt = mtext ();
382       if (mplist_key (group) == Mtext)
383         {
384           MText *candidates = (MText *) mplist_value (group);
385
386           from = (ic->candidate_index - i) * 2 + 1;
387           to = from + 1;
388           for (i = 0; i < len; i++)
389             {
390               mtext_cat_char (mt, ' ');
391               mtext_cat_char (mt, mtext_ref_char (candidates, i));
392             }
393         }
394       else
395         {
396           MPlist *pl;
397
398           for (pl = (MPlist *) mplist_value (group);
399                i < ic->candidate_index && mplist_key (pl) != Mnil;
400                i++, pl = mplist_next (pl))
401             {
402               mtext_cat_char (mt, ' ');
403               mtext_cat (mt, (MText *) mplist_value (pl));
404             }
405           from = mtext_nchars (mt) + 1;
406           to = from + mtext_nchars ((MText *) mplist_value (pl));
407           for (; mplist_key (pl) != Mnil; pl = mplist_next (pl))
408             {
409               mtext_cat_char (mt, ' ');
410               mtext_cat (mt, (MText *) mplist_value (pl));
411             }
412         }
413       mtext_cat_char (mt, ' ');
414       mtext_push_prop (mt, 0, mtext_nchars (mt), Mface, status_face);
415       mtext_push_prop (mt, from, to, Mface, mface_reverse_video);
416       if (ic->im->language != Mnil)
417         mtext_put_prop (mt, 0, mtext_nchars (mt), Mlanguage, ic->im->language);
418       adjust_window_and_draw (frame, ic, mt, 2);
419       M17N_OBJECT_UNREF (mt);
420     }
421   else if (command == Minput_set_spot)
422     {
423       minput__callback (ic, Minput_preedit_draw);
424       minput__callback (ic, Minput_status_draw);
425       minput__callback (ic, Minput_candidates_draw);
426     }
427   else if (command == Minput_toggle)
428     {
429       if (ic->active)
430         {
431           minput__callback (ic, Minput_preedit_done);
432           minput__callback (ic, Minput_status_done);
433           minput__callback (ic, Minput_candidates_done);
434         }
435       else
436         {
437           minput__callback (ic, Minput_preedit_start);
438           minput__callback (ic, Minput_status_start);
439           minput__callback (ic, Minput_candidates_start);
440         }
441     }
442   else if (command == Minput_preedit_start)
443     {
444     }
445   else if (command == Minput_preedit_done)
446     {
447       if (win_ic_info->preedit.mapped)
448         {
449           mwin__unmap_window (frame, win_ic_info->preedit.win);
450           win_ic_info->preedit.mapped = 0;
451         }
452     }
453   else if (command == Minput_status_start)
454     {
455       if (! win_ic_info->status.mapped)
456         {
457           mwin__map_window (frame, win_ic_info->status.win);
458           win_ic_info->status.mapped = 1;
459         }
460     }
461   else if (command == Minput_status_done)
462     {
463       if (win_ic_info->status.mapped)
464         {
465           mwin__unmap_window (frame, win_ic_info->status.win);
466           win_ic_info->status.mapped = 0;
467         }
468     }
469   else if (command == Minput_candidates_start)
470     {
471       if (! win_ic_info->candidates.mapped)
472         {
473           mwin__map_window (frame, win_ic_info->candidates.win);
474           win_ic_info->candidates.mapped = 1;
475         }
476     }
477   else if (command == Minput_candidates_done)
478     {
479       if (win_ic_info->candidates.mapped)
480         {
481           mwin__unmap_window (frame, win_ic_info->candidates.win);
482           win_ic_info->candidates.mapped = 0;
483         }
484     }
485 }
486
487 static int
488 win_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
489 {
490   MInputGUIContextInfo *win_ic_info = (MInputGUIContextInfo *) ic->info;
491   MInputContextInfo *ic_info = (MInputContextInfo *) win_ic_info->ic_info;
492   int ret;
493
494   ic->info = ic_info;
495   ret = (*minput_default_driver.lookup) (ic, key, arg, mt);
496   ic->info = win_ic_info;
497   return ret;
498 }
499
500 \f
501
502 int
503 minput__win_init ()
504 {
505   minput_gui_driver = minput_default_driver;
506
507   minput_gui_driver.create_ic = win_create_ic;
508   minput_gui_driver.destroy_ic = win_destroy_ic;
509   minput_gui_driver.filter = win_filter;
510   minput_gui_driver.lookup = win_lookup;
511   {
512     MPlist *plist = mplist ();
513
514     minput_gui_driver.callback_list = plist;
515     plist = mplist_add (plist, Minput_preedit_start, (void *) win_callback);
516     plist = mplist_add (plist, Minput_preedit_draw, (void *) win_callback);
517     plist = mplist_add (plist, Minput_preedit_done, (void *) win_callback);
518     plist = mplist_add (plist, Minput_status_start, (void *) win_callback);
519     plist = mplist_add (plist, Minput_status_draw, (void *) win_callback);
520     plist = mplist_add (plist, Minput_status_done, (void *) win_callback);
521     plist = mplist_add (plist, Minput_candidates_start, (void *) win_callback);
522     plist = mplist_add (plist, Minput_candidates_draw, (void *) win_callback);
523     plist = mplist_add (plist, Minput_candidates_done, (void *) win_callback);
524     plist = mplist_add (plist, Minput_set_spot, (void *) win_callback);
525     plist = mplist_add (plist, Minput_toggle, (void *) win_callback);
526   }
527   minput_driver = &minput_gui_driver;
528
529   face_box_prop.width = 1;
530   face_box_prop.color_top = face_box_prop.color_left
531     = face_box_prop.color_bottom = face_box_prop.color_right
532     = msymbol ("black");
533   face_box_prop.inner_hmargin = face_box_prop.inner_vmargin = 2;
534   face_box_prop.outer_hmargin = face_box_prop.outer_vmargin = 1;
535   status_face = mface ();
536   mface_put_prop (status_face, Mbox, &face_box_prop);
537
538   return 0;
539 }
540
541 void
542 minput__win_fini ()
543 {
544   M17N_OBJECT_UNREF (status_face);
545   if (minput_gui_driver.callback_list)
546     {
547       M17N_OBJECT_UNREF (minput_gui_driver.callback_list);
548       minput_gui_driver.callback_list = NULL;
549     }
550 }
551
552 /*** @} */
553 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
554
555 \f
556 /* External API */
557
558 /*** @addtogroup m17nInputMethodWin */
559 /*** @{ */
560
561 /*=*/
562 /***en
563     @brief Input driver for internal input methods on window systems.
564
565     The input driver @c minput_gui_driver is for internal input
566     methods to be used on window systems.
567
568     It creates sub-windows for a preedit text and a status text, and
569     displays them at the input spot set by the function
570     minput_set_spot ().
571
572     The function m17n_initialize_win () set the variable @c
573     minput_driver to the pointer to this driver so that all internal
574     input methods use it.
575
576     Therefore, unless @c minput_driver is changed from the default,
577     the driver dependent arguments to the functions whose name begin
578     with minput_ must are treated as follows.
579
580     The argument $ARG of the function minput_open_im () is ignored.
581
582     The argument $ARG of the function minput_create_ic () must be a
583     pointer to the structure @c MInputGUIArgIC.  See the documentation
584     of @c MInputGUIArgIC for more detail.
585
586     If the argument $KEY is @c Mnil, the argument $ARG of the
587     function minput_filter () must be a pointer to the object of type
588     @c XEvent.  In that case, $KEY is generated from $ARG.
589
590     The argument $ARG of the function minput_lookup () must be the
591     same one as that of the function minput_filter (). */
592
593 /***ja
594     @brief ¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à¤ÎÆâÉôÆþÎϥ᥽¥Ã¥ÉÍÑÆþÎϥɥ饤¥Ð.
595
596     ÆþÎϥɥ饤¥Ð @c minput_gui_driver ¤Ï¡¢¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à¾å¤ÇÍѤ¤¤é
597     ¤ì¤ëÆþÎϥ᥽¥Ã¥ÉÍѤǤ¢¤ë¡£
598
599     ¤³¤Î¥É¥é¥¤¥Ð¤Ï¡¢´Ø¿ô minput_set_spot () ¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤¿ÆþÎÏ¥¹¥Ý¥Ã
600     ¥È¤Ë preedit ¥Æ¥­¥¹¥ÈÍѤΥµ¥Ö¥¦¥£¥ó¥É¥¦¤È status ¥Æ¥­¥¹¥ÈÍѤΥµ¥Ö
601     ¥¦¥£¥ó¥É¥¦¤òºî¤ê¡¢¤½¤ì¤¾¤ì¤òɽ¼¨¤¹¤ë¡£
602
603     ´Ø¿ô m17n_initialize_win () ¤ÏÊÑ¿ô @c minput_driver ¤ò¤³¤Î¥É¥é¥¤¥Ð
604     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è
605     ¤¦¤Ë¤¹¤ë¡£
606
607     ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ 
608     ¤Ç»Ï¤Þ¤ë̾Á°¤ò»ý¤Ä´Ø¿ô¤Î°ú¿ô¤Î¤¦¤Á¥É¥é¥¤¥Ð°Í¸¤Î¤â¤Î¤Ï°Ê²¼¤Î¤è¤¦¤Ë
609     ¤Ê¤ë¡£
610
611     ´Ø¿ô minput_open_im () ¤Î°ú¿ô $ARG ¤Ï̵»ë¤µ¤ì¤ë¡£
612
613     ´Ø¿ô minput_create_ic () ¤Î°ú¿ô $ARG ¤Ï¹½Â¤ÂΠ@c MInputGUIArgIC ¤Ø
614     ¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¾ÜºÙ¤Ë¤Ä¤¤¤Æ¤Ï @c MInputGUIArgIC ¤Î
615     ÀâÌÀ¤ò»²¾È¤Î¤³¤È¡£
616
617     ´Ø¿ô minput_filter () ¤Î°ú¿ô $ARG ¤¬ @c Mnil ¤Î¾ì¹ç¡¢ $ARG ¤Ï @c
618     XEvent ·¿¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤³¤Î¾ì¹ç 
619     $KEY ¤Ï $ARG ¤«¤éÀ¸À®¤µ¤ì¤ë¡£
620
621     ´Ø¿ô minput_lookup () ¤Î°ú¿ô $ARG ¤Ï´Ø¿ô minput_filter () ¤Î°ú¿ô 
622     $ARG ¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ */
623
624 MInputDriver minput_gui_driver;
625
626 /*=*/
627
628 /***en
629     @brief Convert an event to an input key.
630
631     The minput_event_to_key () function returns the input key
632     corresponding to event $EVENT on $FRAME by a window system
633     dependent manner.
634
635     In the m17n-X library, $EVENT must be a pointer to the structure
636     @c XKeyEvent, and it is handled as below.
637
638     At first, the keysym name of $EVENT is acquired by the function @c
639     XKeysymToString.  Then, the name is modified as below.
640
641     If the name is one of "a" .. "z" and $EVENT has a Shift modifier,
642     the name is converted to "A" .. "Z" respectively, and the Shift
643     modifier is cleared.
644
645     If the name is one byte length and $EVENT has a Control modifier,
646     the byte is bitwise anded by 0x1F and the Control modifier is
647     cleared.
648
649     If $EVENT still has Shift, Control, Meta, Alt, Super, and/or Hyper
650     modifiers, the name is preceded by "S-", "C-", "M-", "A-", "s-",
651     and/or "H-" respectively in this order.
652
653     For instance, if the keysym name is "a" and the event has Shift,
654     Meta, and Hyper modifiers, the resulting name is "H-M-A".
655
656     At last, a symbol who has the name is returned.  */
657
658 /***ja
659     @brief ¥¤¥Ù¥ó¥È¤òÆþÎÏ¥­¡¼¤ËÊÑ´¹¤¹¤ë
660
661     ´Ø¿ô minput_name_to_key () ¤Ï¡¢$FRAME ¤Î¥¤¥Ù¥ó¥È $EVENT ¤ËÂбþ¤¹¤ë
662     ÆþÎÏ¥­¡¼¤òÊÖ¤¹¡£¤³¤³¤Ç¤Î¡ÖÂбþ¡×¤Ï¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à°Í¸¤Ç¤¢¤ë¡£
663
664     m17n-X ¥é¥¤¥Ö¥é¥ê¤Î¾ì¹ç¤Ë¤Ï¡¢$EVENT ¤Ï ¹½Â¤ÂΠ@c XKeyEvent ¤Ø¤Î¥Ý
665     ¥¤¥ó¥¿¤Ç¤¢¤ê¡¢¼¡¤Î¤è¤¦¤Ë½èÍý¤µ¤ì¤ë¡£
666
667     ¤Þ¤º¡¢´Ø¿ô @c XKeysymToString ¤Ë¤è¤Ã¤Æ¡¢$EVENT ¤Î keysym Ì¾¤ò¼èÆÀ
668     ¤·¡¢¼¡¤¤¤Ç°Ê²¼¤ÎÊѹ¹¤ò²Ã¤¨¤ë¡£
669
670     Ì¾Á°¤¬ "a" .. "z" ¤Î¤¤¤º¤ì¤«¤Ç¤¢¤Ã¤Æ $EVENT ¤Ë Shift ¥â¥Ç¥£¥Õ¥¡¥¤
671     ¥¢¤¬¤¢¤ì¤Ð¡¢Ì¾Á°¤Ï¤½¤ì¤¾¤ì "A" .. "Z" ¤ËÊÑ´¹¤µ¤ì¡¢Shift ¥â¥Ç¥£¥Õ¥¡
672     ¥¤¥¢¤Ï¼è¤ê½ü¤«¤ì¤ë¡£
673
674     Ì¾Á°¤¬£±¥Ð¥¤¥ÈŤǠ$EVENT ¤Ë Control ¥â¥Ç¥£¥Õ¥¡¥¤¥¢¤¬¤¢¤ì¤Ð¡¢Ì¾Á°
675     ¤È 0x1F ¤ò¥Ó¥Ã¥Èñ°Ì and ±é»»¤¹¤ë¡£Control ¥â¥Ç¥£¥Õ¥¡¥¤¥¢¤Ï¼è¤ê½ü
676     ¤«¤ì¤ë¡£
677
678     $EVENT ¤Ë¤Þ¤À Shift, Control, Meta, Alt, Super, Hyper ¤Ê¤É¤Î¥â¥Ç¥£
679     ¥Õ¥¡¥¤¥¢¤¬¤¢¤ì¤Ð¡¢Ì¾Á°¤ÎÁ°¤Ë¤½¤ì¤¾¤ì"S-", "C-", "M-", "A-", "s-",
680     "H-" ¤¬ÉÕ¤¯¡£
681     
682     ¤¿¤È¤¨¤Ð¡¢keysym Ì¾¤¬ "a" ¤Ç¥¤¥Ù¥ó¥È¤¬ Shift, Meta, and Hyper ¥â¥Ç¥£
683     ¥Õ¥¡¥¤¥¢¤ò»ý¤Æ¤Ð¡¢ÆÀ¤é¤ì¤ë̾Á°¤Ï "H-M-A" ¤Ç¤¢¤ë¡£
684
685     ºÇ¸å¤Ë¤½¤Î̾Á°¤ò»ý¤Ä¥·¥ó¥Ü¥ë¤òÊÖ¤¹¡£*/
686
687
688 MSymbol
689 minput_event_to_key (MFrame *frame, void *event)
690 {
691   int modifiers;
692   MSymbol key = mwin__parse_event (frame, event, &modifiers);
693   char *name, *str;
694
695   if (! modifiers)
696     return key;
697
698   name = msymbol_name (key);
699   str = alloca (strlen (name) + 2 * 6 + 1);
700   str[0] = '\0';
701   if (modifiers & MINPUT_KEY_SHIFT_MODIFIER)
702     strcat (str, "S-");
703   if (modifiers & MINPUT_KEY_CONTROL_MODIFIER)
704     strcat (str, "C-");
705   if (modifiers & MINPUT_KEY_META_MODIFIER)
706     strcat (str, "M-");
707   if (modifiers & MINPUT_KEY_ALT_MODIFIER)
708     strcat (str, "A-");
709   if (modifiers & MINPUT_KEY_SUPER_MODIFIER)
710     strcat (str, "s-");
711   if (modifiers & MINPUT_KEY_HYPER_MODIFIER)
712     strcat (str, "H-");
713   strcat (str, name);
714
715   return msymbol (str);
716 }
717
718 /*** @} */
719
720 /*
721   Local Variables:
722   coding: euc-japan
723   End:
724 */