GdkKeymap



Hi,

Modified patch. The revised API I have so far is:

GdkKeymap* gdk_keymap_get_default (void);


guint    gdk_keymap_lookup_key               (GdkKeymap           *keymap,
                                              const GdkKeymapKey  *key);
gboolean gdk_keymap_translate_keyboard_state (GdkKeymap           *keymap,
                                              guint                hardware_keycode,
                                              GdkModifierType      state,
                                              gint                 group,
                                              guint               *keyval,
                                              gint                *effective_group,
                                              gint                *level,
                                              GdkModifierType     *unused_modifiers);
gboolean gdk_keymap_get_entries_for_keyval   (GdkKeymap           *keymap,
                                              guint                keyval,
                                              GdkKeymapKey       **keys,
                                              gint                *n_keys);
gboolean gdk_keymap_get_entries_for_keycode  (GdkKeymap           *keymap,
                                              guint                hardware_keycode,
                                              GdkKeymapKey       **keys,
                                              guint              **keyvals,
                                              gint                *n_entries);


Also, I moved all the gdk_keyval_* stuff out of gdk.[hc] into
gdkkeys.[hc] with the keymap object.

Havoc

Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.1578
diff -u -u -r1.1578 ChangeLog
--- ChangeLog	2000/12/02 18:05:32	1.1578
+++ ChangeLog	2000/12/03 19:18:05
@@ -1,11 +1,39 @@
+2000-12-03  Havoc Pennington  <hp pobox com>
+
+	* gdk/Makefile.am: add gdkkeys.[hc]
+
+	* gdk/gdkkeys.h, gdk/gdkkeys.c: Move all the keyval stuff to these
+	files from gdk.h, gdk.c; add GdkKeymap type and operations on it.
+
+	* acconfig.h, configure.in: add checks and command line options
+	for XKB
+
+	* gdk/x11/gdkkeys-x11.c: Implement the above functions
+	
+	* gdk/x11/gdkevents-x11.c (gdk_event_translate): Put the keycode
+	and group in the key event
+
+	* gdk/gdkevents.h (struct _GdkEventKey): Add a hardware_keycode
+	field with the low-level hardware key code, and a keyboard_group
+	field with the keyboard group
+
+	* gdk/x11/gdkprivate-x11.h: include config.h for HAVE_XKB,
+	and declare a couple globals used for keymap handling
+	
+	* gtk/gtkimcontextsimple.c: Implement ISO 14755 input method,
+	hold down Shift-Control and type a hex number to get a Unicode 
+	character corresponding to the hex number
+	(gtk_im_context_simple_get_preedit_string): Fix cursor position
+	(return bytes not chars)
+
 2000-20-01  Anders Carlsson  <andersca gnu org>
 
 	* gtk/gtktogglebutton.c (gtk_toggle_button_draw): Fix bug when
 	a GtkToggleButton is both insensitive and active, it was being
 	drawn by the GtkButton draw handler which doesn't check the
 	state. Now it's calling gtk_toggle_button_paint instead.
-
-2000-11-30  Havoc Pennington  <hp pobox com>
+	
+2000-12-01  Havoc Pennington  <hp redhat com>
 
 	* gtk/gtktextdisplay.c (gtk_text_layout_draw): don't create
 	dangling pointers to the appearance attributes from the 
Index: gdk/Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/Makefile.am,v
retrieving revision 1.55
diff -u -u -r1.55 Makefile.am
--- gdk/Makefile.am	2000/11/18 01:49:48	1.55
+++ gdk/Makefile.am	2000/12/03 19:18:05
@@ -65,6 +65,7 @@
 	gdkim.h		\
 	gdkimage.h	\
 	gdkinput.h	\
+	gdkkeys.h	\
 	gdkpango.h	\
 	gdkpixbuf.h	\
 	gdkpixmap.h	\
@@ -87,6 +88,7 @@
 	gdkfont.c		\
 	gdkgc.c			\
 	gdkglobals.c		\
+	gdkkeys.c		\
 	gdkkeyuni.c		\
 	gdkimage.c		\
 	gdkinternals.h  	\
Index: gdk/gdk.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdk.c,v
retrieving revision 1.122
diff -u -u -r1.122 gdk.c
--- gdk/gdk.c	2000/07/31 10:16:45	1.122
+++ gdk/gdk.c	2000/12/03 19:18:05
@@ -507,184 +507,6 @@
   return result;
 }
 
