It's possible but a bit hacky. No specific keysyms are already defined. ISO_Level3_{Shift,Latch,Lock} (and the same three for level5) are defined in X11 and libxkbcommon headers at compile time.
At runtime, they are activated in the compatibility module via interpret stanzas and actions; for example, examine your current keymap:
$ xkbcomp $DISPLAY - | less //.... xkb_compatibility "complete+ledcaps(shift_lock)" { //.... interpret ISO_Level3_Shift+AnyOf(all) { virtualModifier= LevelThree; useModMapMods=level1; action= SetMods(modifiers=LevelThree,clearLocks); }; interpret ISO_Level3_Latch+AnyOf(all) { virtualModifier= LevelThree; useModMapMods=level1; action= LatchMods(modifiers=LevelThree,clearLocks,latchToLock); }; interpret ISO_Level3_Lock+AnyOf(all) { virtualModifier= LevelThree; useModMapMods=level1; action= LockMods(modifiers=LevelThree); }; //.... interpret ISO_Level3_Shift+AnyOfOrNone(all) { action= SetMods(modifiers=LevelThree,clearLocks); }; interpret ISO_Level3_Latch+AnyOfOrNone(all) { action= LatchMods(modifiers=LevelThree,clearLocks,latchToLock); }; interpret ISO_Level3_Lock+AnyOfOrNone(all) { action= LockMods(modifiers=LevelThree); }; //....
There is an existing ISO_Level2_Latch keysym. It does not have existing compatibility interpret stanzas like the above, but if you add them it operates as you'd expect. (Shift is already there so ISO_Level2_Shift is unnecessary; Shift_Lock or Caps_Lock takes the place of ISO_Level2_Lock.) So if you wanted a Shift_Latch key, use the ISO_Level2_Latch keysym and add these to your keymap:
interpret ISO_Level2_Latch+AnyOf(all) { useModMapMods=level1; action= LatchMods(modifiers=Shift,clearLocks,latchToLock); }; interpret ISO_Level2_Latch+AnyOfOrNone(all) { action= LatchMods(modifiers=Shift,clearLocks,latchToLock); };
We can use this sort of approach for levels 4, 6, 7 and 8, but there are no predefined keysyms for ISO_Level4_Shift et al. You could add them to the code and recompile, or you could repurpose some unused keysym and interpret it as if it were a level4 shift (or latch, or lock). Examining header files in libxkbcommon we find all the keysym names XKB knows about; these look like they might suit our purposes:
//....in xkbcommon/xkbcommon-keysyms.h: //.... #define XKB_KEY_ISO_Fast_Cursor_Left 0xfe2c #define XKB_KEY_ISO_Fast_Cursor_Right 0xfe2d #define XKB_KEY_ISO_Fast_Cursor_Up 0xfe2e #define XKB_KEY_ISO_Fast_Cursor_Down 0xfe2f
Remove the XKB_KEY_ prefix to get keysym names we can reference in XKB rules. Let's use ISO_Fast_Cursor_Left to fake ISO_Level4_Latch.
First, generate a basic keymap, with setxkbmap -print; then we'll edit this file and add overrides to it, and finally load the altered keymap with xkbcomp [file] $DISPLAY:
$ setxkbmap -print > mykeymap.xkb xkb_keymap { xkb_keycodes { include "evdev+aliases(qwerty)" }; xkb_types { include "complete" }; xkb_compat { include "complete" }; xkb_symbols { include "pc+us(altgr-intl)+inet(evdev)" }; xkb_geometry { include "pc(pc105)" }; };
Now edit this file and place the overrides we need into it:
// Attempting to define and use a key as Level4 Shift/Latch/Lock. // Plan: * activate lv5 shift on rctrl. // * place latches on lv5 of keys 2,3,4,5 for corresponding level. // * replace keys ASDF with 8-level versions and define symbols for test. // * pressing RCtrl+4 then A should result in Á // starting point: setxkbmap -layout us -variant altgr-intl -option '' -print // load this file: xkbcomp myfile.xkb $DISPLAY xkb_keymap { xkb_keycodes { include "evdev+aliases(qwerty)" }; xkb_types { include "complete" }; xkb_compat { include "complete" // add in interpretations // ISO_Level3_Latch includes a +AnyOf stanza and a +AnyOfOrNone stanza (same for ISO_Level5_Latch) // assume each additional latch needs both interpret ISO_Level2_Latch+AnyOf(all) { useModMapMods=level1; action= LatchMods(modifiers=Shift,clearLocks,latchToLock); }; interpret ISO_Level2_Latch+AnyOfOrNone(all) { action= LatchMods(modifiers=Shift,clearLocks,latchToLock); }; interpret ISO_Fast_Cursor_Left+AnyOf(all) { // Level4 needs both Shift and LevelThree useModMapMods=level1; action= LatchMods(modifiers=Shift+LevelThree,clearLocks,latchToLock); }; interpret ISO_Fast_Cursor_Left+AnyOfOrNone(all) { // Level4 needs both Shift and LevelThree action= LatchMods(modifiers=Shift+LevelThree,clearLocks,latchToLock); }; }; xkb_symbols { include "pc" include "us(altgr-intl)" include "inet(evdev)" // latch keys key <AE02> { type= "EIGHT_LEVEL", symbols[Group1]= [ 2, at, twosuperior, dead_doubleacute, ISO_Level2_Latch, X, z, Z ] }; key <AE03> { type= "EIGHT_LEVEL", symbols[Group1]= [ 3, numbersign, threesuperior, dead_macron, ISO_Level3_Latch, X, z, Z ] }; // no ISO_Level4_Latch so use ISO_Fast_Cursor_Left key <AE04> { type= "EIGHT_LEVEL", symbols[Group1]= [ 4, dollar, currency, sterling, ISO_Fast_Cursor_Left, X, z, Z ] }; key <AE05> { type= "EIGHT_LEVEL", symbols[Group1]= [ 5, percent, EuroSign, dead_cedilla, ISO_Level5_Latch, X, z, Z ] }; // no ISO_Level6_Latch so use ISO_Fast_Cursor_Right // no ISO_Level7_Latch so use ISO_Fast_Cursor_Up // no ISO_Level8_Latch so use ISO_Fast_Cursor_Down // eight-level keys ASDF for testing key <AC01> { type= "EIGHT_LEVEL_SEMIALPHABETIC", symbols[Group1]= [ a, A, aacute, Aacute, agrave, Agrave, aring, Aring ] }; key <AC02> { type= "EIGHT_LEVEL_SEMIALPHABETIC", symbols[Group1]= [ s, S, ssharp, section, ccedilla, Ccedilla, ntilde, Ntilde ] }; key <AC03> { type= "EIGHT_LEVEL_SEMIALPHABETIC", symbols[Group1]= [ d, D, eth, ETH, thorn, THORN, t, T ] }; key <AC04> { type= "EIGHT_LEVEL_SEMIALPHABETIC", symbols[Group1]= [ f, F, eacute, Eacute, x, X, z, Z ] }; // ISO_Level3_Shift on Right Alt include "level3(ralt_switch)" // ISO_Level5_Shift on Right Ctrl include "level5(rctrl_switch)" }; xkb_geometry { include "pc(pc105)" }; };
Now you can test the latches (in the example above, ISO_Level5_Shift should be the Right Ctrl key; rerun the xkbcomp command if it is not):
ISO_Level5_Shift+2 then a should print A ISO_Level5_Shift+3 then a should print á ISO_Level5_Shift+4 then a should print Á ISO_Level5_Shift+5 then a should print à
In testing, I've noticed the RCtrl-as-level5-shift is a little flaky and doesn't always get applied properly. Usually rerunning the xkbcomp command once or twice will get it working properly. Test with the A or F keys; Ctrl+D will probably exit your shell.
Some applications will not recognize our borrowed keysym and may do strange things. For example, Firefox will print the 4 even while activating the proper latches, so the key sequence rctrl+4 then a results in 4Á; this does not happen for the real keysyms on 3 and 5, so maybe borrowing a different keysym will let Firefox recognize that nothing should be printed. So far most terminal applications are operating as expected.