3

I'm trying to set some CapsLock + arrows keybindings in xkb

Using ArchLinux, KDE, Xorg

What I'm trying to achieve (wishful thinking)

Ultimately, the perfect solution would be

No modifier CapsLock as modifier
Left Home
Up PageUp
Right End
Down PageDown

while pressing just CapsLock would work on key release, as normal latching CapsLock.

Adding Shift into the mix, or any keybind that uses mapped keys for that matter, should still work.

Moreover, for better compatibility, these bindings should work on keysym level and not using (state, key).

The problem

I don't believe this does what I'd like it to do, and probably doesn't even parse

capslock_nav (added to /usr/share/X11/xkb/symbols)

xkb_symbols "lv3-arrow-nav" {
    include "level3(caps_switch)"
    key.type = "THREE_LEVEL";
    key   <UP> {         [              Up, Up, Prior, NoSymbol] };
    key <LEFT> {         [            Left, Left, Home, NoSymbol ] };
    key <RGHT> {         [           Right, Right, End, NoSymbol ] };
    key <DOWN> {         [            Down, Down, Next, NoSymbol ] };
}

and I've been trying to achieve this by setting CapsLock to ISO_Level3_Shift and using that in symbols declarations, but to no avail.

Progress so far

My changes are visible in KDE's Settings > Keyboard > Advanced list, that was accomplished by adding entry to evdev.xml, like so

<!-- ... under <optionList> ... -->
<group allowMultipleSelection="true">
      <configItem>
        <name>capslock_nav</name>
        <description>Navigation using CapsLock</description>
      </configItem>
      <option>
        <configItem>
          <name>capslock_nav:lv3-arrow-nav</name>
          <description>Caps Lock Arrow Navigation</description>
        </configItem>
      </option>
    </group>

and this one to evdev.lst, just to be sure

...
  capslock_nav         Navigation using CapsLock
  capslock_nav:lv3-arrow-nav Caps Lock Arrow Navigation
...

this is also somewhat reflected by setxkbmap:

setxkbmap -print -query
xkb_keymap {
        xkb_keycodes  { include "evdev+aliases(qwerty)" };
        xkb_types     { include "complete"      };
        xkb_compat    { include "complete"      };
        xkb_symbols   { include "pc+pl+inet(evdev)"     };
        xkb_geometry  { include "pc(pc86)"      };
};
rules:      evdev
model:      pc86
layout:     pl
options:    capslock_nav:lv3-arrow-nav


options contain my changes, but it's not included in xkb_symbols. xkbcomp $DISPLAY - also has no mention of my changes.

I've gone through ArchWiki and various articles online on the topic, but it's a bit complicated. I feel like I'm making some progress, it's just that it's very slow.

EDIT: Progress so far

I've dropped my configs and started working off of xkb#caps hjkl on archwiki

and prepared this config, which I've split into corresponding files (compat, symbols types)

partial xkb_types "lv3-arrow-nav" {
    include "complete";
    type "CUST_CAPSLOCK" {
       modifiers= Shift+Lock; 
       map[Shift] = Level2;            //maps shift and no Lock. Shift+Alt goes here, too, because Alt isn't in modifiers.
       map[Lock] = Level3;
       map[Shift+Lock] = Level3;       //maps shift and Lock. Shift+Lock+Alt goes here, too.
       level_name[Level1]= "Base";
       level_name[Level2]= "Shift";
       level_name[Level3]= "Lock";
   };
}

partial xkb_compatibility "lv3-arrow-nav" {
    interpret Caps_Lock {
        action= SetMods(modifiers=Lock);
    };
    augment "complete";
    augment "caps(caps_lock)";
}

partial xkb_symbols "lv3-arrow-nav" {
    include "pc";
    key <LEFT> {
       type= "CUST_CAPSLOCK",
       symbols[Group1]= [               Left,               Left,               Home],
       actions[Group1]= [      NoAction(),      NoAction(),   RedirectKey(keycode=<LEFT>, clearmods=Lock) ]
    };
    key <UP> {
        type= "CUST_CAPSLOCK",
        symbols[Group1]= [               Up,               Up,               Prior],
        actions[Group1]= [      NoAction(),      NoAction(),   RedirectKey(keycode=<UP>, clearmods=Lock) ]
    };
    key <RGHT> {
        type= "CUST_CAPSLOCK",
        symbols[Group1]= [               Right,               Right,               End],
        actions[Group1]= [      NoAction(),      NoAction(),   RedirectKey(keycode=<RGHT>, clearmods=Lock) ]
    };
    key <DOWN> {
        type= "CUST_CAPSLOCK",
        symbols[Group1]= [               Down,               Down,               Next],
        actions[Group1]= [      NoAction(),      NoAction(),   RedirectKey(keycode=<DOWN>, clearmods=Lock) ]
    };
}

