]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkkeys-win32.c
Remove deprecated code from GdkDnd
[~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) (gintptr) _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_caps_lock_state (GdkKeymap *keymap)
535 {
536   return ((GetKeyState (VK_CAPITAL) & 1) != 0);
537 }
538
539 gboolean
540 gdk_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
541                                    guint          keyval,
542                                    GdkKeymapKey **keys,
543                                    gint          *n_keys)
544 {
545   GArray *retval;
546
547   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
548   g_return_val_if_fail (keys != NULL, FALSE);
549   g_return_val_if_fail (n_keys != NULL, FALSE);
550   g_return_val_if_fail (keyval != 0, FALSE);
551   
552   retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
553
554   /* Accept only the default keymap */
555   if (keymap == NULL || keymap == gdk_keymap_get_default ())
556     {
557       gint vk;
558       
559       update_keymap ();
560
561       for (vk = 0; vk < 256; vk++)
562         {
563           gint i;
564
565           for (i = 0; i < 4; i++)
566             {
567               if (keysym_tab[vk*4+i] == keyval)
568                 {
569                   GdkKeymapKey key;
570                   
571                   key.keycode = vk;
572                   
573                   /* 2 levels (normal, shift), two groups (normal, AltGr) */
574                   key.group = i / 2;
575                   key.level = i % 2;
576                   
577                   g_array_append_val (retval, key);
578                 }
579             }
580         }
581     }
582
583 #ifdef G_ENABLE_DEBUG
584   if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
585     {
586       gint i;
587
588       g_print ("gdk_keymap_get_entries_for_keyval: %#.04x (%s):",
589                keyval, gdk_keyval_name (keyval));
590       for (i = 0; i < retval->len; i++)
591         {
592           GdkKeymapKey *entry = (GdkKeymapKey *) retval->data + i;
593           g_print ("  %#.02x %d %d", entry->keycode, entry->group, entry->level);
594         }
595       g_print ("\n");
596     }
597 #endif
598
599   if (retval->len > 0)
600     {
601       *keys = (GdkKeymapKey*) retval->data;
602       *n_keys = retval->len;
603     }
604   else
605     {
606       *keys = NULL;
607       *n_keys = 0;
608     }
609       
610   g_array_free (retval, retval->len > 0 ? FALSE : TRUE);
611
612   return *n_keys > 0;
613 }
614
615 gboolean
616 gdk_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
617                                     guint          hardware_keycode,
618                                     GdkKeymapKey **keys,
619                                     guint        **keyvals,
620                                     gint          *n_entries)
621 {
622   GArray *key_array;
623   GArray *keyval_array;
624
625   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
626   g_return_val_if_fail (n_entries != NULL, FALSE);
627
628   if (hardware_keycode <= 0 ||
629       hardware_keycode >= 256)
630     {
631       if (keys)
632         *keys = NULL;
633       if (keyvals)
634         *keyvals = NULL;
635
636       *n_entries = 0;
637       return FALSE;
638     }
639   
640   if (keys)
641     key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
642   else
643     key_array = NULL;
644   
645   if (keyvals)
646     keyval_array = g_array_new (FALSE, FALSE, sizeof (guint));
647   else
648     keyval_array = NULL;
649   
650   /* Accept only the default keymap */
651   if (keymap == NULL || keymap == gdk_keymap_get_default ())
652     {
653       gint i;
654
655       update_keymap ();
656
657       for (i = 0; i < 4; i++)
658         {
659           if (key_array)
660             {
661               GdkKeymapKey key;
662               
663               key.keycode = hardware_keycode;
664               
665               key.group = i / 2;
666               key.level = i % 2;
667               
668               g_array_append_val (key_array, key);
669             }
670
671           if (keyval_array)
672             g_array_append_val (keyval_array, keysym_tab[hardware_keycode*4+i]);
673         }
674     }
675
676   if ((key_array && key_array->len > 0) ||
677       (keyval_array && keyval_array->len > 0))
678     {
679       if (keys)
680         *keys = (GdkKeymapKey*) key_array->data;
681
682       if (keyvals)
683         *keyvals = (guint*) keyval_array->data;
684
685       if (key_array)
686         *n_entries = key_array->len;
687       else
688         *n_entries = keyval_array->len;
689     }
690   else
691     {
692       if (keys)
693         *keys = NULL;
694
695       if (keyvals)
696         *keyvals = NULL;
697       
698       *n_entries = 0;
699     }
700
701   if (key_array)
702     g_array_free (key_array, key_array->len > 0 ? FALSE : TRUE);
703   if (keyval_array)
704     g_array_free (keyval_array, keyval_array->len > 0 ? FALSE : TRUE);
705
706   return *n_entries > 0;
707 }
708
709 guint
710 gdk_keymap_lookup_key (GdkKeymap          *keymap,
711                        const GdkKeymapKey *key)
712 {
713   guint sym;
714
715   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), 0);
716   g_return_val_if_fail (key != NULL, 0);
717   g_return_val_if_fail (key->group < 4, 0);
718   
719   /* Accept only the default keymap */
720   if (keymap != NULL && keymap != gdk_keymap_get_default ())
721     return 0;
722
723   update_keymap ();
724   
725   if (key->keycode >= 256 ||
726       key->group < 0 || key->group >= 2 ||
727       key->level < 0 || key->level >= 2)
728     return 0;
729   
730   sym = keysym_tab[key->keycode*4 + key->group*2 + key->level];
731   
732   if (sym == GDK_VoidSymbol)
733     return 0;
734   else
735     return sym;
736 }
737
738 gboolean
739 gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
740                                      guint            hardware_keycode,
741                                      GdkModifierType  state,
742                                      gint             group,
743                                      guint           *keyval,
744                                      gint            *effective_group,
745                                      gint            *level,
746                                      GdkModifierType *consumed_modifiers)
747 {
748   guint tmp_keyval;
749   guint *keyvals;
750   gint shift_level;
751   gboolean ignore_shift = FALSE;
752   gboolean ignore_group = FALSE;
753       
754   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
755   g_return_val_if_fail (group < 4, FALSE);
756   
757 #if 0
758   GDK_NOTE (EVENTS, g_print ("gdk_keymap_translate_keyboard_state: keycode=%#x state=%#x group=%d\n",
759                              hardware_keycode, state, group));
760 #endif
761   if (keyval)
762     *keyval = 0;
763   if (effective_group)
764     *effective_group = 0;
765   if (level)
766     *level = 0;
767   if (consumed_modifiers)
768     *consumed_modifiers = 0;
769
770   /* Accept only the default keymap */
771   if (keymap != NULL && keymap != gdk_keymap_get_default ())
772     return FALSE;
773
774   if (hardware_keycode >= 256)
775     return FALSE;
776
777   if (group < 0 || group >= 2)
778     return FALSE;
779
780   update_keymap ();
781
782   keyvals = keysym_tab + hardware_keycode*4;
783
784   if ((state & GDK_LOCK_MASK) &&
785       (state & GDK_SHIFT_MASK) &&
786       ((gdk_shift_modifiers & GDK_LOCK_MASK) ||
787        (keyvals[group*2 + 1] == gdk_keyval_to_upper (keyvals[group*2 + 0]))))
788     /* Shift always disables ShiftLock. Shift disables CapsLock for
789      * keys with lowercase/uppercase letter pairs.
790      */
791     shift_level = 0;
792   else if (state & gdk_shift_modifiers)
793     shift_level = 1;
794   else
795     shift_level = 0;
796
797   /* Drop group and shift if there are no keysymbols on
798    * the key for those.
799    */
800   if (shift_level == 1 &&
801       keyvals[group*2 + 1] == GDK_VoidSymbol &&
802       keyvals[group*2] != GDK_VoidSymbol)
803     {
804       shift_level = 0;
805       ignore_shift = TRUE;
806     }
807
808   if (group == 1 &&
809       keyvals[2 + shift_level] == GDK_VoidSymbol &&
810       keyvals[0 + shift_level] != GDK_VoidSymbol)
811     {
812       group = 0;
813       ignore_group = TRUE;
814     }
815
816   if (keyvals[group *2 + shift_level] == GDK_VoidSymbol &&
817       keyvals[0 + 0] != GDK_VoidSymbol)
818     {
819       shift_level = 0;
820       group = 0;
821       ignore_group = TRUE;
822       ignore_shift = TRUE;
823     }
824
825   /* See whether the group and shift level actually mattered
826    * to know what to put in consumed_modifiers
827    */
828   if (keyvals[group*2 + 1] == GDK_VoidSymbol ||
829       keyvals[group*2 + 0] == keyvals[group*2 + 1])
830     ignore_shift = TRUE;
831
832   if (keyvals[2 + shift_level] == GDK_VoidSymbol ||
833       keyvals[0 + shift_level] == keyvals[2 + shift_level])
834     ignore_group = TRUE;
835
836   tmp_keyval = keyvals[group*2 + shift_level];
837
838   /* If a true CapsLock is toggled, and Shift is not down,
839    * and the shifted keysym is the uppercase of the unshifted,
840    * use it.
841    */
842   if (!(gdk_shift_modifiers & GDK_LOCK_MASK) &&
843       !(state & GDK_SHIFT_MASK) &&
844       (state & GDK_LOCK_MASK))
845     {
846       guint upper = gdk_keyval_to_upper (tmp_keyval);
847       if (upper == keyvals[group*2 + 1])
848         tmp_keyval = upper;
849     }
850
851   if (keyval)
852     *keyval = tmp_keyval;
853
854   if (effective_group)
855     *effective_group = group;
856
857   if (level)
858     *level = shift_level;
859
860   if (consumed_modifiers)
861     {
862       *consumed_modifiers =
863         (ignore_group ? 0 : GDK_MOD2_MASK) |
864         (ignore_shift ? 0 : (GDK_SHIFT_MASK|GDK_LOCK_MASK));
865     }
866                                 
867 #if 0
868   GDK_NOTE (EVENTS, g_print ("... group=%d level=%d cmods=%#x keyval=%s\n",
869                              group, shift_level, tmp_modifiers, gdk_keyval_name (tmp_keyval)));
870 #endif
871
872   return tmp_keyval != GDK_VoidSymbol;
873 }
874
875 void
876 gdk_keymap_add_virtual_modifiers (GdkKeymap       *keymap,
877                                   GdkModifierType *state)
878 {
879 }
880
881 gboolean
882 gdk_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
883                                   GdkModifierType *state)
884 {
885   /* FIXME: Is this the right thing to do? */
886   return TRUE;
887 }