[gtk/wip/smcv/shifted-shortcuts: 52/52] gdkevents: Don't ignore modifiers that are not currently active




commit f4f6e11cee0dbd4892e8877fb00d410146c525f8
Author: Simon McVittie <smcv debian org>
Date:   Sat Sep 17 18:53:00 2022 +0100

    gdkevents: Don't ignore modifiers that are not currently active
    
    The X11 backend can mark modifiers like Shift as consumed even if they
    aren't actually active, as a way to make shortcuts like
    `<Control><Shift>plus` work as intended on keyboards where the plus
    symbol is obtained by pressing Shift and the plus/equals key. This has
    the desired effect of making both `<Control>plus` and
    `<Control><Shift>plus` work as intended on those keyboards. (The Wayland
    and Windows backends do not do this, so only `<Control>plus` can be
    used with Wayland or Windows.)
    
    However, this can go badly wrong when the modifier is *not* pressed.
    For example, terminals normally have separate bindings for `<Control>c`
    (send SIGINT) and `<Control><Shift>c` (copy). If we disregard the
    consumed modifiers completely, when the X11 backend marks Shift as
    consumed, pressing Ctrl+c would send SIGINT *and* copy to the clipboard,
    which is not what was intended.
    
    By masking out the members of `consumed` that are not in `state`, we
    get the same interpretation for X11 and Wayland, and ensure that
    keyboard shortcuts that explicitly mention Shift can only be triggered
    while holding Shift. It continues to be possible to trigger keyboard
    shortcuts that do not explicitly mention Shift (such as `<Control>plus`)
    while holding Shift, if the backend reports Shift as having been
    consumed in order to generate the plus keysym.
    
    Resolves: https://gitlab.gnome.org/GNOME/gtk/-/issues/5095
    Signed-off-by: Simon McVittie <smcv debian org>

 gdk/gdkevents.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)
---
diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c
index 4b61715575..0daf475c3f 100644
--- a/gdk/gdkevents.c
+++ b/gdk/gdkevents.c
@@ -1773,7 +1773,7 @@ gdk_key_event_matches (GdkEvent        *event,
   guint ev_keyval;
   int layout;
   int level;
-  GdkModifierType consumed_modifiers;
+  GdkModifierType ignored_modifiers;
   GdkModifierType shift_group_mask;
   gboolean group_mod_is_accel_mod = FALSE;
   const GdkModifierType mask = GDK_CONTROL_MASK |
@@ -1792,7 +1792,23 @@ gdk_key_event_matches (GdkEvent        *event,
   ev_keyval = self->translated[1].keyval;
   layout = self->translated[1].layout;
   level = self->translated[1].level;
-  consumed_modifiers = self->translated[1].consumed;
+
+  /*
+   * If a modifier is currently active (e.g. Shift is pressed) and was marked
+   * as consumed, we ignore it for the purposes of matching shortcuts.
+   * For example, when Ctrl+Shift+[plus/equals key] is translated into
+   * Ctrl+plus on a keyboard where Shift+equals is the plus sign, we want
+   * shortcuts for either <Control><Shift>plus or <Control>plus to match.
+   * (See https://bugzilla.gnome.org/show_bug.cgi?id=100439)
+   *
+   * If a modifier is *not* currently active, the X11 backend can sometimes
+   * mark it as consumed where the Wayland and Windows backends do not.
+   * In this case, we still want to pay attention to its state.
+   * For example, when Ctrl+x is translated into Ctrl+x, we only want to
+   * trigger shortcuts for <Control>x, not for <Control><Shift>x.
+   * (See https://gitlab.gnome.org/GNOME/gtk/-/issues/5095)
+   */
+  ignored_modifiers = (self->translated[1].consumed & state);
 
   /* if the group-toggling modifier is part of the default accel mod
    * mask, and it is active, disable it for matching
@@ -1804,7 +1820,7 @@ gdk_key_event_matches (GdkEvent        *event,
   if (mask & shift_group_mask)
     group_mod_is_accel_mod = TRUE;
 
-  if ((modifiers & ~consumed_modifiers & mask) == (state & ~consumed_modifiers & mask))
+  if ((modifiers & ~ignored_modifiers & mask) == (state & ~ignored_modifiers & mask))
     {
       /* modifier match */
       GdkKeymapKey *keys;


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