I'd better answer my own question for future reference.
After a bit of in-depth research, I found out that xmodmap
is actually deprecated and is roughly patched over the xkb
keyboard model. The xkb
model doesn't use a linear array of alternatives, but splits layouts into groups
, with each group having a couple of characters in different shift levels. The xmodmap
definitions fill the entries in a very funny order: group 1, level 1,2, group 2, level 1,2, group 1, levels 3.... The groups are meant to be like "layouts" and aren't usually accessed with modifiers but with toggling. The exception is the Mode_switch
character that I used, but it only accesses group 2.
That would all be fine, except keys have types. Every key is defined by the layout to be TWO_LEVEL
, FOUR_LEVEL
, FOUR_LEVEL_ALPHANUMERIC
and so on, and each level can have different notion of which modifiers map to which levels. The behaviour I assumed (8 levels, all combinations) was actually LOCAL_EIGHT_LEVEL
that wasn't used at all by the layout. So in the case of keycode 51
, the default was actually TWO_LEVEL
, and xmodmap
filled 3 groups with the 6 keys instead of adding 6 levels to 1st group. The 3rd group wasn't reached by the Mode_switch
modifier. Using another key resulted in different behaviour because pre-defined type was different.
As with the repetitions in the printout by xmodmap
, I'm not sure exactly what happens (I printed the xkb
definitions and all was fine), but I'm not surprised that errors occur when you map from a variable-length multidimensional array to a single list of symcodes. The output doesn't reflect the actual state anyway.
In conclusion, xmodmap is evil. Don't ever use it. Its behaviour is erratic and ill-defined at best. It doesn't do what it says it does. Make your own xkb
maps. Reuse most of the layout by include
-ing and add modifications that you need.
In my case, the solution is to derive the second group from greek layout and substitute math symbols in strategic places, plus some modification in the first group.
Most cheap keyboards are very limited when it comes to pressing 3 keys at a time. That resulted in erratic and hardware-dependent failures for some keys. I'll experiment around with different modifier keys (the most useless key in the world - the menu key, or similarly useless right win-key), and possibly buy a better keyboard. Combination of both problems (broken-by-design hardware + evil deceptive software) created a confusing random-looking situation that at first prevented me to see them as separate problems.
Reading material:
As always, figured this one out moments after posting the question. The problem was simply that I was using Hyper_L
which by default is assigned to Mod4
. By changing Caps Lock to Hyper_R
instead, it worked. It still had to be bound to Mod3
though as a real modifier is still needed.
Here's the updated config which now produces the desired behaviour:
partial
xkb_types "hyper" {
virtual_modifiers Alt,Hyper;
type "HYPER" {
modifiers= Shift+Control+Alt+Hyper;
map[Shift]= Level2;
preserve[Shift]= Shift;
map[Control]= Level2;
preserve[Control]= Control;
map[Shift+Control]= Level2;
preserve[Shift+Control]= Shift+Control;
map[Alt]= Level2;
preserve[Alt]= Alt;
map[Shift+Alt]= Level2;
preserve[Shift+Alt]= Shift+Alt;
map[Control+Alt]= Level3;
preserve[Control+Alt]= Control+Alt;
map[Shift+Control+Alt]= Level2;
preserve[Shift+Control+Alt]= Shift+Alt;
map[Hyper]= Level2;
level_name[Level1]= "Extra";
level_name[Level2]= "Normal";
level_name[Level3]= "Ctrl+Alt";
};
};
partial function_keys
xkb_symbols "hyper_f21" {
replace key <FK01> {
type= "HYPER",
symbols[Group1]= [ F21, F1, XF86Switch_VT_1 ]
};
replace key <FK02> {
type= "HYPER",
symbols[Group1]= [ F22, F2, XF86Switch_VT_2 ]
};
...
};
partial modifier_keys
xkb_symbols "caps_hyper" {
replace key <CAPS> {
[ Hyper_R ]
};
# Remove Hyper (Hyper_L/Hyper_R) from Mod4, was added by "pc" layout
modifier_map none { <HYPR> };
# Now make physical caps lock (mapped to Hyper_R above) control Mod3. Mod3 is
# associated with the virtual modifier "Hyper" because the existing XKB config
# links Hyper_L and Hyper_R with this virtual modifier. Therefore Mod3 becomes
# the virtual modifier "Hyper" because they both share the same keysym Hyper_R.
modifier_map Mod3 { <CAPS> };
};
Again, this does:
- F1 ->
F21
- Caps + F1 ->
F1
- Shift + F1 ->
Shift + F1
(unchanged)
- Alt + F1 ->
Alt + F1
(unchanged)
- etc. - all others unchanged
Best Answer
Sorry, this is ancient, but perhaps even if it's too late for you, someone else may find this hint useful:
In your
types
, add:Then, in the
symbols
file, have something likeA program monitoring the keystrokes (
xev
oremacs
, for example) will see the keypresses as though you pressed F21, Shift+F21, F1, and Shift+F1.