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




commit 96fe0bc1cde5d6d8e179162b69057d6948033226
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, which seems to be something to do with making
    shortcuts like `<Control><Shift>plus` and `<Control>plus` work as
    intended regardless of whether the plus symbol is obtained by pressing
    Shift and a key (like `+/=` on American, British or French keyboards)
    or not (like `*/+` on German keyboards).
    
    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]