-#ifndef HAVE_XCONVERTCASE
-/* compatibility function from X11R6.3, since XConvertCase is not
- * supplied by X11R5.
- */
-void
-gdk_keyval_convert_case (guint symbol,
-			 guint *lower,
-			 guint *upper)
-{
-  guint xlower = symbol;
-  guint xupper = symbol;
-
-  switch (symbol >> 8)
-    {
-#if	defined (GDK_A) && defined (GDK_Ooblique)
-    case 0: /* Latin 1 */
-      if ((symbol >= GDK_A) && (symbol <= GDK_Z))
-	xlower += (GDK_a - GDK_A);
-      else if ((symbol >= GDK_a) && (symbol <= GDK_z))
-	xupper -= (GDK_a - GDK_A);
-      else if ((symbol >= GDK_Agrave) && (symbol <= GDK_Odiaeresis))
-	xlower += (GDK_agrave - GDK_Agrave);
-      else if ((symbol >= GDK_agrave) && (symbol <= GDK_odiaeresis))
-	xupper -= (GDK_agrave - GDK_Agrave);
-      else if ((symbol >= GDK_Ooblique) && (symbol <= GDK_Thorn))
-	xlower += (GDK_oslash - GDK_Ooblique);
-      else if ((symbol >= GDK_oslash) && (symbol <= GDK_thorn))
-	xupper -= (GDK_oslash - GDK_Ooblique);
-      break;
-#endif	/* LATIN1 */
-      
-#if	defined (GDK_Aogonek) && defined (GDK_tcedilla)
-    case 1: /* Latin 2 */
-      /* Assume the KeySym is a legal value (ignore discontinuities) */
-      if (symbol == GDK_Aogonek)
-	xlower = GDK_aogonek;
-      else if (symbol >= GDK_Lstroke && symbol <= GDK_Sacute)
-	xlower += (GDK_lstroke - GDK_Lstroke);
-      else if (symbol >= GDK_Scaron && symbol <= GDK_Zacute)
-	xlower += (GDK_scaron - GDK_Scaron);
-      else if (symbol >= GDK_Zcaron && symbol <= GDK_Zabovedot)
-	xlower += (GDK_zcaron - GDK_Zcaron);
-      else if (symbol == GDK_aogonek)
-	xupper = GDK_Aogonek;
-      else if (symbol >= GDK_lstroke && symbol <= GDK_sacute)
-	xupper -= (GDK_lstroke - GDK_Lstroke);
-      else if (symbol >= GDK_scaron && symbol <= GDK_zacute)
-	xupper -= (GDK_scaron - GDK_Scaron);
-      else if (symbol >= GDK_zcaron && symbol <= GDK_zabovedot)
-	xupper -= (GDK_zcaron - GDK_Zcaron);
-      else if (symbol >= GDK_Racute && symbol <= GDK_Tcedilla)
-	xlower += (GDK_racute - GDK_Racute);
-      else if (symbol >= GDK_racute && symbol <= GDK_tcedilla)
-	xupper -= (GDK_racute - GDK_Racute);
-      break;
-#endif	/* LATIN2 */
-      
-#if	defined (GDK_Hstroke) && defined (GDK_Cabovedot)
-    case 2: /* Latin 3 */
-      /* Assume the KeySym is a legal value (ignore discontinuities) */
-      if (symbol >= GDK_Hstroke && symbol <= GDK_Hcircumflex)
-	xlower += (GDK_hstroke - GDK_Hstroke);
-      else if (symbol >= GDK_Gbreve && symbol <= GDK_Jcircumflex)
-	xlower += (GDK_gbreve - GDK_Gbreve);
-      else if (symbol >= GDK_hstroke && symbol <= GDK_hcircumflex)
-	xupper -= (GDK_hstroke - GDK_Hstroke);
-      else if (symbol >= GDK_gbreve && symbol <= GDK_jcircumflex)
-	xupper -= (GDK_gbreve - GDK_Gbreve);
-      else if (symbol >= GDK_Cabovedot && symbol <= GDK_Scircumflex)
-	xlower += (GDK_cabovedot - GDK_Cabovedot);
-      else if (symbol >= GDK_cabovedot && symbol <= GDK_scircumflex)
-	xupper -= (GDK_cabovedot - GDK_Cabovedot);
-      break;
-#endif	/* LATIN3 */
-      
-#if	defined (GDK_Rcedilla) && defined (GDK_Amacron)
-    case 3: /* Latin 4 */
-      /* Assume the KeySym is a legal value (ignore discontinuities) */
-      if (symbol >= GDK_Rcedilla && symbol <= GDK_Tslash)
-	xlower += (GDK_rcedilla - GDK_Rcedilla);
-      else if (symbol >= GDK_rcedilla && symbol <= GDK_tslash)
-	xupper -= (GDK_rcedilla - GDK_Rcedilla);
-      else if (symbol == GDK_ENG)
-	xlower = GDK_eng;
-      else if (symbol == GDK_eng)
-	xupper = GDK_ENG;
-      else if (symbol >= GDK_Amacron && symbol <= GDK_Umacron)
-	xlower += (GDK_amacron - GDK_Amacron);
-      else if (symbol >= GDK_amacron && symbol <= GDK_umacron)
-	xupper -= (GDK_amacron - GDK_Amacron);
-      break;
-#endif	/* LATIN4 */
-      
-#if	defined (GDK_Serbian_DJE) && defined (GDK_Cyrillic_yu)
-    case 6: /* Cyrillic */
-      /* Assume the KeySym is a legal value (ignore discontinuities) */
-      if (symbol >= GDK_Serbian_DJE && symbol <= GDK_Serbian_DZE)
-	xlower -= (GDK_Serbian_DJE - GDK_Serbian_dje);
-      else if (symbol >= GDK_Serbian_dje && symbol <= GDK_Serbian_dze)
-	xupper += (GDK_Serbian_DJE - GDK_Serbian_dje);
-      else if (symbol >= GDK_Cyrillic_YU && symbol <= GDK_Cyrillic_HARDSIGN)
-	xlower -= (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
-      else if (symbol >= GDK_Cyrillic_yu && symbol <= GDK_Cyrillic_hardsign)
-	xupper += (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
-      break;
-#endif	/* CYRILLIC */
-      
-#if	defined (GDK_Greek_ALPHAaccent) && defined (GDK_Greek_finalsmallsigma)
-    case 7: /* Greek */
-      /* Assume the KeySym is a legal value (ignore discontinuities) */
-      if (symbol >= GDK_Greek_ALPHAaccent && symbol <= GDK_Greek_OMEGAaccent)
-	xlower += (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
-      else if (symbol >= GDK_Greek_alphaaccent && symbol <= GDK_Greek_omegaaccent &&
-	       symbol != GDK_Greek_iotaaccentdieresis &&
-	       symbol != GDK_Greek_upsilonaccentdieresis)
-	xupper -= (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
-      else if (symbol >= GDK_Greek_ALPHA && symbol <= GDK_Greek_OMEGA)
-	xlower += (GDK_Greek_alpha - GDK_Greek_ALPHA);
-      else if (symbol >= GDK_Greek_alpha && symbol <= GDK_Greek_omega &&
-	       symbol != GDK_Greek_finalsmallsigma)
-	xupper -= (GDK_Greek_alpha - GDK_Greek_ALPHA);
-      break;
-#endif	/* GREEK */
-    }
-
-  if (lower)
-    *lower = xlower;
-  if (upper)
-    *upper = xupper;
-}
-#endif
-
-guint
-gdk_keyval_to_upper (guint keyval)
-{
-  guint result;
-  
-  gdk_keyval_convert_case (keyval, NULL, &result);
-
-  return result;
-}
-
-guint
-gdk_keyval_to_lower (guint keyval)
-{
-  guint result;
-  
-  gdk_keyval_convert_case (keyval, &result, NULL);
-
-  return result;
-}
-
-gboolean
-gdk_keyval_is_upper (guint keyval)
-{
-  if (keyval)
-    {
-      guint upper_val = 0;
-      
-      gdk_keyval_convert_case (keyval, NULL, &upper_val);
-      return upper_val == keyval;
-    }
-  return FALSE;
-}
-
-gboolean
-gdk_keyval_is_lower (guint keyval)
-{
-  if (keyval)
-    {
-      guint lower_val = 0;
-      
-      gdk_keyval_convert_case (keyval, &lower_val, NULL);
-      return lower_val == keyval;
-    }
-  return FALSE;
-}
-
 void
 gdk_threads_enter ()
 {
Index: gdk/gdk.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdk.h,v
retrieving revision 1.80
diff -u -u -r1.80 gdk.h
--- gdk/gdk.h	2000/11/13 19:47:29	1.80
+++ gdk/gdk.h	2000/12/03 19:18:05
@@ -38,6 +38,7 @@
 #include <gdk/gdkim.h>
 #include <gdk/gdkimage.h>
 #include <gdk/gdkinput.h>
+#include <gdk/gdkkeys.h>
 #include <gdk/gdkpango.h>
 #include <gdk/gdkpixbuf.h>
 #include <gdk/gdkpixmap.h>
@@ -133,21 +134,6 @@
 void     gdk_event_send_clientmessage_toall (GdkEvent    *event);
 gboolean gdk_event_send_client_message (GdkEvent    *event,
 					guint32      xid);
-
-/* Key values
- */
-gchar*   gdk_keyval_name         (guint        keyval) G_GNUC_CONST;
-guint    gdk_keyval_from_name    (const gchar *keyval_name);
-void     gdk_keyval_convert_case (guint        symbol,
-				  guint       *lower,
-				  guint       *upper);
-guint    gdk_keyval_to_upper     (guint        keyval) G_GNUC_CONST;
-guint    gdk_keyval_to_lower     (guint        keyval) G_GNUC_CONST;
-gboolean gdk_keyval_is_upper     (guint        keyval) G_GNUC_CONST;
-gboolean gdk_keyval_is_lower     (guint        keyval) G_GNUC_CONST;
-
-guint32  gdk_keyval_to_unicode   (guint        keyval) G_GNUC_CONST;
-guint    gdk_unicode_to_keyval   (guint32      wc) G_GNUC_CONST;
 
 /* Threading
  */
Index: gdk/gdkevents.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkevents.h,v
retrieving revision 1.8
diff -u -u -r1.8 gdkevents.h
--- gdk/gdkevents.h	2000/11/17 21:59:03	1.8
+++ gdk/gdkevents.h	2000/12/03 19:18:05
@@ -279,6 +279,8 @@
   guint keyval;
   gint length;
   gchar *string;
+  guint16 hardware_keycode;
+  guint8 group;
 };
 
 struct _GdkEventCrossing
Index: gdk/gdkkeys.c
===================================================================
RCS file: gdkkeys.c
diff -N gdkkeys.c
--- /dev/null	Tue May  5 16:32:27 1998
+++ gdkkeys.c	Sun Dec  3 14:18:05 2000
@@ -0,0 +1,280 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "gdkkeys.h"
+#include <config.h>
+
+static void gdk_keymap_init       (GdkKeymap      *keymap);
+static void gdk_keymap_class_init (GdkKeymapClass *klass);
+static void gdk_keymap_finalize   (GObject              *object);
+
+static gpointer parent_class = NULL;
+
+GType
+gdk_keymap_get_type (void)
+{
+  static GType object_type = 0;
+
+  if (!object_type)
+    {
+      static const GTypeInfo object_info =
+      {
+        sizeof (GdkKeymapClass),
+        (GBaseInitFunc) NULL,
+        (GBaseFinalizeFunc) NULL,
+        (GClassInitFunc) gdk_keymap_class_init,
+        NULL,           /* class_finalize */
+        NULL,           /* class_data */
+        sizeof (GdkKeymap),
+        0,              /* n_preallocs */
+        (GInstanceInitFunc) gdk_keymap_init,
+      };
+      
+      object_type = g_type_register_static (G_TYPE_OBJECT,
+                                            "GdkKeymap",
+                                            &object_info, 0);
+    }
+  
+  return object_type;
+}
+
+static void
+gdk_keymap_init (GdkKeymap *keymap)
+{
+
+}
+
+static void
+gdk_keymap_class_init (GdkKeymapClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  object_class->finalize = gdk_keymap_finalize;
+}
+
+static void
+gdk_keymap_finalize (GObject *object)
+{
+  GdkKeymap *keymap = GDK_KEYMAP (object);
+  
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+GdkKeymap*
+gdk_keymap_get_default (void)
+{
+  static GdkKeymap *keymap = NULL;
+
+  if (keymap == NULL)
+    keymap = g_object_new (gdk_keymap_get_type (), NULL);
+
+  return keymap;
+}
+
+
+
+/* Other key-handling stuff
+ */
+
+#ifndef HAVE_XCONVERTCASE
+/* compatibility function from X11R6.3, since XConvertCase is not
+ * supplied by X11R5.
+ */
+void
+gdk_keyval_convert_case (guint symbol,
+			 guint *lower,
+			 guint *upper)
+{
+  guint xlower = symbol;
+  guint xupper = symbol;
+
+  switch (symbol >> 8)
+    {
+#if	defined (GDK_A) && defined (GDK_Ooblique)
+    case 0: /* Latin 1 */
+      if ((symbol >= GDK_A) && (symbol <= GDK_Z))
+	xlower += (GDK_a - GDK_A);
+      else if ((symbol >= GDK_a) && (symbol <= GDK_z))
+	xupper -= (GDK_a - GDK_A);
+      else if ((symbol >= GDK_Agrave) && (symbol <= GDK_Odiaeresis))
+	xlower += (GDK_agrave - GDK_Agrave);
+      else if ((symbol >= GDK_agrave) && (symbol <= GDK_odiaeresis))
+	xupper -= (GDK_agrave - GDK_Agrave);
+      else if ((symbol >= GDK_Ooblique) && (symbol <= GDK_Thorn))
+	xlower += (GDK_oslash - GDK_Ooblique);
+      else if ((symbol >= GDK_oslash) && (symbol <= GDK_thorn))
+	xupper -= (GDK_oslash - GDK_Ooblique);
+      break;
+#endif	/* LATIN1 */
+      
+#if	defined (GDK_Aogonek) && defined (GDK_tcedilla)
+    case 1: /* Latin 2 */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (symbol == GDK_Aogonek)
+	xlower = GDK_aogonek;
+      else if (symbol >= GDK_Lstroke && symbol <= GDK_Sacute)
+	xlower += (GDK_lstroke - GDK_Lstroke);
+      else if (symbol >= GDK_Scaron && symbol <= GDK_Zacute)
+	xlower += (GDK_scaron - GDK_Scaron);
+      else if (symbol >= GDK_Zcaron && symbol <= GDK_Zabovedot)
+	xlower += (GDK_zcaron - GDK_Zcaron);
+      else if (symbol == GDK_aogonek)
+	xupper = GDK_Aogonek;
+      else if (symbol >= GDK_lstroke && symbol <= GDK_sacute)
+	xupper -= (GDK_lstroke - GDK_Lstroke);
+      else if (symbol >= GDK_scaron && symbol <= GDK_zacute)
+	xupper -= (GDK_scaron - GDK_Scaron);
+      else if (symbol >= GDK_zcaron && symbol <= GDK_zabovedot)
+	xupper -= (GDK_zcaron - GDK_Zcaron);
+      else if (symbol >= GDK_Racute && symbol <= GDK_Tcedilla)
+	xlower += (GDK_racute - GDK_Racute);
+      else if (symbol >= GDK_racute && symbol <= GDK_tcedilla)
+	xupper -= (GDK_racute - GDK_Racute);
+      break;
+#endif	/* LATIN2 */
+      
+#if	defined (GDK_Hstroke) && defined (GDK_Cabovedot)
+    case 2: /* Latin 3 */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (symbol >= GDK_Hstroke && symbol <= GDK_Hcircumflex)
+	xlower += (GDK_hstroke - GDK_Hstroke);
+      else if (symbol >= GDK_Gbreve && symbol <= GDK_Jcircumflex)
+	xlower += (GDK_gbreve - GDK_Gbreve);
+      else if (symbol >= GDK_hstroke && symbol <= GDK_hcircumflex)
+	xupper -= (GDK_hstroke - GDK_Hstroke);
+      else if (symbol >= GDK_gbreve && symbol <= GDK_jcircumflex)
+	xupper -= (GDK_gbreve - GDK_Gbreve);
+      else if (symbol >= GDK_Cabovedot && symbol <= GDK_Scircumflex)
+	xlower += (GDK_cabovedot - GDK_Cabovedot);
+      else if (symbol >= GDK_cabovedot && symbol <= GDK_scircumflex)
+	xupper -= (GDK_cabovedot - GDK_Cabovedot);
+      break;
+#endif	/* LATIN3 */
+      
+#if	defined (GDK_Rcedilla) && defined (GDK_Amacron)
+    case 3: /* Latin 4 */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (symbol >= GDK_Rcedilla && symbol <= GDK_Tslash)
+	xlower += (GDK_rcedilla - GDK_Rcedilla);
+      else if (symbol >= GDK_rcedilla && symbol <= GDK_tslash)
+	xupper -= (GDK_rcedilla - GDK_Rcedilla);
+      else if (symbol == GDK_ENG)
+	xlower = GDK_eng;
+      else if (symbol == GDK_eng)
+	xupper = GDK_ENG;
+      else if (symbol >= GDK_Amacron && symbol <= GDK_Umacron)
+	xlower += (GDK_amacron - GDK_Amacron);
+      else if (symbol >= GDK_amacron && symbol <= GDK_umacron)
+	xupper -= (GDK_amacron - GDK_Amacron);
+      break;
+#endif	/* LATIN4 */
+      
+#if	defined (GDK_Serbian_DJE) && defined (GDK_Cyrillic_yu)
+    case 6: /* Cyrillic */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (symbol >= GDK_Serbian_DJE && symbol <= GDK_Serbian_DZE)
+	xlower -= (GDK_Serbian_DJE - GDK_Serbian_dje);
+      else if (symbol >= GDK_Serbian_dje && symbol <= GDK_Serbian_dze)
+	xupper += (GDK_Serbian_DJE - GDK_Serbian_dje);
+      else if (symbol >= GDK_Cyrillic_YU && symbol <= GDK_Cyrillic_HARDSIGN)
+	xlower -= (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
+      else if (symbol >= GDK_Cyrillic_yu && symbol <= GDK_Cyrillic_hardsign)
+	xupper += (GDK_Cyrillic_YU - GDK_Cyrillic_yu);
+      break;
+#endif	/* CYRILLIC */
+      
+#if	defined (GDK_Greek_ALPHAaccent) && defined (GDK_Greek_finalsmallsigma)
+    case 7: /* Greek */
+      /* Assume the KeySym is a legal value (ignore discontinuities) */
+      if (symbol >= GDK_Greek_ALPHAaccent && symbol <= GDK_Greek_OMEGAaccent)
+	xlower += (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
+      else if (symbol >= GDK_Greek_alphaaccent && symbol <= GDK_Greek_omegaaccent &&
+	       symbol != GDK_Greek_iotaaccentdieresis &&
+	       symbol != GDK_Greek_upsilonaccentdieresis)
+	xupper -= (GDK_Greek_alphaaccent - GDK_Greek_ALPHAaccent);
+      else if (symbol >= GDK_Greek_ALPHA && symbol <= GDK_Greek_OMEGA)
+	xlower += (GDK_Greek_alpha - GDK_Greek_ALPHA);
+      else if (symbol >= GDK_Greek_alpha && symbol <= GDK_Greek_omega &&
+	       symbol != GDK_Greek_finalsmallsigma)
+	xupper -= (GDK_Greek_alpha - GDK_Greek_ALPHA);
+      break;
+#endif	/* GREEK */
+    }
+
+  if (lower)
+    *lower = xlower;
+  if (upper)
+    *upper = xupper;
+}
+#endif
+
+guint
+gdk_keyval_to_upper (guint keyval)
+{
+  guint result;
+  
+  gdk_keyval_convert_case (keyval, NULL, &result);
+
+  return result;
+}
+
+guint
+gdk_keyval_to_lower (guint keyval)
+{
+  guint result;
+  
+  gdk_keyval_convert_case (keyval, &result, NULL);
+
+  return result;
+}
+
+gboolean
+gdk_keyval_is_upper (guint keyval)
+{
+  if (keyval)
+    {
+      guint upper_val = 0;
+      
+      gdk_keyval_convert_case (keyval, NULL, &upper_val);
+      return upper_val == keyval;
+    }
+  return FALSE;
+}
+
+gboolean
+gdk_keyval_is_lower (guint keyval)
+{
+  if (keyval)
+    {
+      guint lower_val = 0;
+      
+      gdk_keyval_convert_case (keyval, &lower_val, NULL);
+      return lower_val == keyval;
+    }
+  return FALSE;
+}
Index: gdk/gdkkeys.h
===================================================================
RCS file: gdkkeys.h
diff -N gdkkeys.h
--- /dev/null	Tue May  5 16:32:27 1998
+++ gdkkeys.h	Sun Dec  3 14:18:05 2000
@@ -0,0 +1,120 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __GDK_KEYS_H__
+#define __GDK_KEYS_H__
+
+#include <gdk/gdktypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _GdkKeymapKey GdkKeymapKey;
+
+/* GdkKeymapKey is a hardware key that can be mapped to a keyval */
+struct _GdkKeymapKey
+{
+  guint keycode;
+  gint  group;
+  gint  level;
+};
+
+/* A GdkKeymap defines the translation from keyboard state
+ * (including a hardware key, a modifier mask, and active keyboard group)
+ * to a keyval. This translation has two phases. The first phase is
+ * to determine the effective keyboard group and level for the keyboard
+ * state; the second phase is to look up the keycode/group/level triplet
+ * in the keymap and see what keyval it corresponds to.
+ */
+
+typedef struct _GdkKeymap      GdkKeymap;
+typedef struct _GdkKeymapClass GdkKeymapClass;
+
+#define GDK_TYPE_KEYMAP              (gdk_keymap_get_type ())
+#define GDK_KEYMAP(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_KEYMAP, GdkKeymap))
+#define GDK_KEYMAP_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_KEYMAP, GdkKeymapClass))
+#define GDK_IS_KEYMAP(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_KEYMAP))
+#define GDK_IS_KEYMAP_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_KEYMAP))
+#define GDK_KEYMAP_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_KEYMAP, GdkKeymapClass))
+
+
+struct _GdkKeymap
+{
+  GObject parent_instance;
+};
+
+struct _GdkKeymapClass
+{
+  GObjectClass parent_class;
+};
+
+GType gdk_keymap_get_type (void) G_GNUC_CONST;
+
+GdkKeymap* gdk_keymap_get_default (void);
+
+
+guint    gdk_keymap_lookup_key               (GdkKeymap           *keymap,
+                                              const GdkKeymapKey  *key);
+gboolean gdk_keymap_translate_keyboard_state (GdkKeymap           *keymap,
+                                              guint                hardware_keycode,
+                                              GdkModifierType      state,
+                                              gint                 group,
+                                              guint               *keyval,
+                                              gint                *effective_group,
+                                              gint                *level,
+                                              GdkModifierType     *unused_modifiers);
+gboolean gdk_keymap_get_entries_for_keyval   (GdkKeymap           *keymap,
+                                              guint                keyval,
+                                              GdkKeymapKey       **keys,
+                                              gint                *n_keys);
+gboolean gdk_keymap_get_entries_for_keycode  (GdkKeymap           *keymap,
+                                              guint                hardware_keycode,
+                                              GdkKeymapKey       **keys,
+                                              guint              **keyvals,
+                                              gint                *n_entries);
+
+/* Key values
+ */
+gchar*   gdk_keyval_name         (guint        keyval) G_GNUC_CONST;
+guint    gdk_keyval_from_name    (const gchar *keyval_name);
+void     gdk_keyval_convert_case (guint        symbol,
+				  guint       *lower,
+				  guint       *upper);
+guint    gdk_keyval_to_upper     (guint        keyval) G_GNUC_CONST;
+guint    gdk_keyval_to_lower     (guint        keyval) G_GNUC_CONST;
+gboolean gdk_keyval_is_upper     (guint        keyval) G_GNUC_CONST;
+gboolean gdk_keyval_is_lower     (guint        keyval) G_GNUC_CONST;
+
+guint32  gdk_keyval_to_unicode   (guint        keyval) G_GNUC_CONST;
+guint    gdk_unicode_to_keyval   (guint32      wc) G_GNUC_CONST;
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __GDK_KEYS_H__ */
Index: gdk/x11/Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/Makefile.am,v
retrieving revision 1.15
diff -u -u -r1.15 Makefile.am
--- gdk/x11/Makefile.am	2000/07/14 20:08:07	1.15
+++ gdk/x11/Makefile.am	2000/12/03 19:18:05
@@ -55,6 +55,7 @@
 	gdkim-x11.c	   	\
 	gdkimage-x11.c	   	\
 	gdkinput.c	   	\
+	gdkkeys-x11.c		\
 	gdkmain-x11.c	   	\
 	gdkpango-x11.c		\
 	gdkpixmap-x11.c	   	\
Index: gdk/x11/gdkevents-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkevents-x11.c,v
retrieving revision 1.34
diff -u -u -r1.34 gdkevents-x11.c
--- gdk/x11/gdkevents-x11.c	2000/10/04 16:51:42	1.34
+++ gdk/x11/gdkevents-x11.c	2000/12/03 19:18:06
@@ -40,6 +40,10 @@
 
 #include "gdkinputprivate.h"
 
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
 typedef struct _GdkIOClosure GdkIOClosure;
 typedef struct _GdkEventPrivate GdkEventPrivate;
 
@@ -430,6 +434,7 @@
 				 &keysym, &compose);
 #endif
       event->key.keyval = keysym;
+      event->key.hardware_keycode = xevent->xkey.keycode;
       
       if (charcount > 0 && buf[charcount-1] == '\0')
 	charcount --;
@@ -448,6 +453,9 @@
 		       charcount, buf);
 	}
 #endif /* G_ENABLE_DEBUG */
+
+      /* bits 13 and 14 in the "state" field are the keyboard group */
+#define KEYBOARD_GROUP_MASK ((1 << 13) | (1 << 14))
       
       event->key.type = GDK_KEY_PRESS;
       event->key.window = window;
@@ -455,6 +463,8 @@
       event->key.state = (GdkModifierType) xevent->xkey.state;
       event->key.string = g_strdup (buf);
       event->key.length = charcount;
+
+      event->key.group = xevent->xkey.state & KEYBOARD_GROUP_MASK;
       
       break;
       
@@ -1161,8 +1171,16 @@
       /* Let XLib know that there is a new keyboard mapping.
        */
       XRefreshKeyboardMapping (&xevent->xmapping);
+      ++_gdk_keymap_serial;
       return_val = FALSE;
       break;
+
+#ifdef HAVE_XKB
+    case XkbMapNotify:
+      ++_gdk_keymap_serial;
+      return_val = FALSE;
+      break;
+#endif
       
     default:
       /* something else - (e.g., a Xinput event) */
Index: gdk/x11/gdkkeys-x11.c
===================================================================
RCS file: gdkkeys-x11.c
diff -N gdkkeys-x11.c
--- /dev/null	Tue May  5 16:32:27 1998
+++ gdkkeys-x11.c	Sun Dec  3 14:18:06 2000
@@ -0,0 +1,782 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "gdk.h"
+
+#include "gdkprivate-x11.h"
+#include "gdkinternals.h"
+#include "gdkkeysyms.h"
+
+#include "config.h"
+
+guint _gdk_keymap_serial = 0;
+
+static gint min_keycode = 0;
+static gint max_keycode = 0;
+
+static inline void
+update_keyrange (void)
+{
+  if (max_keycode == 0)
+    XDisplayKeycodes (gdk_display, &min_keycode, &max_keycode);
+}
+
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+
+gboolean _gdk_use_xkb = FALSE;
+static XkbDescPtr xkb_desc = NULL;
+
+static XkbDescPtr
+get_xkb (void)
+{
+  static guint current_serial = 0;
+
+  update_keyrange ();
+  
+  if (xkb_desc == NULL)
+    {
+      xkb_desc = XkbGetMap (gdk_display, XkbKeySymsMask, XkbUseCoreKbd);
+      if (xkb_desc == NULL)
+        g_error ("Failed to get keymap");
+    }
+  else if (current_serial != _gdk_keymap_serial)
+    {
+      XkbGetUpdatedMap (gdk_display, XkbKeySymsMask, xkb_desc);
+    }
+
+  current_serial = _gdk_keymap_serial;
+
+  return xkb_desc;
+}
+#endif /* HAVE_XKB */
+
+static KeySym* keymap = NULL;
+static gint keysyms_per_keycode = 0;
+static XModifierKeymap* mod_keymap = NULL;
+static GdkModifierType group_switch_mask = 0;
+
+static void
+update_keymaps (void)
+{
+  static guint current_serial = 0;
+  
+#ifdef HAVE_XKB
+  g_assert (!_gdk_use_xkb);
+#endif
+  
+  if (keymap == NULL ||
+      current_serial != _gdk_keymap_serial)
+    {
+      gint i;
+      gint map_size;
+
+      update_keyrange ();
+      
+      if (keymap)
+        XFree (keymap);
+
+      if (mod_keymap)
+        XFreeModifiermap (mod_keymap);
+      
+      keymap = XGetKeyboardMapping (gdk_display, min_keycode,
+                                    max_keycode - min_keycode,
+                                    &keysyms_per_keycode);
+
+      mod_keymap = XGetModifierMapping (gdk_display);
+
+
+      group_switch_mask = 0;
+
+      /* there are 8 modifiers, and the first 3 are shift, shift lock,
+       * and control
+       */
+      map_size = 8 * mod_keymap->max_keypermod;
+      i = 3 * mod_keymap->max_keypermod;
+      while (i < map_size)
+        {
+          /* get the key code at this point in the map,
+           * see if its keysym is GDK_Mode_switch, if so
+           * we have the mode key
+           */
+          gint keycode = mod_keymap->modifiermap[i];
+      
+          if (keycode >= min_keycode &&
+              keycode <= max_keycode)
+            {
+              gint j = 0;
+              KeySym *syms = keymap + (keycode - min_keycode) * keysyms_per_keycode;
+              while (j < keysyms_per_keycode)
+                {
+                  if (syms[j] == GDK_Mode_switch)
+                    {
+                      /* This modifier swaps groups */
+
+                      /* GDK_MOD1_MASK is 1 << 3 for example, i.e. the
+                       * fourth modifier, i / keyspermod is the modifier
+                       * index
+                       */
+                  
+                      group_switch_mask |= (1 << ( i / mod_keymap->max_keypermod));
+                      break;
+                    }
+              
+                  ++j;
+                }
+            }
+      
+          ++i;
+        }
+    }
+}
+
+static const KeySym*
+get_keymap (void)
+{
+  update_keymaps ();  
+  
+  return keymap;
+}
+
+/**
+ * gdk_keymap_get_entries_for_keyval:
+ * @keymap: a #GdkKeymap, or %NULL to use the default keymap
+ * @keyval: a keyval, such as %GDK_a, %GDK_Up, %GDK_Return, etc.
+ * @keys: return location for an array of #GdkKeymapKey
+ * @n_keys: return location for number of elements in returned array
+ * 
+ * Obtains a list of keycode/group/level combinations that will
+ * generate @keyval. Groups and levels are two kinds of keyboard mode;
+ * in general, the level determines whether the top or bottom symbol
+ * on a key is used, and the group determines whether the left or
+ * right symbol is used. On US keyboards, the shift key changes the
+ * keyboard level, and there are no groups. A group switch key might
+ * convert a keyboard between Hebrew to English modes, for example.
+ * #GdkEventKey contains a %group field that indicates the active
+ * keyboard group. The level is computed from the modifier mask.
+ * The returned array should be freed
+ * with g_free().
+ *
+ * Return value: %TRUE if keys were found and returned
+ **/
+gboolean
+gdk_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
+                                   guint          keyval,
+                                   GdkKeymapKey **keys,
+                                   gint          *n_keys)
+{
+  GArray *retval;
+
+  g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
+  g_return_val_if_fail (keys != NULL, FALSE);
+  g_return_val_if_fail (n_keys != NULL, FALSE);
+  g_return_val_if_fail (keyval != 0, FALSE);
+  
+  retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
+
+#ifdef HAVE_XKB
+  if (_gdk_use_xkb)
+    {
+      /* See sec 15.3.4 in XKB docs */
+
+      XkbDescRec *xkb = get_xkb ();
+      gint keycode;
+      
+      keycode = min_keycode;
+
+      while (keycode <= max_keycode)
+        {
+          gint max_shift_levels = XkbKeyGroupsWidth (xkb, keycode); /* "key width" */
+          gint group = 0;
+          gint level = 0;
+          gint total_syms = XkbKeyNumSyms (xkb, keycode);
+          gint i = 0;
+          KeySym *entry;
+
+          /* entry is an array with all syms for group 0, all
+           * syms for group 1, etc. and for each group the
+           * shift level syms are in order
+           */
+          entry = XkbKeySymsPtr (xkb, keycode);
+
+          while (i < total_syms)
+            {
+              /* check out our cool loop invariant */
+              g_assert (i == (group * max_shift_levels + level));
+
+              if (entry[i] == keyval)
+                {
+                  /* Found a match */
+                  GdkKeymapKey key;
+
+                  key.keycode = keycode;
+                  key.group = group;
+                  key.level = level;
+
+                  g_array_append_val (retval, key);
+
+                  g_assert (XkbKeySymEntry (xkb, keycode, level, group) == keyval);
+                }
+
+              ++level;
+
+              if (level == max_shift_levels)
+                {
+                  level = 0;
+                  ++group;
+                }
+
+              ++i;
+            }
+
+          ++keycode;
+        }
+    }
+  else
+#endif
+    {
+      const KeySym *map = get_keymap ();
+      gint keycode;
+      
+      keycode = min_keycode;
+      while (keycode < max_keycode)
+        {
+          const KeySym *syms = map + (keycode - min_keycode) * keysyms_per_keycode;
+          gint i = 0;
+
+          while (i < keysyms_per_keycode)
+            {
+              if (syms[i] == keyval)
+                {
+                  /* found a match */
+                  GdkKeymapKey key;
+
+                  key.keycode = keycode;
+
+                  /* The "classic" non-XKB keymap has 2 levels per group */
+                  key.group = i / 2;
+                  key.level = i % 2;
+
+                  g_array_append_val (retval, key);
+                }
+              
+              ++i;
+            }
+          
+          ++keycode;
+        }
+    }
+
+  if (retval->len > 0)
+    {
+      *keys = (GdkKeymapKey*) retval->data;
+      *n_keys = retval->len;
+    }
+  else
+    {
+      *keys = NULL;
+      *n_keys = 0;
+    }
+      
+  g_array_free (retval, retval->len > 0 ? FALSE : TRUE);
+
+  return *n_keys > 0;
+}
+
+/**
+ * gdk_keymap_get_entries_for_keycode:
+ * @keymap: a #GdkKeymap or %NULL to use the default keymap
+ * @hardware_keycode: a keycode
+ * @keys: return location for array of #GdkKeymapKey, or NULL
+ * @keyvals: return location for array of keyvals, or NULL
+ * @n_entries: length of @keys and @keyvals
+ *
+ * Returns the keyvals bound to @hardware_keycode.
+ * The Nth #GdkKeymapKey in @keys is bound to the Nth
+ * keyval in @keyvals. Free the returned arrays with g_free().
+ * When a keycode is pressed by the user, the keyval from
+ * this list of entries is selected by considering the effective
+ * keyboard group and level. See gdk_keymap_translate_keyboard_state().
+ *
+ * Returns: %TRUE if there were any entries
+ **/
+gboolean
+gdk_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
+                                    guint          hardware_keycode,
+                                    GdkKeymapKey **keys,
+                                    guint        **keyvals,
+                                    gint          *n_entries)
+{
+  GArray *key_array;
+  GArray *keyval_array;
+
+  g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
+  g_return_val_if_fail (n_entries != NULL, FALSE);
+
+  update_keyrange ();
+
+  if (hardware_keycode < min_keycode ||
+      hardware_keycode > max_keycode)
+    {
+      if (keys)
+        *keys = NULL;
+      if (keyvals)
+        *keyvals = NULL;
+
+      *n_entries = 0;
+      return FALSE;
+    }
+  
+  if (keys)
+    key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
+  else
+    key_array = NULL;
+  
+  if (keyvals)
+    keyval_array = g_array_new (FALSE, FALSE, sizeof (guint));
+  else
+    keyval_array = NULL;
+  
+#ifdef HAVE_XKB
+  if (_gdk_use_xkb)
+    {
+      /* See sec 15.3.4 in XKB docs */
+
+      XkbDescRec *xkb = get_xkb ();
+      gint max_shift_levels;
+      gint group = 0;
+      gint level = 0;
+      gint total_syms;
+      gint i = 0;
+      KeySym *entry;
+      
+      max_shift_levels = XkbKeyGroupsWidth (xkb, hardware_keycode); /* "key width" */
+      total_syms = XkbKeyNumSyms (xkb, hardware_keycode);
+
+      /* entry is an array with all syms for group 0, all
+       * syms for group 1, etc. and for each group the
+       * shift level syms are in order
+       */
+      entry = XkbKeySymsPtr (xkb, hardware_keycode);
+
+      while (i < total_syms)
+        {          
+          /* check out our cool loop invariant */          
+          g_assert (i == (group * max_shift_levels + level));
+
+          if (key_array)
+            {
+              GdkKeymapKey key;
+              
+              key.keycode = hardware_keycode;
+              key.group = group;
+              key.level = level;
+              
+              g_array_append_val (key_array, key);
+            }
+
+          if (keyval_array)
+            g_array_append_val (keyval_array, entry[i]);
+          
+          ++level;
+          
+          if (level == max_shift_levels)
+            {
+              level = 0;
+              ++group;
+            }
+          
+          ++i;
+        }
+    }
+  else
+#endif
+    {
+      const KeySym *map = get_keymap ();
+      const KeySym *syms;
+      gint i = 0;
+
+      syms = map + (hardware_keycode - min_keycode) * keysyms_per_keycode;
+
+      while (i < keysyms_per_keycode)
+        {
+          if (key_array)
+            {
+              GdkKeymapKey key;
+          
+              key.keycode = hardware_keycode;
+              
+              /* The "classic" non-XKB keymap has 2 levels per group */
+              key.group = i / 2;
+              key.level = i % 2;
+              
+              g_array_append_val (key_array, key);
+            }
+
+          if (keyval_array)
+            g_array_append_val (keyval_array, syms[i]);
+          
+          ++i;
+        }
+    }
+  
+  if ((key_array && key_array->len > 0) ||
+      (keyval_array && keyval_array->len > 0))
+    {
+      if (keys)
+        *keys = (GdkKeymapKey*) key_array->data;
+
+      if (keyvals)
+        *keyvals = (guint*) keyval_array->data;
+
+      if (key_array)
+        *n_entries = key_array->len;
+      else
+        *n_entries = keyval_array->len;
+    }
+  else
+    {
+      if (keys)
+        *keys = NULL;
+
+      if (keyvals)
+        *keyvals = NULL;
+      
+      *n_entries = 0;
+    }
+
+  if (key_array)
+    g_array_free (key_array, key_array->len > 0 ? FALSE : TRUE);
+  if (keyval_array)
+    g_array_free (keyval_array, keyval_array->len > 0 ? FALSE : TRUE);
+
+  return *n_entries > 0;
+}
+
+
+/**
+ * gdk_keymap_lookup_key:
+ * @keymap: a #GdkKeymap or %NULL to use the default keymap
+ * @key: a #GdkKeymapKey with keycode, group, and level initialized
+ * 
+ * Looks up the keyval mapped to a keycode/group/level triplet.
+ * If no keyval is bound to @key, returns 0. For normal user input,
+ * you want to use gdk_keymap_translate_keyboard_state() instead of
+ * this function, since the effective group/level may not be
+ * the same as the current keyboard state.
+ * 
+ * Return value: a keyval, or 0 if none was mapped to the given @key
+ **/
+guint
+gdk_key_key_to_keyval (GdkKeymap          *keymap,
+                       const GdkKeymapKey *key)
+{
+  g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), 0);
+  g_return_val_if_fail (key != NULL, 0);
+  g_return_val_if_fail (key->group < 4, 0);
+  
+#ifdef HAVE_XKB
+  if (_gdk_use_xkb)
+    {
+      XkbDescRec *xkb = get_xkb ();
+      
+      return XkbKeySymEntry (xkb, key->keycode, key->level, key->group);
+    }
+  else
+#endif
+    {
+      update_keymaps ();
+      
+      return XKeycodeToKeysym (gdk_display, key->keycode,
+                               key->group * keysyms_per_keycode + key->level);
+    }
+}
+
+#ifdef HAVE_XKB
+/* This is copied straight from XFree86 Xlib, because I needed to
+ * add the group and level return. It's unchanged for ease of
+ * diff against the Xlib sources; don't reformat it.
+ */
+static Bool
+MyEnhancedXkbTranslateKeyCode(register XkbDescPtr     xkb,
+                              KeyCode                 key,
+                              register unsigned int   mods,
+                              unsigned int *          mods_rtrn,
+                              KeySym *                keysym_rtrn,
+                              unsigned int *          group_rtrn,
+                              unsigned int *          level_rtrn)
+{
+    XkbKeyTypeRec *type;
+    int col,nKeyGroups;
+    unsigned preserve,effectiveGroup;
+    KeySym *syms;
+
+    if (mods_rtrn!=NULL)
+        *mods_rtrn = 0;
+
+    nKeyGroups= XkbKeyNumGroups(xkb,key);
+    if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) {
+        if (keysym_rtrn!=NULL)
+            *keysym_rtrn = NoSymbol;
+        return False;
+    }
+
+    syms = XkbKeySymsPtr(xkb,key);
+
+    /* find the offset of the effective group */
+    col = 0;
+    effectiveGroup= XkbGroupForCoreState(mods);
+    if ( effectiveGroup>=nKeyGroups ) {
+        unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
+        switch (XkbOutOfRangeGroupAction(groupInfo)) {
+            default:
+                effectiveGroup %= nKeyGroups;
+                break;
+            case XkbClampIntoRange:
+                effectiveGroup = nKeyGroups-1;
+                break;
+            case XkbRedirectIntoRange:
+                effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
+                if (effectiveGroup>=nKeyGroups)
+                    effectiveGroup= 0;
+                break;
+        }
+    }
+    col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
+    type = XkbKeyKeyType(xkb,key,effectiveGroup);
+
+    preserve= 0;
+    if (type->map) { /* find the column (shift level) within the group */
+        register int i;
+        register XkbKTMapEntryPtr entry;
+        for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
+            if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
+                col+= entry->level;
+                if (type->preserve)
+                    preserve= type->preserve[i].mask;
+
+                /* ---- Begin stuff GDK adds to the original Xlib version ---- */
+                
+                if (level_rtrn)
+                  *level_rtrn = entry->level;
+                
+                /* ---- End stuff GDK adds to the original Xlib version ---- */
+                
+                break;
+            }
+        }
+    }
+
+    if (keysym_rtrn!=NULL)
+        *keysym_rtrn= syms[col];
+    if (mods_rtrn) {
+        *mods_rtrn= type->mods.mask&(~preserve);
+
+        /* ---- Begin stuff GDK comments out of the original Xlib version ---- */
+        /* This is commented out because xkb_info is a private struct */
+
+#if 0
+        /* The Motif VTS doesn't get the help callback called if help
+         * is bound to Shift+<whatever>, and it appears as though it 
+         * is XkbTranslateKeyCode that is causing the problem.  The 
+         * core X version of XTranslateKey always OR's in ShiftMask 
+         * and LockMask for mods_rtrn, so this "fix" keeps this behavior 
+         * and solves the VTS problem.
+         */
+        if ((xkb->dpy)&&(xkb->dpy->xkb_info)&&
+            (xkb->dpy->xkb_info->xlib_ctrls&XkbLC_AlwaysConsumeShiftAndLock)) {            *mods_rtrn|= (ShiftMask|LockMask);
+        }
+#endif
+        
+        /* ---- End stuff GDK comments out of the original Xlib version ---- */
+    }
+
+    /* ---- Begin stuff GDK adds to the original Xlib version ---- */
+
+    if (group_rtrn)
+      *group_rtrn = effectiveGroup;
+    
+    /* ---- End stuff GDK adds to the original Xlib version ---- */
+    
+    return (syms[col]!=NoSymbol);
+}
+#endif /* HAVE_XKB */
+
+/**
+ * gdk_keymap_translate_keyboard_state:
+ * @keymap: a #GdkKeymap, or %NULL to use the default
+ * @hardware_keycode: a keycode
+ * @state: a modifier state 
+ * @group: active keyboard group
+ * @keyval: return location for keyval
+ * @effective_group: return location for effective group
+ * @level: return location for level
+ * @unused_modifiers: return location for modifiers that didn't affect the group or level
+ * 
+ *
+ * Translates the contents of a #GdkEventKey into a keyval, effective
+ * group, and level. Modifiers that didn't affect the translation and
+ * are thus available for application use are returned in
+ * @unused_modifiers.  See gdk_keyval_get_keys() for an explanation of
+ * groups and levels.  The @effective_group is the group that was
+ * actually used for the translation; some keys such as Enter are not
+ * affected by the active keyboard group. The @level is derived from
+ * @state. For convenience, #GdkEventKey already contains the translated
+ * keyval, so this function isn't as useful as you might think.
+ * 
+ * Return value: %TRUE if there was a keyval bound to the keycode/state/group
+ **/
+gboolean
+gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
+                                     guint            hardware_keycode,
+                                     GdkModifierType  state,
+                                     gint             group,
+                                     guint           *keyval,
+                                     gint            *effective_group,
+                                     gint            *level,
+                                     GdkModifierType *unused_modifiers)
+{
+  KeySym tmp_keyval = NoSymbol;
+
+  g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
+  g_return_val_if_fail (group < 4, FALSE);
+  
+  if (keyval)
+    *keyval = NoSymbol;
+  if (effective_group)
+    *effective_group = 0;
+  if (level)
+    *level = 0;
+  if (unused_modifiers)
+    *unused_modifiers = state;
+
+  update_keyrange ();
+  
+  if (hardware_keycode < min_keycode ||
+      hardware_keycode > max_keycode)
+    return FALSE;
+  
+#ifdef HAVE_XKB
+  if (_gdk_use_xkb)
+    {
+      XkbDescRec *xkb = get_xkb ();
+
+      /* replace bits 13 and 14 with the provided group */
+      state &= ~(1 << 13 | 1 << 14);
+      state |= group << 13;
+      
+      MyEnhancedXkbTranslateKeyCode (xkb,
+                                     hardware_keycode,
+                                     state,
+                                     unused_modifiers,
+                                     &tmp_keyval,
+                                     effective_group,
+                                     level);
+
+      if (keyval)
+        *keyval = tmp_keyval;
+    }
+  else
+#endif
+    {
+      gint shift_level;
+      
+      update_keymaps ();
+
+      if ((state & GDK_SHIFT_MASK) &&
+          (state & GDK_LOCK_MASK))
+        shift_level = 0; /* shift disables shift lock */
+      else if ((state & GDK_SHIFT_MASK) ||
+               (state & GDK_LOCK_MASK))
+        shift_level = 1;
+      else
+        shift_level = 0;
+
+      tmp_keyval = XKeycodeToKeysym (gdk_display, hardware_keycode,
+                                     group * keysyms_per_keycode + shift_level);
+      
+      if (keyval)
+        *keyval = tmp_keyval;
+
+      if (unused_modifiers)
+        {
+          *unused_modifiers = state;
+          *unused_modifiers &= ~(GDK_SHIFT_MASK | GDK_LOCK_MASK | group_switch_mask);
+        }
+      
+      if (effective_group)
+        *effective_group = (state & group_switch_mask) ? 1 : 0;
+
+      if (level)
+        *level = shift_level;
+    }
+
+  return tmp_keyval != NoSymbol;
+}
+
+
+/* Key handling not part of the keymap */
+
+gchar*
+gdk_keyval_name (guint	      keyval)
+{
+  return XKeysymToString (keyval);
+}
+
+guint
+gdk_keyval_from_name (const gchar *keyval_name)
+{
+  g_return_val_if_fail (keyval_name != NULL, 0);
+  
+  return XStringToKeysym (keyval_name);
+}
+
+#ifdef HAVE_XCONVERTCASE
+void
+gdk_keyval_convert_case (guint symbol,
+			 guint *lower,
+			 guint *upper)
+{
+  KeySym xlower = 0;
+  KeySym xupper = 0;
+
+  if (symbol)
+    XConvertCase (symbol, &xlower, &xupper);
+
+  if (lower)
+    *lower = xlower;
+  if (upper)
+    *upper = xupper;
+}  
+#endif HAVE_XCONVERTCASE
Index: gdk/x11/gdkmain-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkmain-x11.c,v
retrieving revision 1.121
diff -u -u -r1.121 gdkmain-x11.c
--- gdk/x11/gdkmain-x11.c	2000/10/04 16:51:42	1.121
+++ gdk/x11/gdkmain-x11.c	2000/12/03 19:18:06
@@ -45,11 +45,16 @@
 #include <X11/Xutil.h>
 #include <X11/cursorfont.h>
 
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
 #include "gdk.h"
 
 #include "gdkprivate-x11.h"
 #include "gdkinternals.h"
 #include "gdkinputprivate.h"
