GNOME Bugzilla – Bug 100439
Consumed modifiers and multi-modifier combinations
Last modified: 2011-02-04 16:12:02 UTC
Pressing Ctrl-Backspace in entries used to delete the whole previous word. This behaviour seems to have disappeared in 2.1.x.
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.
Just to confirm, yes, this is with a recent CVS XFree86.
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.
*** Bug 108786 has been marked as a duplicate of this bug. ***
Any chance this will get fixed in 2.3 series?
Well, there is always a chance... especially if someone interested in the problem wants to work on it.
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
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.
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?
Created attachment 16526 [details] [review] Unsetting GDK_CONTROL_MASK bit in "consumed_modifiers"
> 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.
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 :-)
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 +.
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.
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.
*** Bug 116370 has been marked as a duplicate of this bug. ***
*** Bug 118022 has been marked as a duplicate of this bug. ***
*** Bug 118233 has been marked as a duplicate of this bug. ***
*** Bug 115507 has been marked as a duplicate of this bug. ***
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)