📄 gdkkeys-x11.c
字号:
/* 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 <config.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <limits.h>#include <errno.h>#include "gdk.h"#include "gdkx.h"#include "gdkprivate-x11.h"#include "gdkinternals.h"#include "gdkdisplay-x11.h"#include "gdkkeysyms.h"#include "gdkalias.h"#ifdef HAVE_XKB#include <X11/XKBlib.h>/* OSF-4.0 is apparently missing this macro */# ifndef XkbKeySymEntry# define XkbKeySymEntry(d,k,sl,g) \ (XkbKeySym(d,k,((XkbKeyGroupsWidth(d,k)*(g))+(sl))))# endif#endif /* HAVE_XKB */typedef struct _GdkKeymapX11 GdkKeymapX11;#define GDK_TYPE_KEYMAP_X11 (gdk_keymap_x11_get_type ())#define GDK_KEYMAP_X11(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_KEYMAP_X11, GdkKeymapX11))#define GDK_IS_KEYMAP_X11(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_KEYMAP_X11))typedef struct _DirectionCacheEntry DirectionCacheEntry;struct _DirectionCacheEntry{ guint serial; Atom group_atom; PangoDirection direction;};struct _GdkKeymapX11{ GdkKeymap parent_instance; gint min_keycode; gint max_keycode; KeySym* keymap; gint keysyms_per_keycode; XModifierKeymap* mod_keymap; guint lock_keysym; GdkModifierType group_switch_mask; GdkModifierType num_lock_mask; gboolean sun_keypad; PangoDirection current_direction; gboolean have_direction; guint current_serial;#ifdef HAVE_XKB XkbDescPtr xkb_desc; /* We cache the directions */ Atom current_group_atom; guint current_cache_serial; /* A cache of size four should be more than enough, people usually * have two groups around, and the xkb limit is four. It still * works correct for more than four groups. It's just the * cache. */ DirectionCacheEntry group_direction_cache[4];#endif};#define KEYMAP_USE_XKB(keymap) GDK_DISPLAY_X11 ((keymap)->display)->use_xkb#define KEYMAP_XDISPLAY(keymap) GDK_DISPLAY_XDISPLAY ((keymap)->display)static GType gdk_keymap_x11_get_type (void);static void gdk_keymap_x11_init (GdkKeymapX11 *keymap);static GTypegdk_keymap_x11_get_type (void){ static GType object_type = 0; if (!object_type) { static const GTypeInfo object_info = { sizeof (GdkKeymapClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) NULL, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GdkKeymapX11), 0, /* n_preallocs */ (GInstanceInitFunc) gdk_keymap_x11_init, }; object_type = g_type_register_static (GDK_TYPE_KEYMAP, "GdkKeymapX11", &object_info, 0); } return object_type;}static voidgdk_keymap_x11_init (GdkKeymapX11 *keymap){ keymap->min_keycode = 0; keymap->max_keycode = 0; keymap->keymap = NULL; keymap->keysyms_per_keycode = 0; keymap->mod_keymap = NULL; keymap->num_lock_mask = 0; keymap->sun_keypad = FALSE; keymap->group_switch_mask = 0; keymap->lock_keysym = GDK_Caps_Lock; keymap->have_direction = FALSE; keymap->current_serial = 0;#ifdef HAVE_XKB keymap->xkb_desc = NULL; keymap->current_group_atom = 0; keymap->current_cache_serial = 0;#endif}static inline voidupdate_keyrange (GdkKeymapX11 *keymap_x11){ if (keymap_x11->max_keycode == 0) XDisplayKeycodes (KEYMAP_XDISPLAY (GDK_KEYMAP (keymap_x11)), &keymap_x11->min_keycode, &keymap_x11->max_keycode);}#ifdef HAVE_XKBstatic XkbDescPtrget_xkb (GdkKeymapX11 *keymap_x11){ GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_KEYMAP (keymap_x11)->display); Display *xdisplay = display_x11->xdisplay; update_keyrange (keymap_x11); if (keymap_x11->xkb_desc == NULL) { keymap_x11->xkb_desc = XkbGetMap (xdisplay, XkbKeySymsMask | XkbKeyTypesMask, XkbUseCoreKbd); if (keymap_x11->xkb_desc == NULL) g_error ("Failed to get keymap"); XkbGetNames (xdisplay, XkbGroupNamesMask, keymap_x11->xkb_desc); } else if (keymap_x11->current_serial != display_x11->keymap_serial) { XkbGetUpdatedMap (xdisplay, XkbKeySymsMask | XkbKeyTypesMask, keymap_x11->xkb_desc); XkbGetNames (xdisplay, XkbGroupNamesMask, keymap_x11->xkb_desc); } keymap_x11->current_serial = display_x11->keymap_serial; return keymap_x11->xkb_desc;}#endif /* HAVE_XKB *//* Whether we were able to turn on detectable-autorepeat using * XkbSetDetectableAutorepeat. If FALSE, we'll fall back * to checking the next event with XPending(). *//** * gdk_keymap_get_for_display: * @display: the #GdkDisplay. * @returns: the #GdkKeymap attached to @display. * * Returns the #GdkKeymap attached to @display. * * Since: 2.2 **/GdkKeymap*gdk_keymap_get_for_display (GdkDisplay *display){ GdkDisplayX11 *display_x11; g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); display_x11 = GDK_DISPLAY_X11 (display); if (!display_x11->keymap) display_x11->keymap = g_object_new (gdk_keymap_x11_get_type (), NULL); display_x11->keymap->display = display; return display_x11->keymap;}/* Find the index of the group/level pair within the keysyms for a key. * We round up the number of keysyms per keycode to the next even number, * otherwise we lose a whole group of keys */#define KEYSYM_INDEX(keymap_impl, group, level) \ (2 * ((group) % (gint)((keymap_impl->keysyms_per_keycode + 1) / 2)) + (level))#define KEYSYM_IS_KEYPAD(s) (((s) >= 0xff80 && (s) <= 0xffbd) || \ ((s) >= 0x11000000 && (s) <= 0x1100ffff))static gintget_symbol (const KeySym *syms, GdkKeymapX11 *keymap_x11, gint group, gint level){ gint index; index = KEYSYM_INDEX(keymap_x11, group, level); if (index > keymap_x11->keysyms_per_keycode) return NoSymbol; return syms[index];}static voidupdate_keymaps (GdkKeymapX11 *keymap_x11){ GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_KEYMAP (keymap_x11)->display); Display *xdisplay = display_x11->xdisplay; #ifdef HAVE_XKB g_assert (!KEYMAP_USE_XKB (GDK_KEYMAP (keymap_x11)));#endif if (keymap_x11->keymap == NULL || keymap_x11->current_serial != display_x11->keymap_serial) { gint i; gint map_size; gint keycode; keymap_x11->current_serial = display_x11->keymap_serial; update_keyrange (keymap_x11); if (keymap_x11->keymap) XFree (keymap_x11->keymap); if (keymap_x11->mod_keymap) XFreeModifiermap (keymap_x11->mod_keymap); keymap_x11->keymap = XGetKeyboardMapping (xdisplay, keymap_x11->min_keycode, keymap_x11->max_keycode - keymap_x11->min_keycode + 1, &keymap_x11->keysyms_per_keycode); /* GDK_ISO_Left_Tab, as usually configured through XKB, really messes * up the whole idea of "consumed modifiers" because shift is consumed. * However, <shift>Tab is not usually GDK_ISO_Left_Tab without XKB, * we we fudge the map here. */ keycode = keymap_x11->min_keycode; while (keycode <= keymap_x11->max_keycode) { KeySym *syms = keymap_x11->keymap + (keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode; /* Check both groups */ for (i = 0 ; i < 2 ; i++) { if (get_symbol (syms, keymap_x11, i, 0) == GDK_Tab) syms[KEYSYM_INDEX (keymap_x11, i, 1)] = GDK_ISO_Left_Tab; } /* * If there is one keysym and the key symbol has upper and lower * case variants fudge the keymap */ if (get_symbol (syms, keymap_x11, 0, 1) == 0) { guint lower; guint upper; gdk_keyval_convert_case (get_symbol (syms, keymap_x11, 0, 0), &lower, &upper); if (lower != upper) { syms[KEYSYM_INDEX (keymap_x11, 0, 0)] = lower; syms[KEYSYM_INDEX (keymap_x11, 0, 1)] = upper; } } ++keycode; } keymap_x11->mod_keymap = XGetModifierMapping (xdisplay); keymap_x11->lock_keysym = GDK_VoidSymbol; keymap_x11->group_switch_mask = 0; keymap_x11->num_lock_mask = 0; /* There are 8 sets of modifiers, with each set containing * max_keypermod keycodes. */ map_size = 8 * keymap_x11->mod_keymap->max_keypermod; for (i = 0; i < map_size; i++) { /* Get the key code at this point in the map. */ gint keycode = keymap_x11->mod_keymap->modifiermap[i]; gint j; KeySym *syms; guint mask; /* Ignore invalid keycodes. */ if (keycode < keymap_x11->min_keycode || keycode > keymap_x11->max_keycode) continue; syms = keymap_x11->keymap + (keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode; /* The fourth modifier, GDK_MOD1_MASK is 1 << 3. * Each group of max_keypermod entries refers to the same modifier. */ mask = 1 << (i / keymap_x11->mod_keymap->max_keypermod); switch (mask) { case GDK_LOCK_MASK: /* Get the Lock keysym. If any keysym bound to the Lock modifier * is Caps_Lock, we will interpret the modifier as Caps_Lock; * otherwise, if any is bound to Shift_Lock, we will interpret * the modifier as Shift_Lock. Otherwise, the lock modifier * has no effect. */ for (j = 0; j < keymap_x11->keysyms_per_keycode; j++) { if (syms[j] == GDK_Caps_Lock) keymap_x11->lock_keysym = GDK_Caps_Lock; else if (syms[j] == GDK_Shift_Lock && keymap_x11->lock_keysym == GDK_VoidSymbol) keymap_x11->lock_keysym = GDK_Shift_Lock; } break; case GDK_CONTROL_MASK: case GDK_SHIFT_MASK: case GDK_MOD1_MASK: /* Some keyboard maps are known to map Mode_Switch as an * extra Mod1 key. In circumstances like that, it won't be * used to switch groups. */ break; default: /* Find the Mode_Switch and Num_Lock modifiers. */ for (j = 0; j < keymap_x11->keysyms_per_keycode; j++) { if (syms[j] == GDK_Mode_switch) { /* This modifier swaps groups */ keymap_x11->group_switch_mask |= mask; } else if (syms[j] == GDK_Num_Lock) { /* This modifier is used for Num_Lock */ keymap_x11->num_lock_mask |= mask; } } break; } } /* Hack: The Sun X server puts the keysym to use when the Num Lock * modifier is on in the third element of the keysym array, instead * of the second. */ if ((strcmp (ServerVendor (xdisplay), "Sun Microsystems, Inc.") == 0) && (keymap_x11->keysyms_per_keycode > 2)) keymap_x11->sun_keypad = TRUE; else keymap_x11->sun_keypad = FALSE; }}static const KeySym*get_keymap (GdkKeymapX11 *keymap_x11){ update_keymaps (keymap_x11); return keymap_x11->keymap;}#define GET_EFFECTIVE_KEYMAP(keymap) get_effective_keymap ((keymap), G_STRFUNC)static GdkKeymap *get_effective_keymap (GdkKeymap *keymap, const char *function){ if (!keymap) { GDK_NOTE (MULTIHEAD, g_message ("reverting to default display keymap in %s", function)); return gdk_keymap_get_default (); } return keymap;}#if HAVE_XKBstatic PangoDirectionget_direction (XkbDescRec *xkb, gint group){ gint code; gint rtl_minus_ltr = 0; /* total number of RTL keysyms minus LTR ones */ for (code = xkb->min_key_code; code <= xkb->max_key_code; code++) { gint width = XkbKeyGroupWidth (xkb, code, group); gint level; for (level = 0; level < width; level++) { KeySym sym = XkbKeySymEntry (xkb, code, level, group); PangoDirection dir = pango_unichar_direction (gdk_keyval_to_unicode (sym)); switch (dir) { case PANGO_DIRECTION_RTL: rtl_minus_ltr++; break; case PANGO_DIRECTION_LTR: rtl_minus_ltr--; break; default: break; } } } if (rtl_minus_ltr > 0) return PANGO_DIRECTION_RTL; else return PANGO_DIRECTION_LTR;}static voidupdate_direction (GdkKeymapX11 *keymap_x11){ XkbDescRec *xkb = get_xkb (keymap_x11); XkbStateRec state_rec; GdkDisplay *display = GDK_KEYMAP (keymap_x11)->display; gint group; Atom group_atom; XkbGetState (GDK_DISPLAY_XDISPLAY (display), XkbUseCoreKbd, &state_rec); group = XkbGroupLock (&state_rec);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -