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