Search code examples
linuxnumerickeypademulationintegrated

How to emulate integrated numeric keypad cursor keys in linux


On many older laptops and some compact keyboards there is an integrated numeric keypad in the main keyboard area. This alternate keypad is activated with a special 'Fn' key next to the left Ctrl key.

As a programmer I learned to use the cursor movement keys (arrows, PgUp, PgDn etc.) and found it greatly improved my programming speed. And the benefits were not bound to just a single application as is the case with specialised shortcut keys.

On conventional PC keyboards, the 'Windows Key' can be used to emulate the 'Fn' key and a corresponding integrated numeric keypad. When I used to use MS Windows I found Autohotkey was able to map the keys using a simple script.

Recently I learned about xkb and how it can be used to map keystrokes at a very low level.

What is the xkb keyboard mapping profile that will emulate an integrated numeric keypad using the windows key as the fn key?

Hint(?): I suspect the file will look a lot like the '/usr/share/X11/xkb/symbols/keypad' file on a Debian-derivative linux distro. This 'keypad' file is included at the top of the '/usr/share/X11/xkb/symbols/pc' file.

The corresponding autohotkey script for reference (# == WinKey):

#8::Up
#k::Down
#u::Left
#o::Right

#7::Home
#j::End
#9::PgUp
#l::PgDn

#m::Insert
#.::Delete

;(Scroll with the left-over keys)
#i::WheelUp
#,::WheelDown

Note that all these keys need to work with any combination of Ctrl, Alt, Shift as well as the Windows Key.


Solution

  • Steps to install numeric keypad-like cursor keys on the main keyboard in Linux / XKB...

    1. xkbcomp $DISPLAY original.xkb (just in case ;)
    2. xkbcomp $DISPLAY custom.xkb
    3. Edit custom.xkb
    4. Add the following at the end of section: xkb_types "..." {

      type "WinKeyAsFnKey" {
        modifiers = Shift+Super;
        map[Shift] = level2;
        map[Super] = level3;
        map[Super+Shift] = level3;
        level_name[Level1] = "Base";
        level_name[Level2] = "Caps";
        level_name[Level3] = "Fn";
      };
      
    5. Add the following at the end of section xkb_symbols "..." {

       key <AE07> {type="WinKeyAsFnKey",symbols[Group1]=[7,ampersand,NoSymbol],actions=[NoAction(),NoAction(),RedirectKey(key=<HOME>,clearmods=Super)]};
       key <AE08> {type="WinKeyAsFnKey",symbols[Group1]=[8,asterisk,NoSymbol],actions=[NoAction(),NoAction(),RedirectKey(key=<UP>,clearmods=Super)]};
       key <AE09> {type="WinKeyAsFnKey",symbols[Group1]=[9,parenleft,NoSymbol],actions=[NoAction(),NoAction(),RedirectKey(key=<PGUP>,clearmods=Super)]};
       key <AD07> {type="WinKeyAsFnKey",symbols[Group1]=[u,U,NoSymbol],actions=[NoAction(),NoAction(),RedirectKey(key=<LEFT>,clearmods=Super)]};
       key <AD09> {type="WinKeyAsFnKey",symbols[Group1]=[o,O,NoSymbol],actions=[NoAction(),NoAction(),RedirectKey(key=<RGHT>,clearmods=Super)]};
       key <AC07> {type="WinKeyAsFnKey",symbols[Group1]=[j,J,NoSymbol],actions=[NoAction(),NoAction(),RedirectKey(key=<END>,clearmods=Super)]};
       key <AC08> {type="WinKeyAsFnKey",symbols[Group1]=[k,K,NoSymbol],actions=[NoAction(),NoAction(),RedirectKey(key=<DOWN>,clearmods=Super)]};
       key <AC09> {type="WinKeyAsFnKey",symbols[Group1]=[l,L,NoSymbol],actions=[NoAction(),NoAction(),RedirectKey(key=<PGDN>,clearmods=Super)]};
       key <AB07> {type="WinKeyAsFnKey",symbols[Group1]=[m,M,NoSymbol],actions=[NoAction(),NoAction(),RedirectKey(key=<INS>,clearmods=Super)]};
       key <AB09> {type="WinKeyAsFnKey",symbols[Group1]=[period,greater,NoSymbol],actions=[NoAction(),NoAction(),RedirectKey(key=<DELE>,clearmods=Super)]};
      
    6. Save custom.xkb

    7. xkbcomp custom.xkb $DISPLAY

    I'm still working on the mouse scroll with 'i' and ','.

    EDIT: The above solution does not play nice with Google Chrome and Chrome-based apps (like Slack).

    Alternative approach is to use a programmable keyboard. I use an after-market PCB for a CoolerMaster Masterkeys S keyboard. The Easy AVR layout is available online (although currently the left win-key now doesn't work by itself...I use the right one).