[gnome-control-center] keyboard: Handle shift shortcut modifier the same way as the shell does



commit bad61a2229e2485ac37211ea5ebf1fa6b7ce2ca1
Author: Sebastian Keller <skeller gnome org>
Date:   Thu Dec 16 23:48:57 2021 +0100

    keyboard: Handle shift shortcut modifier the same way as the shell does
    
    The way shortcuts in mutter/gnome-shell work is that it looks up the
    keycode that generates the shortcut keyval at the lowest shift level and
    then checks if all the modifiers match. This does not work for shortcuts
    that for example include "dollar" to represent "<Shift>4", because on
    some keyboards/layout there is a separate dollar key key with its own
    keycode. This would be at a lower shift level than "<Shift>4".
    
    By always translating such shortcuts to "<Shift>number", we make sure
    the resulting shortcut will work in the shell and is closer to what the
    user likely intended the shortcut to be, because numbers are usually
    assigned to things that can be enumerated, such as workspaces or
    favorite applications.
    
    This also special cases the num-row key on layouts such as AZERTY, where
    the number is the shifted keyval, to always prefer the number. Due to
    the way the shell interprets these shortcuts, they still work and by
    always using numbers they work across different layouts.
    
    This change also fixes that pressing "<Shift><Super>4" was turned into
    "<Shift><Super>dollar", which effectively included the "<Shift>" twice.
    
    Fixes: https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/1528

 panels/keyboard/cc-keyboard-shortcut-editor.c |  2 +-
 panels/keyboard/keyboard-shortcuts.c          | 73 ++++++++++++++++++++-------
 2 files changed, 57 insertions(+), 18 deletions(-)
---
diff --git a/panels/keyboard/cc-keyboard-shortcut-editor.c b/panels/keyboard/cc-keyboard-shortcut-editor.c
index 95fa3aa65..66cf02460 100644
--- a/panels/keyboard/cc-keyboard-shortcut-editor.c
+++ b/panels/keyboard/cc-keyboard-shortcut-editor.c
@@ -687,7 +687,7 @@ on_key_pressed_cb (GtkEventControllerKey    *key_controller,
   if (!editing)
     return GDK_EVENT_PROPAGATE;
 
-  normalize_keyval_and_mask (keyval, state,
+  normalize_keyval_and_mask (keycode, state,
                              gtk_event_controller_key_get_group (key_controller),
                              &keyval_lower, &real_mask);
 
diff --git a/panels/keyboard/keyboard-shortcuts.c b/panels/keyboard/keyboard-shortcuts.c
index c40794d80..cfaa11ecb 100644
--- a/panels/keyboard/keyboard-shortcuts.c
+++ b/panels/keyboard/keyboard-shortcuts.c
@@ -377,35 +377,74 @@ convert_keysym_state_to_string (const CcKeyCombo *combo)
   return name;
 }
 
+/* This adjusts the keyval and modifiers such that it matches how
+ * gnome-shell detects shortcuts, which works as follows:
+ * First for the non-modifier key, the keycode that generates this
+ * keyval at the lowest shift level is determined, which might be a
+ * level > 0, such as for numbers in the num-row in AZERTY.
+ * Next it checks if all the specified modifiers were pressed.
+ */
 void
-normalize_keyval_and_mask (guint            keyval,
+normalize_keyval_and_mask (guint            keycode,
                            GdkModifierType  mask,
                            guint            group,
                            guint           *out_keyval,
                            GdkModifierType *out_mask)
 {
-  guint keyval_lower;
-  GdkModifierType real_mask;
-
-  real_mask = mask & gtk_accelerator_get_default_mod_mask ();
-
-  keyval_lower = gdk_keyval_to_lower (keyval);
+  guint unmodified_keyval;
+  guint shifted_keyval;
+  GdkModifierType explicit_modifiers;
+  GdkModifierType used_modifiers;
+
+  /* We want shift to always be included as explicit modifier for
+   * gnome-shell shortcuts. That's because users usually think of
+   * shortcuts as including the shift key rather than being defined
+   * for the shifted keyval.
+   * This helps with num-row keys which have different keyvals on
+   * different layouts for example, but also with keys that have
+   * explicit key codes at shift level 0, that gnome-shell would prefer
+   * over shifted ones, such the DOLLAR key.
+   */
+  explicit_modifiers = gtk_accelerator_get_default_mod_mask () | GDK_SHIFT_MASK;
+  used_modifiers = mask & explicit_modifiers;  
+
+  /* Find the base keyval of the pressed key without the explicit
+   * modifiers. */
+  gdk_display_translate_key (gdk_display_get_default (),
+                             keycode,
+                             mask & ~explicit_modifiers,
+                             group,
+                             &unmodified_keyval,
+                             NULL,
+                             NULL,
+                             NULL);
+
+  /* Normalize num-row keys to the number value. This allows these
+   * shortcuts to work when switching between AZERTY and layouts where
+   * the numbers are at shift level 0. */
+  gdk_display_translate_key (gdk_display_get_default (),
+                             keycode,
+                             GDK_SHIFT_MASK | (mask & ~explicit_modifiers),
+                             group,
+                             &shifted_keyval,
+                             NULL,
+                             NULL,
+                             NULL);
+
+  if (shifted_keyval >= GDK_KEY_0 && shifted_keyval <= GDK_KEY_9)
+    unmodified_keyval = shifted_keyval;
 
   /* Normalise <Tab> */
-  if (keyval_lower == GDK_KEY_ISO_Left_Tab)
-    keyval_lower = GDK_KEY_Tab;
-
-  /* Put shift back if it changed the case of the key, not otherwise. */
-  if (keyval_lower != keyval)
-    real_mask |= GDK_SHIFT_MASK;
+  if (unmodified_keyval == GDK_KEY_ISO_Left_Tab)
+    unmodified_keyval = GDK_KEY_Tab;
 
-  if (keyval_lower == GDK_KEY_Sys_Req && (real_mask & GDK_ALT_MASK) != 0)
+  if (unmodified_keyval == GDK_KEY_Sys_Req && (used_modifiers & GDK_ALT_MASK) != 0)
     {
       /* HACK: we don't want to use SysRq as a keybinding (but we do
        * want Alt+Print), so we avoid translation from Alt+Print to SysRq */
-      keyval_lower = GDK_KEY_Print;
+      unmodified_keyval = GDK_KEY_Print;
     }
 
-  *out_keyval = keyval_lower;
-  *out_mask = real_mask;
+  *out_keyval = unmodified_keyval;
+  *out_mask = used_modifiers;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]