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