1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 2000 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
37 #include "gdkprivate-x11.h"
38 #include "gdkinternals.h"
39 #include "gdkkeysyms.h"
43 guint _gdk_keymap_serial = 0;
45 static gint min_keycode = 0;
46 static gint max_keycode = 0;
49 update_keyrange (void)
52 XDisplayKeycodes (gdk_display, &min_keycode, &max_keycode);
56 #include <X11/XKBlib.h>
58 gboolean _gdk_use_xkb = FALSE;
59 gint _gdk_xkb_event_type;
60 static XkbDescPtr xkb_desc = NULL;
65 static guint current_serial = 0;
71 xkb_desc = XkbGetMap (gdk_display, XkbKeySymsMask, XkbUseCoreKbd);
73 g_error ("Failed to get keymap");
75 XkbGetNames (gdk_display, XkbGroupNamesMask, xkb_desc);
77 else if (current_serial != _gdk_keymap_serial)
79 XkbGetUpdatedMap (gdk_display, XkbKeySymsMask, xkb_desc);
80 XkbGetNames (gdk_display, XkbGroupNamesMask, xkb_desc);
83 current_serial = _gdk_keymap_serial;
89 /* Whether we were able to turn on detectable-autorepeat using
90 * XkbSetDetectableAutorepeat. If FALSE, we'll fall back
91 * to checking the next event with XPending().
93 gboolean _gdk_have_xkb_autorepeat = FALSE;
95 static KeySym* keymap = NULL;
96 static gint keysyms_per_keycode = 0;
97 static XModifierKeymap* mod_keymap = NULL;
98 static GdkModifierType group_switch_mask = 0;
99 static PangoDirection current_direction;
100 static gboolean have_direction = FALSE;
101 static GdkKeymap *default_keymap = NULL;
104 gdk_keymap_get_default (void)
106 if (default_keymap == NULL)
107 default_keymap = g_object_new (gdk_keymap_get_type (), NULL);
109 return default_keymap;
113 update_keymaps (void)
115 static guint current_serial = 0;
118 g_assert (!_gdk_use_xkb);
121 if (keymap == NULL ||
122 current_serial != _gdk_keymap_serial)
133 XFreeModifiermap (mod_keymap);
135 keymap = XGetKeyboardMapping (gdk_display, min_keycode,
136 max_keycode - min_keycode,
137 &keysyms_per_keycode);
139 mod_keymap = XGetModifierMapping (gdk_display);
142 group_switch_mask = 0;
144 /* there are 8 modifiers, and the first 3 are shift, shift lock,
147 map_size = 8 * mod_keymap->max_keypermod;
148 i = 3 * mod_keymap->max_keypermod;
151 /* get the key code at this point in the map,
152 * see if its keysym is GDK_Mode_switch, if so
153 * we have the mode key
155 gint keycode = mod_keymap->modifiermap[i];
157 if (keycode >= min_keycode &&
158 keycode <= max_keycode)
161 KeySym *syms = keymap + (keycode - min_keycode) * keysyms_per_keycode;
162 while (j < keysyms_per_keycode)
164 if (syms[j] == GDK_Mode_switch)
166 /* This modifier swaps groups */
168 /* GDK_MOD1_MASK is 1 << 3 for example, i.e. the
169 * fourth modifier, i / keyspermod is the modifier
173 group_switch_mask |= (1 << ( i / mod_keymap->max_keypermod));
199 XkbDescRec *xkb = get_xkb ();
201 XkbStateRec state_rec;
202 PangoDirection result;
204 XkbGetState (gdk_display, XkbUseCoreKbd, &state_rec);
206 name = gdk_atom_name (xkb->names->groups[state_rec.locked_group]);
207 if (g_strcasecmp (name, "arabic") == 0 ||
208 g_strcasecmp (name, "hebrew") == 0 ||
209 g_strcasecmp (name, "israelian") == 0)
210 result = PANGO_DIRECTION_RTL;
212 result = PANGO_DIRECTION_LTR;
220 _gdk_keymap_state_changed (void)
224 PangoDirection new_direction = get_direction ();
226 if (!have_direction || new_direction != current_direction)
228 have_direction = TRUE;
229 current_direction = new_direction;
230 g_signal_emit_by_name (G_OBJECT (default_keymap), "direction_changed");
234 #endif /* HAVE_XKB */
237 gdk_keymap_get_direction (GdkKeymap *keymap)
241 current_direction = get_direction ();
242 have_direction = TRUE;
245 return current_direction;
249 * gdk_keymap_get_entries_for_keyval:
250 * @keymap: a #GdkKeymap, or %NULL to use the default keymap
251 * @keyval: a keyval, such as %GDK_a, %GDK_Up, %GDK_Return, etc.
252 * @keys: return location for an array of #GdkKeymapKey
253 * @n_keys: return location for number of elements in returned array
255 * Obtains a list of keycode/group/level combinations that will
256 * generate @keyval. Groups and levels are two kinds of keyboard mode;
257 * in general, the level determines whether the top or bottom symbol
258 * on a key is used, and the group determines whether the left or
259 * right symbol is used. On US keyboards, the shift key changes the
260 * keyboard level, and there are no groups. A group switch key might
261 * convert a keyboard between Hebrew to English modes, for example.
262 * #GdkEventKey contains a %group field that indicates the active
263 * keyboard group. The level is computed from the modifier mask.
264 * The returned array should be freed
267 * Return value: %TRUE if keys were found and returned
270 gdk_keymap_get_entries_for_keyval (GdkKeymap *keymap,
277 g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
278 g_return_val_if_fail (keys != NULL, FALSE);
279 g_return_val_if_fail (n_keys != NULL, FALSE);
280 g_return_val_if_fail (keyval != 0, FALSE);
282 retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
287 /* See sec 15.3.4 in XKB docs */
289 XkbDescRec *xkb = get_xkb ();
292 keycode = min_keycode;
294 while (keycode <= max_keycode)
296 gint max_shift_levels = XkbKeyGroupsWidth (xkb, keycode); /* "key width" */
299 gint total_syms = XkbKeyNumSyms (xkb, keycode);
303 /* entry is an array with all syms for group 0, all
304 * syms for group 1, etc. and for each group the
305 * shift level syms are in order
307 entry = XkbKeySymsPtr (xkb, keycode);
309 while (i < total_syms)
311 /* check out our cool loop invariant */
312 g_assert (i == (group * max_shift_levels + level));
314 if (entry[i] == keyval)
319 key.keycode = keycode;
323 g_array_append_val (retval, key);
325 g_assert (XkbKeySymEntry (xkb, keycode, level, group) == keyval);
330 if (level == max_shift_levels)
345 const KeySym *map = get_keymap ();
348 keycode = min_keycode;
349 while (keycode < max_keycode)
351 const KeySym *syms = map + (keycode - min_keycode) * keysyms_per_keycode;
354 while (i < keysyms_per_keycode)
356 if (syms[i] == keyval)
361 key.keycode = keycode;
363 /* The "classic" non-XKB keymap has 2 levels per group */
367 g_array_append_val (retval, key);
379 *keys = (GdkKeymapKey*) retval->data;
380 *n_keys = retval->len;
388 g_array_free (retval, retval->len > 0 ? FALSE : TRUE);
394 * gdk_keymap_get_entries_for_keycode:
395 * @keymap: a #GdkKeymap or %NULL to use the default keymap
396 * @hardware_keycode: a keycode
397 * @keys: return location for array of #GdkKeymapKey, or NULL
398 * @keyvals: return location for array of keyvals, or NULL
399 * @n_entries: length of @keys and @keyvals
401 * Returns the keyvals bound to @hardware_keycode.
402 * The Nth #GdkKeymapKey in @keys is bound to the Nth
403 * keyval in @keyvals. Free the returned arrays with g_free().
404 * When a keycode is pressed by the user, the keyval from
405 * this list of entries is selected by considering the effective
406 * keyboard group and level. See gdk_keymap_translate_keyboard_state().
408 * Returns: %TRUE if there were any entries
411 gdk_keymap_get_entries_for_keycode (GdkKeymap *keymap,
412 guint hardware_keycode,
418 GArray *keyval_array;
420 g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
421 g_return_val_if_fail (n_entries != NULL, FALSE);
425 if (hardware_keycode < min_keycode ||
426 hardware_keycode > max_keycode)
438 key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
443 keyval_array = g_array_new (FALSE, FALSE, sizeof (guint));
450 /* See sec 15.3.4 in XKB docs */
452 XkbDescRec *xkb = get_xkb ();
453 gint max_shift_levels;
460 max_shift_levels = XkbKeyGroupsWidth (xkb, hardware_keycode); /* "key width" */
461 total_syms = XkbKeyNumSyms (xkb, hardware_keycode);
463 /* entry is an array with all syms for group 0, all
464 * syms for group 1, etc. and for each group the
465 * shift level syms are in order
467 entry = XkbKeySymsPtr (xkb, hardware_keycode);
469 while (i < total_syms)
471 /* check out our cool loop invariant */
472 g_assert (i == (group * max_shift_levels + level));
478 key.keycode = hardware_keycode;
482 g_array_append_val (key_array, key);
486 g_array_append_val (keyval_array, entry[i]);
490 if (level == max_shift_levels)
502 const KeySym *map = get_keymap ();
506 syms = map + (hardware_keycode - min_keycode) * keysyms_per_keycode;
508 while (i < keysyms_per_keycode)
514 key.keycode = hardware_keycode;
516 /* The "classic" non-XKB keymap has 2 levels per group */
520 g_array_append_val (key_array, key);
524 g_array_append_val (keyval_array, syms[i]);
530 if ((key_array && key_array->len > 0) ||
531 (keyval_array && keyval_array->len > 0))
534 *keys = (GdkKeymapKey*) key_array->data;
537 *keyvals = (guint*) keyval_array->data;
540 *n_entries = key_array->len;
542 *n_entries = keyval_array->len;
556 g_array_free (key_array, key_array->len > 0 ? FALSE : TRUE);
558 g_array_free (keyval_array, keyval_array->len > 0 ? FALSE : TRUE);
560 return *n_entries > 0;
565 * gdk_keymap_lookup_key:
566 * @keymap: a #GdkKeymap or %NULL to use the default keymap
567 * @key: a #GdkKeymapKey with keycode, group, and level initialized
569 * Looks up the keyval mapped to a keycode/group/level triplet.
570 * If no keyval is bound to @key, returns 0. For normal user input,
571 * you want to use gdk_keymap_translate_keyboard_state() instead of
572 * this function, since the effective group/level may not be
573 * the same as the current keyboard state.
575 * Return value: a keyval, or 0 if none was mapped to the given @key
578 gdk_keymap_lookup_key (GdkKeymap *keymap,
579 const GdkKeymapKey *key)
581 g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), 0);
582 g_return_val_if_fail (key != NULL, 0);
583 g_return_val_if_fail (key->group < 4, 0);
588 XkbDescRec *xkb = get_xkb ();
590 return XkbKeySymEntry (xkb, key->keycode, key->level, key->group);
597 return XKeycodeToKeysym (gdk_display, key->keycode,
598 key->group * keysyms_per_keycode + key->level);
603 /* This is copied straight from XFree86 Xlib, because I needed to
604 * add the group and level return. It's unchanged for ease of
605 * diff against the Xlib sources; don't reformat it.
608 MyEnhancedXkbTranslateKeyCode(register XkbDescPtr xkb,
610 register unsigned int mods,
611 unsigned int * mods_rtrn,
612 KeySym * keysym_rtrn,
613 unsigned int * group_rtrn,
614 unsigned int * level_rtrn)
618 unsigned preserve,effectiveGroup;
624 nKeyGroups= XkbKeyNumGroups(xkb,key);
625 if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) {
626 if (keysym_rtrn!=NULL)
627 *keysym_rtrn = NoSymbol;
631 syms = XkbKeySymsPtr(xkb,key);
633 /* find the offset of the effective group */
635 effectiveGroup= XkbGroupForCoreState(mods);
636 if ( effectiveGroup>=nKeyGroups ) {
637 unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
638 switch (XkbOutOfRangeGroupAction(groupInfo)) {
640 effectiveGroup %= nKeyGroups;
642 case XkbClampIntoRange:
643 effectiveGroup = nKeyGroups-1;
645 case XkbRedirectIntoRange:
646 effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
647 if (effectiveGroup>=nKeyGroups)
652 col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
653 type = XkbKeyKeyType(xkb,key,effectiveGroup);
656 if (type->map) { /* find the column (shift level) within the group */
658 register XkbKTMapEntryPtr entry;
659 for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
660 if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
663 preserve= type->preserve[i].mask;
665 /* ---- Begin stuff GDK adds to the original Xlib version ---- */
668 *level_rtrn = entry->level;
670 /* ---- End stuff GDK adds to the original Xlib version ---- */
677 if (keysym_rtrn!=NULL)
678 *keysym_rtrn= syms[col];
680 *mods_rtrn= type->mods.mask&(~preserve);
682 /* ---- Begin stuff GDK comments out of the original Xlib version ---- */
683 /* This is commented out because xkb_info is a private struct */
686 /* The Motif VTS doesn't get the help callback called if help
687 * is bound to Shift+<whatever>, and it appears as though it
688 * is XkbTranslateKeyCode that is causing the problem. The
689 * core X version of XTranslateKey always OR's in ShiftMask
690 * and LockMask for mods_rtrn, so this "fix" keeps this behavior
691 * and solves the VTS problem.
693 if ((xkb->dpy)&&(xkb->dpy->xkb_info)&&
694 (xkb->dpy->xkb_info->xlib_ctrls&XkbLC_AlwaysConsumeShiftAndLock)) { *mods_rtrn|= (ShiftMask|LockMask);
698 /* ---- End stuff GDK comments out of the original Xlib version ---- */
701 /* ---- Begin stuff GDK adds to the original Xlib version ---- */
704 *group_rtrn = effectiveGroup;
706 /* ---- End stuff GDK adds to the original Xlib version ---- */
708 return (syms[col]!=NoSymbol);
710 #endif /* HAVE_XKB */
713 * gdk_keymap_translate_keyboard_state:
714 * @keymap: a #GdkKeymap, or %NULL to use the default
715 * @hardware_keycode: a keycode
716 * @state: a modifier state
717 * @group: active keyboard group
718 * @keyval: return location for keyval
719 * @effective_group: return location for effective group
720 * @level: return location for level
721 * @unused_modifiers: return location for modifiers that didn't affect the group or level
724 * Translates the contents of a #GdkEventKey into a keyval, effective
725 * group, and level. Modifiers that didn't affect the translation and
726 * are thus available for application use are returned in
727 * @unused_modifiers. See gdk_keyval_get_keys() for an explanation of
728 * groups and levels. The @effective_group is the group that was
729 * actually used for the translation; some keys such as Enter are not
730 * affected by the active keyboard group. The @level is derived from
731 * @state. For convenience, #GdkEventKey already contains the translated
732 * keyval, so this function isn't as useful as you might think.
734 * Return value: %TRUE if there was a keyval bound to the keycode/state/group
737 gdk_keymap_translate_keyboard_state (GdkKeymap *keymap,
738 guint hardware_keycode,
739 GdkModifierType state,
742 gint *effective_group,
744 GdkModifierType *unused_modifiers)
746 KeySym tmp_keyval = NoSymbol;
748 g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
749 g_return_val_if_fail (group < 4, FALSE);
754 *effective_group = 0;
757 if (unused_modifiers)
758 *unused_modifiers = state;
762 if (hardware_keycode < min_keycode ||
763 hardware_keycode > max_keycode)
769 XkbDescRec *xkb = get_xkb ();
771 /* replace bits 13 and 14 with the provided group */
772 state &= ~(1 << 13 | 1 << 14);
773 state |= group << 13;
775 MyEnhancedXkbTranslateKeyCode (xkb,
784 *keyval = tmp_keyval;
793 if ((state & GDK_SHIFT_MASK) &&
794 (state & GDK_LOCK_MASK))
795 shift_level = 0; /* shift disables shift lock */
796 else if ((state & GDK_SHIFT_MASK) ||
797 (state & GDK_LOCK_MASK))
802 tmp_keyval = XKeycodeToKeysym (gdk_display, hardware_keycode,
803 group * keysyms_per_keycode + shift_level);
806 *keyval = tmp_keyval;
808 if (unused_modifiers)
810 *unused_modifiers = state;
811 *unused_modifiers &= ~(GDK_SHIFT_MASK | GDK_LOCK_MASK | group_switch_mask);
815 *effective_group = (state & group_switch_mask) ? 1 : 0;
818 *level = shift_level;
821 return tmp_keyval != NoSymbol;
825 /* Key handling not part of the keymap */
828 gdk_keyval_name (guint keyval)
830 return XKeysymToString (keyval);
834 gdk_keyval_from_name (const gchar *keyval_name)
836 g_return_val_if_fail (keyval_name != NULL, 0);
838 return XStringToKeysym (keyval_name);
841 #ifdef HAVE_XCONVERTCASE
843 gdk_keyval_convert_case (guint symbol,
851 XConvertCase (symbol, &xlower, &xupper);
858 #endif /* HAVE_XCONVERTCASE */