which I've validated using xkbcomp, but it still does not behave in expected way.

EDIT2

Well, at least it does something, because this config,

xkb
├── compat
│  └── capslock_nav
├── rules
│  └── evdev
├── symbols
│  └── capslock_nav
├── types
│  └── capslock_nav
└── xkb_keymap.xkb

applied using

xkbcomp -I$HOME/xkb/ $HOME/xkb/xkb_keymap.xkb $DISPLAY

at least disables caps lock...

EDIT3

Looks like I've made some progress, by making all actions = NoAction() in symbols definition

Esgariot
  • 41
  • 3

1 Answers1

1

Looks like this is as far as I'm getting:

Working

  • CapsLock + Left, Up, Right, Down working as Home, PageUp, End, PageDown
  • existing layout settings preserved (I can still use pl layout, set in KDE's keyboard settings)

Not working

  • integration with KDE's keyboard > advanced toggles - toggle is there, but it only changes symbols includes when queried by setxkbmap -query
  • stand-alone CapsLock as usual CapsLock latch

The solution

I've created a folder structure compliant with xkeyboard-config, like so (the xkb/**/* part)

$HOME/xkb_mod
├── xkb
│  ├── compat
│  │  └── capslock_nav
│  ├── symbols
│  │  └── capslock_nav
│  └── types
│     └── capslock_nav
└── xkb_keymap.xkb

xkb/ will be part of -I includes

File contents

(inspired by https://wiki.archlinux.org/title/X_keyboard_extension#Caps_hjkl_as_vimlike_arrow_keys )

compat/capslock_nav

partial xkb_compatibility "caps-arrow-nav" {
    interpret Caps_Lock {
        action= SetMods(modifiers=Lock);
    };
};

symbols/capslock_nav

partial xkb_symbols "caps-arrow-nav" {
    key <LEFT> {
       type= "CUST_CAPSLOCK",
       symbols[Group1]= [               Left,               Left,               Home]
    };
    key <UP> {
        type= "CUST_CAPSLOCK",
        symbols[Group1]= [               Up,               Up,               Prior]
    };
    key <RGHT> {
        type= "CUST_CAPSLOCK",
        symbols[Group1]= [               Right,               Right,               End]
    };
    key <DOWN> {
        type= "CUST_CAPSLOCK",
        symbols[Group1]= [               Down,               Down,               Next]
    };
};

types/capslock_nav

partial xkb_types "caps-arrow-nav" {
    type "CUST_CAPSLOCK" {
       modifiers= Shift+Lock; 
       map[Shift] = Level2;            //maps shift and no Lock. Shift+Alt goes here, too, because Alt isn't in modifiers.
       map[Lock] = Level3;
       map[Shift+Lock] = Level3;       //maps shift and Lock. Shift+Lock+Alt goes here, too.
       level_name[Level1]= "Base";
       level_name[Level2]= "Shift";
       level_name[Level3]= "Lock";
   };
};

After that I've queried existing settings and put them in xkb_keymap.xkb

setxkbmap -query > ~/xkb_mod/xkb_keymap.xkb

and manually included +capslock_nav(caps-arrow-nav) in every include, like so:

xkb_keymap.xkb

xkb_keymap {
    xkb_keycodes  { include "evdev+aliases(qwerty)" };
    xkb_types     { include "complete+capslock_nav(caps-arrow-nav)" };
    xkb_compat    { include "complete+capslock_nav(caps-arrow-nav)" };
    xkb_symbols   { include "pc+pl+inet(evdev)+capslock_nav(caps-arrow-nav)"    };
    xkb_geometry  { include "pc(pc86)"  };
};

Finally, I've applied the config by running

xkbcomp -I$HOME/xkb_mod/xkb xkb_mod/xkb_keymap.xkb $DISPLAY
Esgariot
  • 41
  • 3