]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkkeys-x11.c
Fixes for non XKB operation. (#73103)
[~andy/gtk] / gdk / x11 / gdkkeys-x11.c
index db587736cf3f054afbee404fb53cef3eded14b72..f80b742abb59439e4a9d31315c43510f35bfea5e 100644 (file)
@@ -24,7 +24,6 @@
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
  */
 
-#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -68,7 +67,7 @@ get_xkb (void)
   
   if (xkb_desc == NULL)
     {
-      xkb_desc = XkbGetMap (gdk_display, XkbKeySymsMask, XkbUseCoreKbd);
+      xkb_desc = XkbGetMap (gdk_display, XkbKeySymsMask | XkbKeyTypesMask, XkbUseCoreKbd);
       if (xkb_desc == NULL)
         g_error ("Failed to get keymap");
 
@@ -76,7 +75,7 @@ get_xkb (void)
     }
   else if (current_serial != _gdk_keymap_serial)
     {
-      XkbGetUpdatedMap (gdk_display, XkbKeySymsMask, xkb_desc);
+      XkbGetUpdatedMap (gdk_display, XkbKeySymsMask | XkbKeyTypesMask, xkb_desc);
       XkbGetNames (gdk_display, XkbGroupNamesMask, xkb_desc);
     }
 
@@ -116,6 +115,11 @@ gdk_keymap_get_default (void)
   return default_keymap;
 }
 
+/* Find the index of the group/level pair within the keysyms for a key.
+ */
+#define KEYSYM_INDEX(group, level) \
+  (2 * ((group) % (keysyms_per_keycode / 2)) + (level))
+
 static void
 update_keymaps (void)
 {
@@ -130,7 +134,8 @@ update_keymaps (void)
     {
       gint i;
       gint map_size;
-
+      gint keycode;
+      
       current_serial = _gdk_keymap_serial;
 
       update_keyrange ();
@@ -145,6 +150,26 @@ update_keymaps (void)
                                     max_keycode - min_keycode,
                                     &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 = min_keycode;
+      while (keycode < max_keycode)
+        {
+          KeySym *syms = keymap + (keycode - min_keycode) * keysyms_per_keycode;
+         /* Check both groups */
+         for (i = 0 ; i < 2 ; i++)
+           {
+             if (syms[KEYSYM_INDEX (i, 0)] == GDK_Tab)
+               syms[KEYSYM_INDEX (i, 1)] = GDK_ISO_Left_Tab;
+           }
+          
+          ++keycode;
+        }
+
       mod_keymap = XGetModifierMapping (gdk_display);
 
 
@@ -610,10 +635,9 @@ gdk_keymap_lookup_key (GdkKeymap          *keymap,
   else
 #endif
     {
-      update_keymaps ();
-      
-      return XKeycodeToKeysym (gdk_display, key->keycode,
-                               key->group * keysyms_per_keycode + key->level);
+      const KeySym *map = get_keymap ();
+      const KeySym *syms = map + (key->keycode - min_keycode) * keysyms_per_keycode;
+      return syms [KEYSYM_INDEX (key->group, key->level)];
     }
 }
 
@@ -736,13 +760,13 @@ MyEnhancedXkbTranslateKeyCode(register XkbDescPtr     xkb,
  * @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
+ * @consumed_modifiers: return location for modifiers that were used to determine 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
+ * group, and level. Modifiers that affected the translation and
+ * are thus unavailable for application use are returned in
+ * @consumed_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
@@ -759,9 +783,10 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
                                      guint           *keyval,
                                      gint            *effective_group,
                                      gint            *level,
-                                     GdkModifierType *unused_modifiers)
+                                     GdkModifierType *consumed_modifiers)
 {
   KeySym tmp_keyval = NoSymbol;
+  guint tmp_modifiers;
 
   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
   g_return_val_if_fail (group < 4, FALSE);
@@ -772,8 +797,8 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
     *effective_group = 0;
   if (level)
     *level = 0;
-  if (unused_modifiers)
-    *unused_modifiers = state;
+  if (consumed_modifiers)
+    *consumed_modifiers = 0;
 
   update_keyrange ();
   
@@ -793,49 +818,92 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
       MyEnhancedXkbTranslateKeyCode (xkb,
                                      hardware_keycode,
                                      state,
-                                     unused_modifiers,
+                                     &tmp_modifiers,
                                      &tmp_keyval,
                                      effective_group,
                                      level);
 
-      if (keyval)
-        *keyval = tmp_keyval;
+      if (state & ~tmp_modifiers & LockMask)
+       tmp_keyval = gdk_keyval_to_upper (tmp_keyval);
+
+      /* We need to augment the consumed modifiers with LockMask, since
+       * we handle that ourselves, and also with the group bits
+       */
+      tmp_modifiers |= LockMask | 1 << 13 | 1 << 14;
     }
   else
 #endif
     {
+      const KeySym *map = get_keymap ();
+      const KeySym *syms;
       gint shift_level;
+      gboolean ignore_shift = FALSE;
+      gboolean ignore_group = FALSE;
       
-      update_keymaps ();
-
       if ((state & GDK_SHIFT_MASK) &&
           (state & GDK_LOCK_MASK))
-        shift_level = 0; /* shift disables shift lock */
+       shift_level = 0; /* shift disables shift lock */
       else if ((state & GDK_SHIFT_MASK) ||
                (state & GDK_LOCK_MASK))
-        shift_level = 1;
+       shift_level = 1;
       else
-        shift_level = 0;
+       shift_level = 0;
 
-      tmp_keyval = XKeycodeToKeysym (gdk_display, hardware_keycode,
-                                     group * keysyms_per_keycode + shift_level);
-      
-      if (keyval)
-        *keyval = tmp_keyval;
+      syms = map + (hardware_keycode - min_keycode) * keysyms_per_keycode;
+
+#define SYM(g,l) syms[KEYSYM_INDEX (g,l)]
+
+      /* Drop group and shift if there are no keysymbols on
+       * the specified key.
+       */
+      if (!SYM (group, shift_level) && SYM (group, 0))
+       {
+         shift_level = 0;
+         ignore_shift = TRUE;
+       }
+      if (!SYM (group, shift_level) && SYM (0, shift_level))
+       {
+         group = 0;
+         ignore_group = TRUE;
+       }
+      if (!SYM (group, shift_level) && SYM (0, 0))
+       {
+         shift_level = 0;
+         group = 0;
+         ignore_group = TRUE;
+         ignore_shift = TRUE;
+       }
+
+      /* See whether the group and shift level actually mattered
+       * to know what to put in consumed_modifiers
+       */
+      if (!SYM (group, 1) ||
+         SYM (group, 0) == SYM (group, 1))
+       ignore_shift = TRUE;
+
+      if (!SYM (1, shift_level) ||
+         SYM (0, shift_level) == SYM (1, shift_level))
+       ignore_group = TRUE;
+
+      tmp_keyval = SYM (group, shift_level);
+
+      tmp_modifiers = ignore_group ? 0 : group_switch_mask;
+      tmp_modifiers |= ignore_shift ? 0 : (GDK_SHIFT_MASK | GDK_LOCK_MASK);
 
-      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;
+        *effective_group = group;
 
       if (level)
         *level = shift_level;
+#undef SYM       
     }
 
+  if (consumed_modifiers)
+    *consumed_modifiers = tmp_modifiers;
+                               
+  if (keyval)
+    *keyval = tmp_keyval;
+
   return tmp_keyval != NoSymbol;
 }
 
