]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkkeys-win32.c
Remove support for Windows 9x/ME. GTK+ hasn't worked on Win9x since 2.6 or
[~andy/gtk] / gdk / win32 / gdkkeys-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 2000 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26 #include <ctype.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <limits.h>
31 #include <errno.h>
32
33 #include "gdk.h"
34
35 #include "gdkprivate-win32.h"
36 #include "gdkinternals.h"
37 #include "gdkkeysyms.h"
38
39 #include <config.h>
40
41 guint _gdk_keymap_serial = 0;
42 gboolean _gdk_keyboard_has_altgr = FALSE;
43 guint _scancode_rshift = 0;
44
45 static GdkModifierType gdk_shift_modifiers = GDK_SHIFT_MASK;
46
47 static GdkKeymap *default_keymap = NULL;
48
49 static guint *keysym_tab = NULL;
50
51 #ifdef G_ENABLE_DEBUG
52 static void
53 print_keysym_tab (void)
54 {
55   gint vk;
56   
57   g_print ("keymap:%s%s\n",
58            _gdk_keyboard_has_altgr ? " (uses AltGr)" : "",
59            (gdk_shift_modifiers & GDK_LOCK_MASK) ? " (has ShiftLock)" : "");
60   for (vk = 0; vk < 256; vk++)
61     {
62       gint state;
63       
64       g_print ("%#.02x: ", vk);
65       for (state = 0; state < 4; state++)
66         {
67           gchar *name = gdk_keyval_name (keysym_tab[vk*4 + state]);
68           if (name == NULL)
69             name = "(none)";
70           g_print ("%s ", name);
71         }
72       g_print ("\n");
73     }
74 }
75 #endif
76
77 static void
78 handle_special (guint  vk,
79                 guint *ksymp,
80                 gint   shift)
81
82 {
83   switch (vk)
84     {
85     case VK_CANCEL:
86       *ksymp = GDK_Cancel; break;
87     case VK_BACK:
88       *ksymp = GDK_BackSpace; break;
89     case VK_TAB:
90       if (shift & 0x1)
91         *ksymp = GDK_ISO_Left_Tab;
92       else
93         *ksymp = GDK_Tab;
94       break;
95     case VK_CLEAR:
96       *ksymp = GDK_Clear; break;
97     case VK_RETURN:
98       *ksymp = GDK_Return; break;
99     case VK_SHIFT:
100     case VK_LSHIFT:
101       *ksymp = GDK_Shift_L; break;
102     case VK_CONTROL:
103     case VK_LCONTROL:
104       *ksymp = GDK_Control_L; break;
105     case VK_MENU:
106     case VK_LMENU:
107       *ksymp = GDK_Alt_L; break;
108     case VK_PAUSE:
109       *ksymp = GDK_Pause; break;
110     case VK_ESCAPE:
111       *ksymp = GDK_Escape; break;
112     case VK_PRIOR:
113       *ksymp = GDK_Prior; break;
114     case VK_NEXT:
115       *ksymp = GDK_Next; break;
116     case VK_END:
117       *ksymp = GDK_End; break;
118     case VK_HOME:
119       *ksymp = GDK_Home; break;
120     case VK_LEFT:
121       *ksymp = GDK_Left; break;
122     case VK_UP:
123       *ksymp = GDK_Up; break;
124     case VK_RIGHT:
125       *ksymp = GDK_Right; break;
126     case VK_DOWN:
127       *ksymp = GDK_Down; break;
128     case VK_SELECT:
129       *ksymp = GDK_Select; break;
130     case VK_PRINT:
131       *ksymp = GDK_Print; break;
132     case VK_EXECUTE:
133       *ksymp = GDK_Execute; break;
134     case VK_INSERT:
135       *ksymp = GDK_Insert; break;
136     case VK_DELETE:
137       *ksymp = GDK_Delete; break;
138     case VK_HELP:
139       *ksymp = GDK_Help; break;
140     case VK_LWIN:
141       *ksymp = GDK_Meta_L; break;
142     case VK_RWIN:
143       *ksymp = GDK_Meta_R; break;
144     case VK_APPS:
145       *ksymp = GDK_Menu; break;
146     case VK_MULTIPLY:
147       *ksymp = GDK_KP_Multiply; break;
148     case VK_ADD:
149       *ksymp = GDK_KP_Add; break;
150     case VK_SEPARATOR:
151       *ksymp = GDK_KP_Separator; break;
152     case VK_SUBTRACT:
153       *ksymp = GDK_KP_Subtract; break;
154     case VK_DIVIDE:
155       *ksymp = GDK_KP_Divide; break;
156     case VK_NUMPAD0:
157       *ksymp = GDK_KP_0; break;
158     case VK_NUMPAD1:
159       *ksymp = GDK_KP_1; break;
160     case VK_NUMPAD2:
161       *ksymp = GDK_KP_2; break;
162     case VK_NUMPAD3:
163       *ksymp = GDK_KP_3; break;
164     case VK_NUMPAD4:
165       *ksymp = GDK_KP_4; break;
166     case VK_NUMPAD5:
167       *ksymp = GDK_KP_5; break;
168     case VK_NUMPAD6:
169       *ksymp = GDK_KP_6; break;
170     case VK_NUMPAD7:
171       *ksymp = GDK_KP_7; break;
172     case VK_NUMPAD8:
173       *ksymp = GDK_KP_8; break;
174     case VK_NUMPAD9:
175       *ksymp = GDK_KP_9; break;
176     case VK_F1:
177       *ksymp = GDK_F1; break;
178     case VK_F2:
179       *ksymp = GDK_F2; break;
180     case VK_F3:
181       *ksymp = GDK_F3; break;
182     case VK_F4:
183       *ksymp = GDK_F4; break;
184     case VK_F5:
185       *ksymp = GDK_F5; break;
186     case VK_F6:
187       *ksymp = GDK_F6; break;
188     case VK_F7:
189       *ksymp = GDK_F7; break;
190     case VK_F8:
191       *ksymp = GDK_F8; break;
192     case VK_F9:
193       *ksymp = GDK_F9; break;
194     case VK_F10:
195       *ksymp = GDK_F10; break;
196     case VK_F11:
197       *ksymp = GDK_F11; break;
198     case VK_F12:
199       *ksymp = GDK_F12; break;
200     case VK_F13:
201       *ksymp = GDK_F13; break;
202     case VK_F14:
203       *ksymp = GDK_F14; break;
204     case VK_F15:
205       *ksymp = GDK_F15; break;
206     case VK_F16:
207       *ksymp = GDK_F16; break;
208     case VK_F17:
209       *ksymp = GDK_F17; break;
210     case VK_F18:
211       *ksymp = GDK_F18; break;
212     case VK_F19:
213       *ksymp = GDK_F19; break;
214     case VK_F20:
215       *ksymp = GDK_F20; break;
216     case VK_F21:
217       *ksymp = GDK_F21; break;
218     case VK_F22:
219       *ksymp = GDK_F22; break;
220     case VK_F23:
221       *ksymp = GDK_F23; break;
222     case VK_F24:
223       *ksymp = GDK_F24; break;
224     case VK_NUMLOCK:
225       *ksymp = GDK_Num_Lock; break;
226     case VK_SCROLL:
227       *ksymp = GDK_Scroll_Lock; break;
228     case VK_RSHIFT:
229       *ksymp = GDK_Shift_R; break;
230     case VK_RCONTROL:
231       *ksymp = GDK_Control_R; break;
232     case VK_RMENU:
233       *ksymp = GDK_Alt_R; break;
234     }
235 }
236
237 static void
238 set_shift_vks (guchar *key_state,
239                gint    shift)
240 {
241   switch (shift)
242     {
243     case 0:
244       key_state[VK_SHIFT] = 0;
245       key_state[VK_CONTROL] = key_state[VK_MENU] = 0;
246       break;
247     case 1:
248       key_state[VK_SHIFT] = 0x80;
249       key_state[VK_CONTROL] = key_state[VK_MENU] = 0;
250       break;
251     case 2:
252       key_state[VK_SHIFT] = 0;
253       key_state[VK_CONTROL] = key_state[VK_MENU] = 0x80;
254       break;
255     case 3:
256       key_state[VK_SHIFT] = 0x80;
257       key_state[VK_CONTROL] = key_state[VK_MENU] = 0x80;
258       break;
259     }
260 }
261
262 static void
263 reset_after_dead (guchar key_state[256])
264 {
265   guchar temp_key_state[256];
266   wchar_t wcs[2];
267
268   memmove (temp_key_state, key_state, sizeof (key_state));
269
270   temp_key_state[VK_SHIFT] =
271     temp_key_state[VK_CONTROL] =
272     temp_key_state[VK_MENU] = 0;
273
274   ToUnicodeEx (VK_SPACE, MapVirtualKey (VK_SPACE, 0),
275                temp_key_state, wcs, G_N_ELEMENTS (wcs),
276                0, _gdk_input_locale);
277 }
278
279 static void
280 handle_dead (guint  keysym,
281              guint *ksymp)
282 {
283   switch (keysym)
284     {
285     case '"': /* 0x022 */
286       *ksymp = GDK_dead_diaeresis; break;
287     case '\'': /* 0x027 */
288       *ksymp = GDK_dead_acute; break;
289     case GDK_asciicircum: /* 0x05e */
290       *ksymp = GDK_dead_circumflex; break;
291     case GDK_grave:     /* 0x060 */
292       *ksymp = GDK_dead_grave; break;
293     case GDK_asciitilde: /* 0x07e */
294       *ksymp = GDK_dead_tilde; break;
295     case GDK_diaeresis: /* 0x0a8 */
296       *ksymp = GDK_dead_diaeresis; break;
297     case GDK_degree: /* 0x0b0 */
298       *ksymp = GDK_dead_abovering; break;
299     case GDK_acute:     /* 0x0b4 */
300       *ksymp = GDK_dead_acute; break;
301     case GDK_periodcentered: /* 0x0b7 */
302       *ksymp = GDK_dead_abovedot; break;
303     case GDK_cedilla: /* 0x0b8 */
304       *ksymp = GDK_dead_cedilla; break;
305     case GDK_breve:     /* 0x1a2 */
306       *ksymp = GDK_dead_breve; break;
307     case GDK_ogonek: /* 0x1b2 */
308       *ksymp = GDK_dead_ogonek; break;
309     case GDK_caron:     /* 0x1b7 */
310       *ksymp = GDK_dead_caron; break;
311     case GDK_doubleacute: /* 0x1bd */
312       *ksymp = GDK_dead_doubleacute; break;
313     case GDK_abovedot: /* 0x1ff */
314       *ksymp = GDK_dead_abovedot; break;
315     case 0x1000384: /* Greek tonos */
316       *ksymp = GDK_dead_acute; break;
317     case GDK_Greek_accentdieresis: /* 0x7ae */
318       *ksymp = GDK_Greek_accentdieresis; break;
319     default:
320       /* By default use the keysym as such. This takes care of for
321        * instance the dead U+09CD (BENGALI VIRAMA) on the ekushey
322        * Bengali layout.
323        */
324       *ksymp = keysym; break;
325     }
326 }
327
328 static void
329 update_keymap (void)
330 {
331   static guint current_serial = 0;
332   guchar key_state[256];
333   guint scancode;
334   guint vk;
335   gboolean capslock_tested = FALSE;
336
337   if (keysym_tab != NULL && current_serial == _gdk_keymap_serial)
338     return;
339
340   current_serial = _gdk_keymap_serial;
341
342   if (keysym_tab == NULL)
343     keysym_tab = g_new (guint, 4*256);
344
345   memset (key_state, 0, sizeof (key_state));
346
347   _gdk_keyboard_has_altgr = FALSE;
348   gdk_shift_modifiers = GDK_SHIFT_MASK;
349
350   for (vk = 0; vk < 256; vk++)
351     {
352       if ((scancode = MapVirtualKey (vk, 0)) == 0 &&
353           vk != VK_DIVIDE)
354         keysym_tab[vk*4+0] =
355           keysym_tab[vk*4+1] =
356           keysym_tab[vk*4+2] =
357           keysym_tab[vk*4+3] = GDK_VoidSymbol;
358       else
359         {
360           gint shift;
361
362           if (vk == VK_RSHIFT)
363             _scancode_rshift = scancode;
364
365           key_state[vk] = 0x80;
366           for (shift = 0; shift < 4; shift++)
367             {
368               guint *ksymp = keysym_tab + vk*4 + shift;
369               guchar chars[2];
370               
371               set_shift_vks (key_state, shift);
372
373               *ksymp = 0;
374
375               /* First, handle those virtual keys that we always want
376                * as special GDK_* keysyms, even if ToAsciiEx might
377                * turn some them into a ASCII character (like TAB and
378                * ESC).
379                */
380               handle_special (vk, ksymp, shift);
381
382               if (*ksymp == 0)
383                 {
384                   wchar_t wcs[10];
385                   gint k;
386
387                   k = ToUnicodeEx (vk, scancode, key_state,
388                                    wcs, G_N_ELEMENTS (wcs),
389                                    0, _gdk_input_locale);
390 #if 0
391                   g_print ("ToUnicodeEx(%02x, %d: %d): %d, %04x %04x\n",
392                            vk, scancode, shift, k,
393                            (k != 0 ? wcs[0] : 0),
394                            (k >= 2 ? wcs[1] : 0));
395 #endif
396                   if (k == 1)
397                     *ksymp = gdk_unicode_to_keyval (wcs[0]);
398
399                   if (k == 1)
400                     {
401                       /* Keysym already stored above */
402                     }
403                   else if (k == -1)
404                     {
405                       guint keysym = gdk_unicode_to_keyval (wcs[0]);
406
407                       /* It is a dead key, and it's has been stored in
408                        * the keyboard layout's state by
409                        * ToAsciiEx()/ToUnicodeEx(). Yes, this is an
410                        * incredibly silly API! Make the keyboard
411                        * layout forget it by calling
412                        * ToAsciiEx()/ToUnicodeEx() once more, with the
413                        * virtual key code and scancode for the
414                        * spacebar, without shift or AltGr. Otherwise
415                        * the next call to ToAsciiEx() with a different
416                        * key would try to combine with the dead key.
417                        */
418                       reset_after_dead (key_state);
419
420                       /* Use dead keysyms instead of "undead" ones */
421                       handle_dead (keysym, ksymp);
422                     }
423                   else if (k == 0)
424                     {
425                       /* Seems to be necessary to "reset" the keyboard layout
426                        * in this case, too. Otherwise problems on NT4.
427                        */
428                       reset_after_dead (key_state);
429                     }
430                   else
431                     {
432 #if 0
433                       GDK_NOTE (EVENTS,
434                                 g_print ("ToUnicodeEx returns %d "
435                                          "for vk:%02x, sc:%02x%s%s\n",
436                                          k, vk, scancode,
437                                          (shift&0x1 ? " shift" : ""),
438                                          (shift&0x2 ? " altgr" : "")));
439 #endif
440                     }
441                 }
442               if (*ksymp == 0)
443                 *ksymp = GDK_VoidSymbol;
444             }
445           key_state[vk] = 0;
446
447           /* Check if keyboard has an AltGr key by checking if
448            * the mapping with Control+Alt is different.
449            */
450           if (!_gdk_keyboard_has_altgr)
451             if ((keysym_tab[vk*4 + 2] != GDK_VoidSymbol &&
452                  keysym_tab[vk*4] != keysym_tab[vk*4 + 2]) ||
453                 (keysym_tab[vk*4 + 3] != GDK_VoidSymbol &&
454                  keysym_tab[vk*4 + 1] != keysym_tab[vk*4 + 3]))
455               _gdk_keyboard_has_altgr = TRUE;
456           
457           if (!capslock_tested)
458             {
459               /* Can we use this virtual key to determine the CapsLock
460                * key behaviour: CapsLock or ShiftLock? If it generates
461                * keysyms for printable characters and has a shifted
462                * keysym that isn't just the upperacase of the
463                * unshifted keysym, check the behaviour of VK_CAPITAL.
464                */
465               if (g_unichar_isgraph (gdk_keyval_to_unicode (keysym_tab[vk*4 + 0])) &&
466                   keysym_tab[vk*4 + 1] != keysym_tab[vk*4 + 0] &&
467                   g_unichar_isgraph (gdk_keyval_to_unicode (keysym_tab[vk*4 + 1])) &&
468                   keysym_tab[vk*4 + 1] != gdk_keyval_to_upper (keysym_tab[vk*4 + 0]))
469                 {
470                   guchar chars[2];
471                   
472                   capslock_tested = TRUE;
473                   
474                   key_state[VK_SHIFT] = 0;
475                   key_state[VK_CONTROL] = key_state[VK_MENU] = 0;
476                   key_state[VK_CAPITAL] = 1;
477
478                   if (ToAsciiEx (vk, scancode, key_state,
479                                  (LPWORD) chars, 0, _gdk_input_locale) == 1)
480                     {
481                       if (chars[0] >= GDK_space &&
482                           chars[0] <= GDK_asciitilde &&
483                           chars[0] == keysym_tab[vk*4 + 1])
484                         {
485                           /* CapsLock acts as ShiftLock */
486                           gdk_shift_modifiers |= GDK_LOCK_MASK;
487                         }
488                     }
489                   key_state[VK_CAPITAL] = 0;
490                 }    
491             }
492         }
493     }
494   GDK_NOTE (EVENTS, print_keysym_tab ());
495
496
497 GdkKeymap*
498 gdk_keymap_get_for_display (GdkDisplay *display)
499 {
500   g_return_val_if_fail (display == gdk_display_get_default (), NULL);
501
502   if (default_keymap == NULL)
503     default_keymap = g_object_new (gdk_keymap_get_type (), NULL);
504
505   return default_keymap;
506 }
507
508 PangoDirection
509 gdk_keymap_get_direction (GdkKeymap *keymap)
510 {
511   update_keymap ();
512
513   switch (PRIMARYLANGID (LOWORD ((DWORD) _gdk_input_locale)))
514     {
515     case LANG_HEBREW:
516     case LANG_ARABIC:
517 #ifdef LANG_URDU
518     case LANG_URDU:
519 #endif
520     case LANG_FARSI:
521       /* Others? */
522       return PANGO_DIRECTION_RTL;
523
524     default:
525       return PANGO_DIRECTION_LTR;
526     }
527 }
528
529 gboolean
530 gdk_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
531                                    guint          keyval,
532                                    GdkKeymapKey **keys,
533                                    gint          *n_keys)
534 {
535   GArray *retval;
536
537   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
538   g_return_val_if_fail (keys != NULL, FALSE);
539   g_return_val_if_fail (n_keys != NULL, FALSE);
540   g_return_val_if_fail (keyval != 0, FALSE);
541   
542   retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
543
544   /* Accept only the default keymap */
545   if (keymap == NULL || keymap == gdk_keymap_get_default ())
546     {
547       gint vk;
548       
549       update_keymap ();
550
551       for (vk = 0; vk < 256; vk++)
552         {
553           gint i;
554
555           for (i = 0; i < 4; i++)
556             {
557               if (keysym_tab[vk*4+i] == keyval)
558                 {
559                   GdkKeymapKey key;
560                   
561                   key.keycode = vk;
562                   
563                   /* 2 levels (normal, shift), two groups (normal, AltGr) */
564                   key.group = i / 2;
565                   key.level = i % 2;
566                   
567                   g_array_append_val (retval, key);
568                 }
569             }
570         }
571     }
572
573 #ifdef G_ENABLE_DEBUG
574   if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
575     {
576       gint i;
577
578       g_print ("gdk_keymap_get_entries_for_keyval: %#.04x (%s):",
579                keyval, gdk_keyval_name (keyval));
580       for (i = 0; i < retval->len; i++)
581         {
582           GdkKeymapKey *entry = (GdkKeymapKey *) retval->data + i;
583           g_print ("  %#.02x %d %d", entry->keycode, entry->group, entry->level);
584         }
585       g_print ("\n");
586     }
587 #endif
588
589   if (retval->len > 0)
590     {
591       *keys = (GdkKeymapKey*) retval->data;
592       *n_keys = retval->len;
593     }
594   else
595     {
596       *keys = NULL;
597       *n_keys = 0;
598     }
599       
600   g_array_free (retval, retval->len > 0 ? FALSE : TRUE);
601
602   return *n_keys > 0;
603 }
604
605 gboolean
606 gdk_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
607                                     guint          hardware_keycode,
608                                     GdkKeymapKey **keys,
609                                     guint        **keyvals,
610                                     gint          *n_entries)
611 {
612   GArray *key_array;
613   GArray *keyval_array;
614
615   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
616   g_return_val_if_fail (n_entries != NULL, FALSE);
617
618   if (hardware_keycode <= 0 ||
619       hardware_keycode >= 256)
620     {
621       if (keys)
622         *keys = NULL;
623       if (keyvals)
624         *keyvals = NULL;
625
626       *n_entries = 0;
627       return FALSE;
628     }
629   
630   if (keys)
631     key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
632   else
633     key_array = NULL;
634   
635   if (keyvals)
636     keyval_array = g_array_new (FALSE, FALSE, sizeof (guint));
637   else
638     keyval_array = NULL;
639   
640   /* Accept only the default keymap */
641   if (keymap == NULL || keymap == gdk_keymap_get_default ())
642     {
643       gint i;
644
645       update_keymap ();
646
647       for (i = 0; i < 4; i++)
648         {
649           if (key_array)
650             {
651               GdkKeymapKey key;
652               
653               key.keycode = hardware_keycode;
654               
655               key.group = i / 2;
656               key.level = i % 2;
657               
658               g_array_append_val (key_array, key);
659             }
660
661           if (keyval_array)
662             g_array_append_val (keyval_array, keysym_tab[hardware_keycode*4+i]);
663         }
664     }
665
666   if ((key_array && key_array->len > 0) ||
667       (keyval_array && keyval_array->len > 0))
668     {
669       if (keys)
670         *keys = (GdkKeymapKey*) key_array->data;
671
672       if (keyvals)
673         *keyvals = (guint*) keyval_array->data;
674
675       if (key_array)
676         *n_entries = key_array->len;
677       else
678         *n_entries = keyval_array->len;
679     }
680   else
681     {
682       if (keys)
683         *keys = NULL;
684
685       if (keyvals)
686         *keyvals = NULL;
687       
688       *n_entries = 0;
689     }
690
691   if (key_array)
692     g_array_free (key_array, key_array->len > 0 ? FALSE : TRUE);
693   if (keyval_array)
694     g_array_free (keyval_array, keyval_array->len > 0 ? FALSE : TRUE);
695
696   return *n_entries > 0;
697 }
698
699 guint
700 gdk_keymap_lookup_key (GdkKeymap          *keymap,
701                        const GdkKeymapKey *key)
702 {
703   guint sym;
704
705   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), 0);
706   g_return_val_if_fail (key != NULL, 0);
707   g_return_val_if_fail (key->group < 4, 0);
708   
709   /* Accept only the default keymap */
710   if (keymap != NULL && keymap != gdk_keymap_get_default ())
711     return 0;
712
713   update_keymap ();
714   
715   if (key->keycode >= 256 ||
716       key->group < 0 || key->group >= 2 ||
717       key->level < 0 || key->level >= 2)
718     return 0;
719   
720   sym = keysym_tab[key->keycode*4 + key->group*2 + key->level];
721   
722   if (sym == GDK_VoidSymbol)
723     return 0;
724   else
725     return sym;
726 }
727
728 gboolean
729 gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
730                                      guint            hardware_keycode,
731                                      GdkModifierType  state,
732                                      gint             group,
733                                      guint           *keyval,
734                                      gint            *effective_group,
735                                      gint            *level,
736                                      GdkModifierType *consumed_modifiers)
737 {
738   guint tmp_keyval;
739   guint *keyvals;
740   gint shift_level;
741   gboolean ignore_shift = FALSE;
742   gboolean ignore_group = FALSE;
743       
744   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
745   g_return_val_if_fail (group < 4, FALSE);
746   
747 #if 0
748   GDK_NOTE (EVENTS, g_print ("gdk_keymap_translate_keyboard_state: keycode=%#x state=%#x group=%d\n",
749                              hardware_keycode, state, group));
750 #endif
751   if (keyval)
752     *keyval = 0;
753   if (effective_group)
754     *effective_group = 0;
755   if (level)
756     *level = 0;
757   if (consumed_modifiers)
758     *consumed_modifiers = 0;
759
760   /* Accept only the default keymap */
761   if (keymap != NULL && keymap != gdk_keymap_get_default ())
762     return FALSE;
763
764   if (hardware_keycode >= 256)
765     return FALSE;
766
767   if (group < 0 || group >= 2)
768     return FALSE;
769
770   update_keymap ();
771
772   keyvals = keysym_tab + hardware_keycode*4;
773
774   if ((state & GDK_LOCK_MASK) &&
775       (state & GDK_SHIFT_MASK) &&
776       ((gdk_shift_modifiers & GDK_LOCK_MASK) ||
777        (keyvals[group*2 + 1] == gdk_keyval_to_upper (keyvals[group*2 + 0]))))
778     /* Shift always disables ShiftLock. Shift disables CapsLock for
779      * keys with lowercase/uppercase letter pairs.
780      */
781     shift_level = 0;
782   else if (state & gdk_shift_modifiers)
783     shift_level = 1;
784   else
785     shift_level = 0;
786
787   /* Drop group and shift if there are no keysymbols on
788    * the key for those.
789    */
790   if (shift_level == 1 &&
791       keyvals[group*2 + 1] == GDK_VoidSymbol &&
792       keyvals[group*2] != GDK_VoidSymbol)
793     {
794       shift_level = 0;
795       ignore_shift = TRUE;
796     }
797
798   if (group == 1 &&
799       keyvals[2 + shift_level] == GDK_VoidSymbol &&
800       keyvals[0 + shift_level] != GDK_VoidSymbol)
801     {
802       group = 0;
803       ignore_group = TRUE;
804     }
805
806   if (keyvals[group *2 + shift_level] == GDK_VoidSymbol &&
807       keyvals[0 + 0] != GDK_VoidSymbol)
808     {
809       shift_level = 0;
810       group = 0;
811       ignore_group = TRUE;
812       ignore_shift = TRUE;
813     }
814
815   /* See whether the group and shift level actually mattered
816    * to know what to put in consumed_modifiers
817    */
818   if (keyvals[group*2 + 1] == GDK_VoidSymbol ||
819       keyvals[group*2 + 0] == keyvals[group*2 + 1])
820     ignore_shift = TRUE;
821
822   if (keyvals[2 + shift_level] == GDK_VoidSymbol ||
823       keyvals[0 + shift_level] == keyvals[2 + shift_level])
824     ignore_group = TRUE;
825
826   tmp_keyval = keyvals[group*2 + shift_level];
827
828   /* If a true CapsLock is toggled, and Shift is not down,
829    * and the shifted keysym is the uppercase of the unshifted,
830    * use it.
831    */
832   if (!(gdk_shift_modifiers & GDK_LOCK_MASK) &&
833       !(state & GDK_SHIFT_MASK) &&
834       (state & GDK_LOCK_MASK))
835     {
836       guint upper = gdk_keyval_to_upper (tmp_keyval);
837       if (upper == keyvals[group*2 + 1])
838         tmp_keyval = upper;
839     }
840
841   if (keyval)
842     *keyval = tmp_keyval;
843
844   if (effective_group)
845     *effective_group = group;
846
847   if (level)
848     *level = shift_level;
849
850   if (consumed_modifiers)
851     {
852       *consumed_modifiers =
853         (ignore_group ? 0 : GDK_MOD2_MASK) |
854         (ignore_shift ? 0 : (GDK_SHIFT_MASK|GDK_LOCK_MASK));
855     }
856                                 
857 #if 0
858   GDK_NOTE (EVENTS, g_print ("... group=%d level=%d cmods=%#x keyval=%s\n",
859                              group, shift_level, tmp_modifiers, gdk_keyval_name (tmp_keyval)));
860 #endif
861
862   return tmp_keyval != GDK_VoidSymbol;
863 }