]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkkeys-win32.c
Bug 541305 – [Win32] Scrolling was broken after GdkWindow refactoring
[~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               
370               set_shift_vks (key_state, shift);
371
372               *ksymp = 0;
373
374               /* First, handle those virtual keys that we always want
375                * as special GDK_* keysyms, even if ToAsciiEx might
376                * turn some them into a ASCII character (like TAB and
377                * ESC).
378                */
379               handle_special (vk, ksymp, shift);
380
381               if (*ksymp == 0)
382                 {
383                   wchar_t wcs[10];
384                   gint k;
385
386                   wcs[0] = wcs[1] = 0;
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                            wcs[0], wcs[1]);
394 #endif
395                   if (k == 1)
396                     *ksymp = gdk_unicode_to_keyval (wcs[0]);
397                   else if (k == -1)
398                     {
399                       guint keysym = gdk_unicode_to_keyval (wcs[0]);
400
401                       /* It is a dead key, and it's has been stored in
402                        * the keyboard layout's state by
403                        * ToAsciiEx()/ToUnicodeEx(). Yes, this is an
404                        * incredibly silly API! Make the keyboard
405                        * layout forget it by calling
406                        * ToAsciiEx()/ToUnicodeEx() once more, with the
407                        * virtual key code and scancode for the
408                        * spacebar, without shift or AltGr. Otherwise
409                        * the next call to ToAsciiEx() with a different
410                        * key would try to combine with the dead key.
411                        */
412                       reset_after_dead (key_state);
413
414                       /* Use dead keysyms instead of "undead" ones */
415                       handle_dead (keysym, ksymp);
416                     }
417                   else if (k == 0)
418                     {
419                       /* Seems to be necessary to "reset" the keyboard layout
420                        * in this case, too. Otherwise problems on NT4.
421                        */
422                       reset_after_dead (key_state);
423                     }
424                   else
425                     {
426 #if 0
427                       GDK_NOTE (EVENTS,
428                                 g_print ("ToUnicodeEx returns %d "
429                                          "for vk:%02x, sc:%02x%s%s\n",
430                                          k, vk, scancode,
431                                          (shift&0x1 ? " shift" : ""),
432                                          (shift&0x2 ? " altgr" : "")));
433 #endif
434                     }
435                 }
436               if (*ksymp == 0)
437                 *ksymp = GDK_VoidSymbol;
438             }
439           key_state[vk] = 0;
440
441           /* Check if keyboard has an AltGr key by checking if
442            * the mapping with Control+Alt is different.
443            */
444           if (!_gdk_keyboard_has_altgr)
445             if ((keysym_tab[vk*4 + 2] != GDK_VoidSymbol &&
446                  keysym_tab[vk*4] != keysym_tab[vk*4 + 2]) ||
447                 (keysym_tab[vk*4 + 3] != GDK_VoidSymbol &&
448                  keysym_tab[vk*4 + 1] != keysym_tab[vk*4 + 3]))
449               _gdk_keyboard_has_altgr = TRUE;
450           
451           if (!capslock_tested)
452             {
453               /* Can we use this virtual key to determine the CapsLock
454                * key behaviour: CapsLock or ShiftLock? If it generates
455                * keysyms for printable characters and has a shifted
456                * keysym that isn't just the upperacase of the
457                * unshifted keysym, check the behaviour of VK_CAPITAL.
458                */
459               if (g_unichar_isgraph (gdk_keyval_to_unicode (keysym_tab[vk*4 + 0])) &&
460                   keysym_tab[vk*4 + 1] != keysym_tab[vk*4 + 0] &&
461                   g_unichar_isgraph (gdk_keyval_to_unicode (keysym_tab[vk*4 + 1])) &&
462                   keysym_tab[vk*4 + 1] != gdk_keyval_to_upper (keysym_tab[vk*4 + 0]))
463                 {
464                   guchar chars[2];
465                   
466                   capslock_tested = TRUE;
467                   
468                   key_state[VK_SHIFT] = 0;
469                   key_state[VK_CONTROL] = key_state[VK_MENU] = 0;
470                   key_state[VK_CAPITAL] = 1;
471
472                   if (ToAsciiEx (vk, scancode, key_state,
473                                  (LPWORD) chars, 0, _gdk_input_locale) == 1)
474                     {
475                       if (chars[0] >= GDK_space &&
476                           chars[0] <= GDK_asciitilde &&
477                           chars[0] == keysym_tab[vk*4 + 1])
478                         {
479                           /* CapsLock acts as ShiftLock */
480                           gdk_shift_modifiers |= GDK_LOCK_MASK;
481                         }
482                     }
483                   key_state[VK_CAPITAL] = 0;
484                 }    
485             }
486         }
487     }
488   GDK_NOTE (EVENTS, print_keysym_tab ());
489
490
491 GdkKeymap*
492 gdk_keymap_get_for_display (GdkDisplay *display)
493 {
494   g_return_val_if_fail (display == gdk_display_get_default (), NULL);
495
496   if (default_keymap == NULL)
497     default_keymap = g_object_new (gdk_keymap_get_type (), NULL);
498
499   return default_keymap;
500 }
501
502 PangoDirection
503 gdk_keymap_get_direction (GdkKeymap *keymap)
504 {
505   update_keymap ();
506
507   switch (PRIMARYLANGID (LOWORD ((DWORD) _gdk_input_locale)))
508     {
509     case LANG_HEBREW:
510     case LANG_ARABIC:
511 #ifdef LANG_URDU
512     case LANG_URDU:
513 #endif
514     case LANG_FARSI:
515       /* Others? */
516       return PANGO_DIRECTION_RTL;
517
518     default:
519       return PANGO_DIRECTION_LTR;
520     }
521 }
522
523 gboolean
524 gdk_keymap_have_bidi_layouts (GdkKeymap *keymap)
525 {
526   /* Should we check if the kayboard layouts switchable at the moment
527    * cover both directionalities? What does the doc comment in
528    * ../x11/gdkkeys-x11.c exactly mean?
529    */
530   return FALSE;
531 }
532
533 gboolean
534 gdk_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
535                                    guint          keyval,
536                                    GdkKeymapKey **keys,
537                                    gint          *n_keys)
538 {
539   GArray *retval;
540
541   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
542   g_return_val_if_fail (keys != NULL, FALSE);
543   g_return_val_if_fail (n_keys != NULL, FALSE);
544   g_return_val_if_fail (keyval != 0, FALSE);
545   
546   retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
547
548   /* Accept only the default keymap */
549   if (keymap == NULL || keymap == gdk_keymap_get_default ())
550     {
551       gint vk;
552       
553       update_keymap ();
554
555       for (vk = 0; vk < 256; vk++)
556         {
557           gint i;
558
559           for (i = 0; i < 4; i++)
560             {
561               if (keysym_tab[vk*4+i] == keyval)
562                 {
563                   GdkKeymapKey key;
564                   
565                   key.keycode = vk;
566                   
567                   /* 2 levels (normal, shift), two groups (normal, AltGr) */
568                   key.group = i / 2;
569                   key.level = i % 2;
570                   
571                   g_array_append_val (retval, key);
572                 }
573             }
574         }
575     }
576
577 #ifdef G_ENABLE_DEBUG
578   if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
579     {
580       gint i;
581
582       g_print ("gdk_keymap_get_entries_for_keyval: %#.04x (%s):",
583                keyval, gdk_keyval_name (keyval));
584       for (i = 0; i < retval->len; i++)
585         {
586           GdkKeymapKey *entry = (GdkKeymapKey *) retval->data + i;
587           g_print ("  %#.02x %d %d", entry->keycode, entry->group, entry->level);
588         }
589       g_print ("\n");
590     }
591 #endif
592
593   if (retval->len > 0)
594     {
595       *keys = (GdkKeymapKey*) retval->data;
596       *n_keys = retval->len;
597     }
598   else
599     {
600       *keys = NULL;
601       *n_keys = 0;
602     }
603       
604   g_array_free (retval, retval->len > 0 ? FALSE : TRUE);
605
606   return *n_keys > 0;
607 }
608
609 gboolean
610 gdk_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
611                                     guint          hardware_keycode,
612                                     GdkKeymapKey **keys,
613                                     guint        **keyvals,
614                                     gint          *n_entries)
615 {
616   GArray *key_array;
617   GArray *keyval_array;
618
619   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
620   g_return_val_if_fail (n_entries != NULL, FALSE);
621
622   if (hardware_keycode <= 0 ||
623       hardware_keycode >= 256)
624     {
625       if (keys)
626         *keys = NULL;
627       if (keyvals)
628         *keyvals = NULL;
629
630       *n_entries = 0;
631       return FALSE;
632     }
633   
634   if (keys)
635     key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
636   else
637     key_array = NULL;
638   
639   if (keyvals)
640     keyval_array = g_array_new (FALSE, FALSE, sizeof (guint));
641   else
642     keyval_array = NULL;
643   
644   /* Accept only the default keymap */
645   if (keymap == NULL || keymap == gdk_keymap_get_default ())
646     {
647       gint i;
648
649       update_keymap ();
650
651       for (i = 0; i < 4; i++)
652         {
653           if (key_array)
654             {
655               GdkKeymapKey key;
656               
657               key.keycode = hardware_keycode;
658               
659               key.group = i / 2;
660               key.level = i % 2;
661               
662               g_array_append_val (key_array, key);
663             }
664
665           if (keyval_array)
666             g_array_append_val (keyval_array, keysym_tab[hardware_keycode*4+i]);
667         }
668     }
669
670   if ((key_array && key_array->len > 0) ||
671       (keyval_array && keyval_array->len > 0))
672     {
673       if (keys)
674         *keys = (GdkKeymapKey*) key_array->data;
675
676       if (keyvals)
677         *keyvals = (guint*) keyval_array->data;
678
679       if (key_array)
680         *n_entries = key_array->len;
681       else
682         *n_entries = keyval_array->len;
683     }
684   else
685     {
686       if (keys)
687         *keys = NULL;
688
689       if (keyvals)
690         *keyvals = NULL;
691       
692       *n_entries = 0;
693     }
694
695   if (key_array)
696     g_array_free (key_array, key_array->len > 0 ? FALSE : TRUE);
697   if (keyval_array)
698     g_array_free (keyval_array, keyval_array->len > 0 ? FALSE : TRUE);
699
700   return *n_entries > 0;
701 }
702
703 guint
704 gdk_keymap_lookup_key (GdkKeymap          *keymap,
705                        const GdkKeymapKey *key)
706 {
707   guint sym;
708
709   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), 0);
710   g_return_val_if_fail (key != NULL, 0);
711   g_return_val_if_fail (key->group < 4, 0);
712   
713   /* Accept only the default keymap */
714   if (keymap != NULL && keymap != gdk_keymap_get_default ())
715     return 0;
716
717   update_keymap ();
718   
719   if (key->keycode >= 256 ||
720       key->group < 0 || key->group >= 2 ||
721       key->level < 0 || key->level >= 2)
722     return 0;
723   
724   sym = keysym_tab[key->keycode*4 + key->group*2 + key->level];
725   
726   if (sym == GDK_VoidSymbol)
727     return 0;
728   else
729     return sym;
730 }
731
732 gboolean
733 gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
734                                      guint            hardware_keycode,
735                                      GdkModifierType  state,
736                                      gint             group,
737                                      guint           *keyval,
738                                      gint            *effective_group,
739                                      gint            *level,
740                                      GdkModifierType *consumed_modifiers)
741 {
742   guint tmp_keyval;
743   guint *keyvals;
744   gint shift_level;
745   gboolean ignore_shift = FALSE;
746   gboolean ignore_group = FALSE;
747       
748   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
749   g_return_val_if_fail (group < 4, FALSE);
750   
751 #if 0
752   GDK_NOTE (EVENTS, g_print ("gdk_keymap_translate_keyboard_state: keycode=%#x state=%#x group=%d\n",
753                              hardware_keycode, state, group));
754 #endif
755   if (keyval)
756     *keyval = 0;
757   if (effective_group)
758     *effective_group = 0;
759   if (level)
760     *level = 0;
761   if (consumed_modifiers)
762     *consumed_modifiers = 0;
763
764   /* Accept only the default keymap */
765   if (keymap != NULL && keymap != gdk_keymap_get_default ())
766     return FALSE;
767
768   if (hardware_keycode >= 256)
769     return FALSE;
770
771   if (group < 0 || group >= 2)
772     return FALSE;
773
774   update_keymap ();
775
776   keyvals = keysym_tab + hardware_keycode*4;
777
778   if ((state & GDK_LOCK_MASK) &&
779       (state & GDK_SHIFT_MASK) &&
780       ((gdk_shift_modifiers & GDK_LOCK_MASK) ||
781        (keyvals[group*2 + 1] == gdk_keyval_to_upper (keyvals[group*2 + 0]))))
782     /* Shift always disables ShiftLock. Shift disables CapsLock for
783      * keys with lowercase/uppercase letter pairs.
784      */
785     shift_level = 0;
786   else if (state & gdk_shift_modifiers)
787     shift_level = 1;
788   else
789     shift_level = 0;
790
791   /* Drop group and shift if there are no keysymbols on
792    * the key for those.
793    */
794   if (shift_level == 1 &&
795       keyvals[group*2 + 1] == GDK_VoidSymbol &&
796       keyvals[group*2] != GDK_VoidSymbol)
797     {
798       shift_level = 0;
799       ignore_shift = TRUE;
800     }
801
802   if (group == 1 &&
803       keyvals[2 + shift_level] == GDK_VoidSymbol &&
804       keyvals[0 + shift_level] != GDK_VoidSymbol)
805     {
806       group = 0;
807       ignore_group = TRUE;
808     }
809
810   if (keyvals[group *2 + shift_level] == GDK_VoidSymbol &&
811       keyvals[0 + 0] != GDK_VoidSymbol)
812     {
813       shift_level = 0;
814       group = 0;
815       ignore_group = TRUE;
816       ignore_shift = TRUE;
817     }
818
819   /* See whether the group and shift level actually mattered
820    * to know what to put in consumed_modifiers
821    */
822   if (keyvals[group*2 + 1] == GDK_VoidSymbol ||
823       keyvals[group*2 + 0] == keyvals[group*2 + 1])
824     ignore_shift = TRUE;
825
826   if (keyvals[2 + shift_level] == GDK_VoidSymbol ||
827       keyvals[0 + shift_level] == keyvals[2 + shift_level])
828     ignore_group = TRUE;
829
830   tmp_keyval = keyvals[group*2 + shift_level];
831
832   /* If a true CapsLock is toggled, and Shift is not down,
833    * and the shifted keysym is the uppercase of the unshifted,
834    * use it.
835    */
836   if (!(gdk_shift_modifiers & GDK_LOCK_MASK) &&
837       !(state & GDK_SHIFT_MASK) &&
838       (state & GDK_LOCK_MASK))
839     {
840       guint upper = gdk_keyval_to_upper (tmp_keyval);
841       if (upper == keyvals[group*2 + 1])
842         tmp_keyval = upper;
843     }
844
845   if (keyval)
846     *keyval = tmp_keyval;
847
848   if (effective_group)
849     *effective_group = group;
850
851   if (level)
852     *level = shift_level;
853
854   if (consumed_modifiers)
855     {
856       *consumed_modifiers =
857         (ignore_group ? 0 : GDK_MOD2_MASK) |
858         (ignore_shift ? 0 : (GDK_SHIFT_MASK|GDK_LOCK_MASK));
859     }
860                                 
861 #if 0
862   GDK_NOTE (EVENTS, g_print ("... group=%d level=%d cmods=%#x keyval=%s\n",
863                              group, shift_level, tmp_modifiers, gdk_keyval_name (tmp_keyval)));
864 #endif
865
866   return tmp_keyval != GDK_VoidSymbol;
867 }