diff options
author | Havoc Pennington <hp@pobox.com> | 2000-12-06 05:31:30 +0000 |
---|---|---|
committer | Havoc Pennington <hp@src.gnome.org> | 2000-12-06 05:31:30 +0000 |
commit | 36aac0177bfe4dfed46cfcf8568256fe5b05f9b0 (patch) | |
tree | 5091a09100b1743bf733d47dde7db34e9b673fc6 /gdk | |
parent | 3bc53c742d676a974987ad084f8617a1ab6068fd (diff) | |
download | gtk+-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.am | 2 | ||||
-rw-r--r-- | gdk/gdk.c | 178 | ||||
-rw-r--r-- | gdk/gdk.h | 16 | ||||
-rw-r--r-- | gdk/gdkevents.h | 2 | ||||
-rw-r--r-- | gdk/gdkkeys.c | 280 | ||||
-rw-r--r-- | gdk/gdkkeys.h | 120 | ||||
-rw-r--r-- | gdk/x11/Makefile.am | 1 | ||||
-rw-r--r-- | gdk/x11/gdkevents-x11.c | 18 | ||||
-rw-r--r-- | gdk/x11/gdkkeys-x11.c | 782 | ||||
-rw-r--r-- | gdk/x11/gdkmain-x11.c | 59 | ||||
-rw-r--r-- | gdk/x11/gdkprivate-x11.h | 7 |
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 \ @@ -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 () { @@ -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__ */ |