Setting Hyper and Super modifiers for certain keys with setxkbmap or xmodmap

Problem: I want to modify/redefine my keyboard layout (pc105 se) so that when I press certain keys with mod3 (super) and mod4 (hyper), a different character is returned than usual.

E.g.

Keycode 61 produces 'minus' (-) when pressed normally and 'underscore' (_) when pressed with shift. When pressed with the first modifier group (AltGr) 'dead_belowdot' and 'dead_abovedot' is produced (without/with shift).

What I want is a left paranthesis or right paranthesis (without/with shift) when I press the key with the Super (win) key also pressed, and slash/backslash for the Hyper key (which I have configured to Caps Lock).

I have tried to add a .Xmodmap to my home directory and run it with xmodmap ~/.Xmodmap using the following syntax

keycode 61 = minus underscore a b c d e f g h i j k l m n o p

However, that will cause AltGr to result in c/d, while win/caps lock still only results in -/_

I have also tried modifying /usr/share/X11/xkb/symbols/se directly and tried the following changes:

key <BKSL>  { [apostrophe, asterisk, acute, multiply], [a,b,c,d], [e,f,g,h], [i,j,k,l]};

But all that happens is ' * ´ × ' * ' * (for normal, altgr, win and caps lock respectively). I have also tried

key <BKSL>  { [apostrophe, asterisk, acute, multiply, a,b,c,d, e,f,g,h, i,j,k,l]};

But as soon as there are more than four specified fields, it seems to break the key totaly, and the key reverts to default pc105 (us?) behaviour.

As I have failed to find anything on stackoverflow, superuser or google on how to deal with my scenario, I ask here.

This is my xmodmap -pm

xmodmap:  up to 3 keys per modifier, (keycodes in parentheses):

shift       Shift_L (0x32),  Shift_R (0x3e)
lock      
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_L (0x40),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3        Hyper_L (0x42),  Hyper_L (0xcf)
mod4        Super_L (0x85),  Super_R (0x86),  Super_L (0xce)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

Two years later, I am finally proud to answer my own question.

I have found the easiest, most reliable and most extendable method is to solely rely on xmodmap.

1. Get keycodes of special keys

Run xev to determine the key code of keys you wish to use as mode switchers. Then press the keys you are interested in and note down the keycode

$ xev
KeyRelease event, serial 40, synthetic NO, window 0x2600001,
    root 0x2a6, subw 0x0, time 1221887800, (885,743), root:(3447,805),
    state 0x2010, keycode 66 (keysym 0xff7e, Mode_switch), same_screen YES,
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False

The keycode is on the third line, keycode 66.

For me, these were the keys I was particularly interested in, and their corresponding key codes for me:

  • Caps Lock, keycode 66
  • Pause|Break, keycode 128
  • Left Windows key, keycode 133
  • Num Lock, key code 77

2. Set switcher keys

This is the setup I have opted for, but you can choose your own setup. I have saved this to a file $HOME/.xmodmap.

~/.xmodmap
keycode  66 = Mode_switch
keycode 127 = Multi_key
keycode 133 = Super_L
...

This way I have bound Caps Lock to Mode_switch, Pause Break to Compose and the left Win key to Super_L. The Compose key is particularly useful as it allows two keys to be combined to ligature. E.g. Compose followed by T and M results in the trademark sign .

3. Get current keymap bindings of xmodmap

In order to not destroy my keyboard layout, I wanted to keep my keys as close to my original layout as possible. In order to do that I printed the current keymap and looked for the keycodes I wanted to change.

$ xmodmap -pke | ag 'keycode  51' 

Off course, you could just as easily use grep or ack, depending on the tool you prefer to use.

$ xmodmap -pke | grep 'keycode  41' 
$ xmodmap -pke | ack 'keycode  31' 

The output of this is in the same format as the one you specify in your ~/.xmodmap like this:

keycode  31 = i I i I rightarrow idotless rightarrow idotless i I rightarrow idotless i I rightarrow idotless

4. Backup your existing xmodmap

Just in case something goes wrong, it's never a bad Idea to have your current xmodmap available to fall back to easily.

$ xmodmap -pke > ~/.xmodmap.bak

5. Add characters to 2nd, 3rd, 4th level of your keys

As far as I have understood, the format of the .xmodmap file is like this:

keycode <keycode> = <1st level> <Shift+1st> <2nd level> <shift+2nd> <3rd level> <shift+3rd level> <4th level> <shift+4th> ...

Now, I don't understand all those levels but Mode_Switch (Caps Lock in my case) will give you level 2 and Alt Gr gives me level 3, and that is pretty much all I am interested in so I left the rest of that line as it was in my ~/.xmodmap.bak and just changed the 3rd, 4th, 5th and 6th columns (level 2 and 3, plus shift) to valid characters (See here for a list of valid characters).

~/.xmodmap
...
keycode  51 = apostrophe asterisk dollar ampersand acute multiply acute multiply apostrophe asterisk acute multiply apostrophe asterisk acute multiply
keycode  59 = comma semicolon parenleft parenright dead_cedilla dead_ogonek dead_cedilla dead_ogonek comma semicolon dead_cedilla dead_ogonek comma semicolon dead_cedilla dead_ogonek
keycode  60 = period colon bracketleft bracketright periodcentered dead_abovedot periodcentered dead_abovedot period colon periodcentered dead_abovedot period colon periodcentered dead_abovedot
keycode  61 = minus underscore braceleft braceright slash backslash braceleft braceright
keycode  65 = space space space space space underscore space space
...

6. Test your .xmodmap

Now let xmodmap execute your .xmodmap and test your brand new keyboard layout.

$ xmodmap /home/user/.xmodmap

7. Make sure your keyboard layout is loaded on x init

I added this to my $HOME/.xinitrc:

~/.xinitrc
...
[-f $HOME/.xmodmap] && xmodmap $HOME/.xmodmap
...

I hope this was helpful!