@@ -845,6 +913,18 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
 gchar*
 gdk_keyval_name (guint       keyval)
 {
+  switch (keyval)
+    {
+    case GDK_Page_Up:
+      return "Page_Up";
+    case GDK_Page_Down:
+      return "Page_Down";
+    case GDK_KP_Page_Up:
+      return "KP_Page_Up";
+    case GDK_KP_Page_Down:
+      return "KP_Page_Down";
+    }
+  
   return XKeysymToString (keyval);
 }
 
@@ -865,6 +945,16 @@ gdk_keyval_convert_case (guint symbol,
   KeySym xlower = 0;
   KeySym xupper = 0;
 
+  /* Check for directly encoded 24-bit UCS characters: */
+  if ((symbol & 0xff000000) == 0x01000000)
+    {
+      if (lower)
+       *lower = gdk_unicode_to_keyval (g_unichar_tolower (symbol & 0x00ffffff));
+      if (upper)
+       *upper = gdk_unicode_to_keyval (g_unichar_toupper (symbol & 0x00ffffff));
+      return;
+    }
+  
   if (symbol)
     XConvertCase (symbol, &xlower, &xupper);
 
@@ -874,3 +964,19 @@ gdk_keyval_convert_case (guint symbol,
     *upper = xupper;
 }  
 #endif /* HAVE_XCONVERTCASE */
+
+gint
+_gdk_x11_get_group_for_state (GdkModifierType state)
+{
+#ifdef HAVE_XKB
+  if (_gdk_use_xkb)
+    {
+      return XkbGroupForCoreState (state);
+    }
+  else
+#endif
+    {
+      update_keymaps ();
+      return (state & group_switch_mask) ? 1 : 0;
+    }
+}