After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 100439 - Consumed modifiers and multi-modifier combinations
Consumed modifiers and multi-modifier combinations
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Widget: Other
2.1.x
Other Linux
: Normal normal
: ---
Assigned To: gtk-bugs
gtk-bugs
: 108786 115507 118022 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2002-12-05 15:38 UTC by Richard Hult
Modified: 2011-02-04 16:12 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Unsetting GDK_CONTROL_MASK bit in "consumed_modifiers" (414 bytes, patch)
2003-05-14 14:58 UTC, Danilo Segan
none Details | Review

Description Richard Hult 2002-12-05 15:38:18 UTC
Pressing Ctrl-Backspace in entries used to delete the whole previous word.
This behaviour seems to have disappeared in 2.1.x.
Comment 1 Owen Taylor 2002-12-06 22:43:54 UTC
CVS XFree86, right?

The problem here is subtle... the problem is that with current
XFree86 Ctrl+Alt+Backspace now gives Terminate_Server not
Backspace, so "Ctrl" is a "consumed modifier", and 
thus Ctrl+Backspace and Backspace are considered the same.

Perhaps we can modify the definition of consumed modifier
in some fashion to handle 3-key combinations like this better.

Ugh.
Comment 2 Richard Hult 2002-12-06 22:54:45 UTC
Just to confirm, yes, this is with a recent CVS XFree86.
Comment 3 Owen Taylor 2002-12-09 21:20:04 UTC
Don't expect to have time to look at this for 2.2.0, though
it will probably get dup'ed alot after 4.3.0 comes out.
Comment 4 Owen Taylor 2003-03-21 14:18:44 UTC
*** Bug 108786 has been marked as a duplicate of this bug. ***
Comment 5 Danilo Segan 2003-04-15 15:09:47 UTC
Any chance this will get fixed in 2.3 series?
Comment 6 Owen Taylor 2003-04-15 15:36:38 UTC
Well, there is always a chance... especially if someone
interested in the problem wants to work on it.
Comment 7 Danilo Segan 2003-04-16 21:45:02 UTC
I'm interested!

Is there any documentation on Gdk behaviour on this issue, so it would
be easier to read the code? (I'm somewhat familiar with the XKB source
code, so I might be able to work something out, though I make no promises)

Thanks
Comment 8 Owen Taylor 2003-04-17 14:33:42 UTC
http://mail.gnome.org/archives/gtk-devel-list/2002-February/msg00224.html

May be a little helpful in understanding what GTK+ uses the
"consumed modifiers" return for.

As for the details of how it is implemented, I'm afraid no 
documentation other than the code.

The task is to:

 A) Consider what the right interpretation of "consumed modifiers"
    is, if it isn't simply "The union of all modifiers that
    effect the group/level of the key"

 B) Implement that interpretation in MyEnhancedXkbTranslateKeyCode()
    (a cut-and-paste of dXkbTranslateKeyCode()) and also in
    the non-Xkb code.
