summaryrefslogtreecommitdiff
path: root/gdk
diff options
context:
space:
mode:
authorHavoc Pennington <hp@pobox.com>2000-12-06 05:31:30 +0000
committerHavoc Pennington <hp@src.gnome.org>2000-12-06 05:31:30 +0000
commit36aac0177bfe4dfed46cfcf8568256fe5b05f9b0 (patch)
tree5091a09100b1743bf733d47dde7db34e9b673fc6 /gdk
parent3bc53c742d676a974987ad084f8617a1ab6068fd (diff)
downloadgtk+-36aac0177bfe4dfed46cfcf8568256fe5b05f9b0.tar.gz
add gdkkeys.[hc]
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 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)
Diffstat (limited to 'gdk')
-rw-r--r--gdk/Makefile.am2
-rw-r--r--gdk/gdk.c178
-rw-r--r--gdk/gdk.h16
-rw-r--r--gdk/gdkevents.h2
-rw-r--r--gdk/gdkkeys.c280
-rw-r--r--gdk/gdkkeys.h120
-rw-r--r--gdk/x11/Makefile.am1
-rw-r--r--gdk/x11/gdkevents-x11.c18
-rw-r--r--gdk/x11/gdkkeys-x11.c782
-rw-r--r--gdk/x11/gdkmain-x11.c59
-rw-r--r--gdk/x11/gdkprivate-x11.h7
11 files changed, 1239 insertions, 226 deletions
diff --git a/gdk/Makefile.am b/gdk/Makefile.am
index 5aec9804d9..916f02a563 100644
--- a/gdk/Makefile.am
+++ b/gdk/Makefile.am
@@ -65,6 +65,7 @@ gdk_public_h_sources = @STRIP_BEGIN@ \
gdkim.h \
gdkimage.h \
gdkinput.h \
+ gdkkeys.h \
gdkpango.h \
gdkpixbuf.h \
gdkpixmap.h \
@@ -87,6 +88,7 @@ gdk_c_sources = @STRIP_BEGIN@ \
gdkfont.c \
gdkgc.c \
gdkglobals.c \
+ gdkkeys.c \
gdkkeyuni.c \
gdkimage.c \
gdkinternals.h \
diff --git a/gdk/gdk.c b/gdk/gdk.c
index 6860146a16..fb0a7654ed 100644
--- a/gdk/gdk.c
+++ b/gdk/gdk.c
@@ -507,184 +507,6 @@ gdk_error_trap_pop (void)
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 ()
{
diff --git a/gdk/gdk.h b/gdk/gdk.h
index 8553663cc8..ec048524a1 100644
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -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>
@@ -134,21 +135,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
*/
diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h
index 5813f894d5..04f1d78710 100644
--- a/gdk/gdkevents.h
+++ b/gdk/gdkevents.h
@@ -280,7 +280,7 @@ struct _GdkEventKey
gint length;
gchar *string;
guint16 hardware_keycode;
- guint8 keyboard_group;
+ guint8 group;
};
struct _GdkEventCrossing
diff --git a/gdk/gdkkeys.c b/gdk/gdkkeys.c
new file mode 100644
index 0000000000..9b5911fd30
--- /dev/null
+++ b/gdk/gdkkeys.c
@@ -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;
+}
diff --git a/gdk/gdkkeys.h b/gdk/gdkkeys.h
new file mode 100644
index 0000000000..20d50348cd
--- /dev/null
+++ b/gdk/gdkkeys.h
@@ -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__ */
diff --git a/gdk/x11/Makefile.am b/gdk/x11/Makefile.am
index d4870774d2..ab32460360 100644
--- a/gdk/x11/Makefile.am
+++ b/gdk/x11/Makefile.am
@@ -55,6 +55,7 @@ libgdk_x11_la_SOURCES = \
gdkim-x11.c \
gdkimage-x11.c \
gdkinput.c \
+ gdkkeys-x11.c \
gdkmain-x11.c \
gdkpango-x11.c \
gdkpixmap-x11.c \
diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c
index afd843deda..f0cb18affc 100644
--- a/gdk/x11/gdkevents-x11.c
+++ b/gdk/x11/gdkevents-x11.c
@@ -40,6 +40,10 @@
#include "gdkinputprivate.h"
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
typedef struct _GdkIOClosure GdkIOClosure;
typedef struct _GdkEventPrivate GdkEventPrivate;
@@ -432,6 +436,7 @@ gdk_event_translate (GdkEvent *event,
&keysym, &compose);
#endif
event->key.keyval = keysym;
+ event->key.hardware_keycode = xevent->xkey.keycode;
if (charcount > 0 && buf[charcount-1] == '\0')
charcount --;
@@ -450,6 +455,9 @@ gdk_event_translate (GdkEvent *event,
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;
@@ -457,6 +465,8 @@ gdk_event_translate (GdkEvent *event,
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;
@@ -1163,8 +1173,16 @@ gdk_event_translate (GdkEvent *event,
/* 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) */
diff --git a/gdk/x11/gdkkeys-x11.c b/gdk/x11/gdkkeys-x11.c
new file mode 100644
index 0000000000..648459d6e6
--- /dev/null
+++ b/gdk/x11/gdkkeys-x11.c
@@ -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
diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c
index c37d6b5fa2..3c34790533 100644
--- a/gdk/x11/gdkmain-x11.c
+++ b/gdk/x11/gdkmain-x11.c
@@ -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 @@ _gdk_windowing_init_check (int argc, char **argv)
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 @@ gdk_send_xevent (Window window, gboolean propagate, glong event_mask,
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
diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h
index 4653fd0ac9..2a53104be1 100644
--- a/gdk/x11/gdkprivate-x11.h
+++ b/gdk/x11/gdkprivate-x11.h
@@ -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 GdkICPrivate *gdk_xim_ic; /* currently using IC */
extern GdkWindow *gdk_xim_window; /* currently using Window */
#endif /* USE_XIM */
+/* Used to detect not-up-to-date keymap */
+extern guint _gdk_keymap_serial;
+#ifdef HAVE_XKB
+extern gboolean _gdk_use_xkb;
+#endif
#endif /* __GDK_PRIVATE_X11_H__ */