+
 #include <pango/pangox.h>
 
 typedef struct _GdkPredicate  GdkPredicate;
@@ -196,6 +201,28 @@
   
   XGetKeyboardControl (gdk_display, &keyboard_state);
   autorepeat = keyboard_state.global_auto_repeat;
+
+#ifdef HAVE_XKB
+  {
+    gint xkb_major = XkbMajorVersion;
+    gint xkb_minor = XkbMinorVersion;
+    if (XkbLibraryVersion (&xkb_major, &xkb_minor))
+      {
+        xkb_major = XkbMajorVersion;
+        xkb_minor = XkbMinorVersion;
+        if (XkbQueryExtension (gdk_display, NULL, NULL, NULL,
+                               &xkb_major, &xkb_minor))
+          {
+            _gdk_use_xkb = TRUE;
+
+            XkbSelectEvents (gdk_display,
+                             XkbUseCoreKbd,
+                             XkbMapNotifyMask,
+                             XkbMapNotifyMask);
+          }
+      }
+  }
+#endif
   
   return TRUE;
 }
@@ -725,35 +752,3 @@
   return result && !gdk_error_code;
 }
 
-gchar*
-gdk_keyval_name (guint	      keyval)
-{
-  return XKeysymToString (keyval);
-}
-
-guint
-gdk_keyval_from_name (const gchar *keyval_name)
-{
-  g_return_val_if_fail (keyval_name != NULL, 0);
-  
-  return XStringToKeysym (keyval_name);
-}
-
-#ifdef HAVE_XCONVERTCASE
-void
-gdk_keyval_convert_case (guint symbol,
-			 guint *lower,
-			 guint *upper)
-{
-  KeySym xlower = 0;
-  KeySym xupper = 0;
-
-  if (symbol)
-    XConvertCase (symbol, &xlower, &xupper);
-
-  if (lower)
-    *lower = xlower;
-  if (upper)
-    *upper = xupper;
-}  
-#endif HAVE_XCONVERTCASE
Index: gdk/x11/gdkprivate-x11.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkprivate-x11.h,v
retrieving revision 1.6
diff -u -u -r1.6 gdkprivate-x11.h
--- gdk/x11/gdkprivate-x11.h	2000/10/24 00:15:13	1.6
+++ gdk/x11/gdkprivate-x11.h	2000/12/03 19:18:06
@@ -34,6 +34,8 @@
 #include <gdk/gdkprivate.h>
 #include "gdkx.h"
 
+#include <config.h>
+
 void          gdk_xid_table_insert     (XID             *xid,
 					gpointer         data);
 void          gdk_xid_table_remove     (XID              xid);
@@ -101,5 +103,10 @@
 extern GdkWindow *gdk_xim_window;	        /* currently using Window */
 #endif /* USE_XIM */
 
+#ifdef HAVE_XKB
+/* Used to detect not-up-to-date XKB keymap */
+extern guint _gdk_keymap_serial;
+extern gboolean _gdk_use_xkb;
+#endif
 
 #endif /* __GDK_PRIVATE_X11_H__ */




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]