Comment 9 Danilo Segan 2003-05-14 14:57:41 UTC
Since XKB works with all this correctly in eg. xterm (if the
"preserve[Control]=Control" is set), the code in gdk/x11/* seemed to
be irrelevant.

While doing some experimenting, I noticed that this is related to
accelerator matching in gtk/gtkkeyhash.c. 

To resolve the problems mentioned in this bug and in DUPed bug
(http://bugzilla.gnome.org/show_bug.cgi?id=108786), it was enough to
unset the GDK_CONTROL_MASK bit in "consumed_modifiers" variable.

When XKB is set as in bug 108786, and on press of the <A> key with a
keyval of Cyrillic_a, consumed_modifiers has the CONTROL bit set, but
modifier CONTROL is not set (checked this using GTK_DEBUG=keybindings). 

I noticed that *only* when there is a menu bar with assigned shortcut
for "<control>a" does simple pressing of "a" key trigger the operation
behind "<control>a" (usually, "select all"). In other cases (I have
checked it with gtk-demo), it does not seem to happen.

It doesn't seem to break anything, but it's an ugly hack. I actually
have no idea what consequences it would have on all the other
applications, but since Control should be in "modifiers" (actually
event->state), then it seems to be fine not to care about it if it's
consumed.

Of course, this breaks the entire idea of "consumed_modifiers"
variable, because we might as well ignore it.

Everything else (like Ctrl+Alt+[Left|Right|Up|Down] for switching the
workspaces, Ctrl+Backspace for deleting a word, dynamicaly changing
shortcuts in menus,...) also seems to work.

Attached is the one-liner patch (apply in gtk/ directory against Gtk+
2.2.1) that modifies a function _gtk_key_hash_lookup. 

Any comments? What did I do wrong, and what did I break?
Comment 10 Danilo Segan 2003-05-14 14:58:05 UTC
Created attachment 16526 [details] [review]
Unsetting GDK_CONTROL_MASK bit in "consumed_modifiers"
Comment 11 Owen Taylor 2003-05-14 15:49:48 UTC
> Since XKB works with all this correctly in eg. xterm (if the
> "preserve[Control]=Control" is set), the code in gdk/x11/* seemed to
> be irrelevant.

GTK+ has a more sophisticated algorithm than old Xt based apps 
like xterm, the code in gdk/x11 is *precisely* relevant.

Your patch will break the Pause/Break key, where Contrl *is*
consumed. A keybinding to "Break" would no longer work and
would have to be specified as "Control+Break".

Plus it "fixes" only tiny portion of the problem; e.g. if your keymap 
had Alt+Shift instead of Control+Shift as the modifier, then
it would be the Alt key that would be the problem rather
than the control key.
Comment 12 Danilo Segan 2003-05-14 21:01:21 UTC
This is how PC_BREAK key type is defined in XFree86. It makes me
believe that "Control" is *not* consumed, because that's what
"preserve" is for (see below on me being confused).

    type "PC_BREAK" {
        modifiers = Control;
        map[None] = Level1;
        map[Control] = Level2;
        preserve[Control] = Control;
        level_name[Level1] = "Base";
        level_name[Level2] = "Control";
    };

There is either a bug in this definition (preserve should be removed)
or I completely misunderstand the "preserve" keyword: I thought it
should also set the GDK_CONTROL_MASK in "event->state" (real
modifiers) in XKB apps [actually in XKB code, and XKB_CONTROL..., but
it seems equivalent], thereby making it visible, instead of "consumed").

It was my belief that a key is practicaly "consumed" iff it is not set
in "modifiers", and it is set in "consumed_modifiers". If that was not
the case, what is the goal of "preserve" keyword?

I don't see *any* reason for actually parsing the "consumed modifiers"
except to work around some bugs.

Sorry for being so confused :-)
Comment 13 Owen Taylor 2003-05-14 21:23:56 UTC
XFree86-4.3.0 has:

    type "PC_BREAK" {
        modifiers = Control;
        map[None] = Level1;
        map[Control] = Level2;
        level_name[Level1] = "Base";
        level_name[Level2] = "Control";
    };
 
So I'm puzzled by the above. In any case, "preserve"
doesn't make any sense to me for this key. If it was
put into XFree86 CVS, that's a bug.

The consumed modifiers has no effect on event->state
to my knowledge.

The reason that GTK+ uses consumed modifiers is because,
say you want to make a keybinding to "<Alt>+"

On a US keyboard, you get a Plus as <shift>-, on a 
DE keyboard, you get it as +. 

So, the <shift> modifier must be ignored on the US 
keyboard. It is "consumed" in converting the - to a +.
Comment 14 Danilo Segan 2003-05-16 00:28:18 UTC
Uhm, that "preserve" seems to be error on my part (I have it in
/etc/X11/xkb/types/pc, but not in xc/programs/xkbcomp/types/pc which
is odd, but most probably my mistake). So, PC_BREAK is really
correctly defined in XFree86 4.3.0 (that's what I'm using). Sorry for
that.

And yes, now I see what you mean.

But I cannot track the code where the following happens:

Suppose we have a new XKB test map (types and symbols):
$ cat /etc/X11/xkb/types/test
# be sure to include it in "complete" while testing
partial default xkb_types "default" {

    type "TEST_ALPHABETIC" {
      modifiers = Control;
      map[None] = Level1;
      map[Control] = Level2;
      preserve[Control]=Control;
      level_name[Level1] = "Base";
      level_name[Level2] = "Control";
    };
};

$ cat /etc/X11/xkb/symbols/pc/test
partial alphanumeric_keys
xkb_symbols "base" {
  include "pc/en_US"

  key.type[Group1] = "TEST_ALPHABETIC";
  key <AC01> {   [ a,          A ]   };
  key <AB06> {   [ n,          N ]   };
};

$ setxkbmap test; export GTK_DEBUG=keybindings; gtk-demo

This is what pressing "n" in gtk-demo/Application main window gives me:
Gtk-Message: Looking up keycode = 57, modifiers = 0x0000,
    keyval = 110, group = 0, level = 0, consumed_modifiers = 0x6006
Gtk-Message:   found exact match, keyval = 110, modifiers = 0x0004
Gtk-Message: Looking up keycode = 57, modifiers = 0x0000,
    keyval = 110, group = 0, level = 0, consumed_modifiers = 0x6006
Gtk-Message:   found exact match, keyval = 110, modifiers = 0x0004
Gtk-Message: Looking up keycode = 57, modifiers = 0x0000,
    keyval = 110, group = 0, level = 0, consumed_modifiers = 0x6006
Gtk-Message:   found exact match, keyval = 110, modifiers = 0x0004

So, somewhere is GDK_CONTROL_MASK *forced* into the entry->modifiers,
even though I'd expect it not to be set. It might be hashing problem,
though I doubt it. This is a place where I'd expect "Control" not to
be set in real modifiers, unless it really is pressed, and not consumed.

With regards to the mentioned problem of alt++ being equivalent with
alt+shift+-, I don't see where's the issue.

For alt++ we have:
keyval: plus
mods: alt
consumed: none

For alt+shift+- we have:
keyval: plus
mods: alt+shift
consumed: shift

so, effective_mods=mods & ~consumed is enough.


But in my test we have:
keyval: n
mods: none
consumed: control

and this should give effective_mods=mods & ~consumed = none.


Control+Pause or Break is quite similar to alt++:
keyval: Break
mods: control
consumed: control

so we end up with the pure "Break".


Then, I got lost, and I was not able to track where this is actually
set (too many new structs and other data for me at the moment, I'll
give it another try tommorow).


I'll repeat that this seems to cause problems if and only if there's a
menubar in application (as far as I could see). Otherwise, an expected
"n" is output. Key code and state gotten from
gdk_keymap_translate_keyboard_state seems fine to me (except the Lock
modifier, but I think I ran across some Gtk+ code which handles it, so
I'm not alarmed).

Owen, thanks for all the help so far. I also hope not to annoy you too
much in the future, and will certainly try to be more careful from now
on. If I am wasting too much of your time you could be spending on
enhancing Gtk+ in other ways (or if I seem hopeless), please ignore
me, and I'll try to resolve this on my own -- more carefully then I
have done till now.
Comment 15 Owen Taylor 2003-05-22 14:50:22 UTC
Gtk-Message: Looking up keycode = 57, modifiers = 0x0000,
    keyval = 110, group = 0, level = 0, consumed_modifiers = 0x6006
Gtk-Message:   found exact match, keyval = 110, modifiers = 0x0004

The point is that the matching is done

 event->modifiers & ~consumed_modifiers == key->modifiers &
~consumed_modifiers

You seem to be proposing instead:

 event->modifiers & ~consumed_modifiers == key->modifiers

But:

 A) That isn't a compatible change ... people may have
    specified <Alt><Shift>+ currently (for one thing,
    you had to do that in GTK+-1.2)

 B) It still leaves you broken, because you won't be
    able to get to use the Control-N accelerator. Yes,
    that's less major breakage, but we should fix this
    right, not go for a half-fix.
Comment 16 Owen Taylor 2003-06-30 18:32:49 UTC
*** Bug 116370 has been marked as a duplicate of this bug. ***
Comment 17 Owen Taylor 2003-07-23 15:34:58 UTC
*** Bug 118022 has been marked as a duplicate of this bug. ***
Comment 18 Owen Taylor 2003-07-24 21:42:32 UTC
*** Bug 118233 has been marked as a duplicate of this bug. ***
Comment 19 Owen Taylor 2003-08-01 18:47:26 UTC
*** Bug 115507 has been marked as a duplicate of this bug. ***
Comment 20 Owen Taylor 2003-08-21 19:29:20 UTC
http://mail.gnome.org/archives/gtk-devel-list/2003-August/msg00173.html

has patch and detailed discussion.

Thu Aug 21 15:17:42 2003  Owen Taylor  <otaylor@redhat.com>
 
        * gdk/x11/gdkkeys-x11.c: Change the interpretation
        of consumed_modifiers so that it contains:
         - Modifiers combinations actually found in
           state.
         - Single modifier modifier combinations.
        But not multi-modifier combinations that aren't
        in event->state. Document. (#100439)