How to fix F13-F24 keys

I have a USB foot pedal that acts as a keyboard and sends the F13 key. On Windows and Mac it works like you’d expect. But Linux seems to remap the F13-F24 keys at a low level to a bunch of random XF86 keys.

This reddit thread has instructions for a fix on plain Linux. But I am having trouble translating the fix to NixOS. The NixOS wiki describes how to define an entirely new layout, and how to set predefined options. But it does not describe how to define a new option.

Does anyone have a working recipe for using F13-F24 as normal keys on NixOS?

It looks like someone has tried to do this before.

The problems seems to be that you can’t edit xkb rules:

Replicating the patterns using in the linked code, I came up with this:

{ pkgs, ... }:
let
  my-xkeyboard-config = pkgs.xkeyboard_config.overrideAttrs (_: { 
   postFixup = ''
      cat > $out/share/X11/xkb/symbols/myoptions <<EOF
        default partial function_keys
        xkb_symbols "restore_fk" {
          key<FK13> { [ F13 ] };
          key<FK14> { [ F14 ] };
          key<FK15> { [ F15 ] };
          key<FK16> { [ F16 ] };
          key<FK17> { [ F17 ] };
          key<FK18> { [ F18 ] };
          key<FK19> { [ F19 ] };
          key<FK20> { [ F20 ] };
          key<FK21> { [ F21 ] };
          key<FK22> { [ F22 ] };
          key<FK23> { [ F23 ] };
          key<FK24> { [ F24 ] };
        };
      EOF

      ${pkgs.ed}/bin/ed -v $out/share/X11/xkb/rules/evdev <<EOF
      /^!\W\+option\W\+=\W\+symbols$
      a
      myopts:re_fk = +myoptions(restore_fk)
      .
      w
      EOF

      ${pkgs.ed}/bin/ed -v $out/share/X11/xkb/rules/evdev.xml <<EOF
      /<optionList>
      a
      <group allowMultipleSelection="true">
        <configItem>
          <name>myopts</name>
          <description>My custom options</description>
        </configItem>
        <option>
          <configItem>
            <name>myopts:re_fk</name>
            <description>Restore original keysyms of the function keys from 13 to 24</description>
          </configItem>
        </option>
      </group>
      .
      w
      EOF

    '';
  });
in
{
  services.xserver = {
    enable = true;
    exportConfiguration = true; # I'm not sure if this is necessary
    xkb.dir = my-xkeyboard-config + "/etc/X11/xkb";
  };
}

I have not tested this, but it should be a good starting point for you.

After building your system the files should be modified and located in /etc/X11/xkb/rules/evdev.xml… etc

1 Like

I haven’t had exactly this problem, but when I’ve had similar problems I’ve fixed them at the libinput level (i.e. below the xkb/wayland level) using keymapper or kmonad or any of various other programs - see GitHub - jtroo/kanata: Improve keyboard comfort and usability with advanced customization for some other options.

Somewhat less intrusive might be using home-manager. I managed to define some XKB options this way in the past:

2 Likes

Thanks for your responses, especially @lelgenio for writing out that config. It worked exactly as you intended, but unfortunately X wasn’t applying the option. I never figured out why.

In the end I got it working with a hacky script that runs on login:

#!/bin/sh

dir=$(mktemp -d)
mkdir "${dir}"/symbols
cat > "${dir}"/symbols/myoptions <<EOF
xkb_symbols "restore_fk" {
    key<FK13> { [ F13 ] };
    key<FK14> { [ F14 ] };
    key<FK15> { [ F15 ] };
    key<FK16> { [ F16 ] };
    key<FK17> { [ F17 ] };
    key<FK18> { [ F18 ] };
    key<FK19> { [ F19 ] };
    key<FK20> { [ F20 ] };
    key<FK21> { [ F21 ] };
    key<FK22> { [ F22 ] };
    key<FK23> { [ F23 ] };
    key<FK24> { [ F24 ] };
};
EOF

setxkbmap -print \
    | sed 's/\(xkb_symbols.*\)"/\1+myoptions(restore_fk)"/' \
    | xkbcomp -I"${dir}" - $DISPLAY

rm -r "${dir}"

I got it working by just modifying the inet file directly.
Setting the XKB_CONFIG_ROOT environment variable makes this also work on wayland.

{ pkgs, ... }:
let
  fixed-keyboard-config = pkgs.xkeyboard_config.overrideAttrs (_: {
    postFixup = ''
      ${pkgs.gnused}/bin/sed -i 's/\(key <FK\)\(13\|14\|15\|16\|17\|18\|19\|20\|21\|22\|23\|24\)\(>\)\(.\+\)/\1\2\3 { [ F\2 ] };/g' $out/share/X11/xkb/symbols/inet
      ${pkgs.gnused}/bin/sed -i '/xkb_symbols "evdev" {/a key <FK24> { [ F24 ] };' $out/share/X11/xkb/symbols/inet
    '';
  });

in
{
  services.xserver = {
    enable = true;
    xkb.dir = fixed-keyboard-config + "/etc/X11/xkb";
  };

  environment.sessionVariables = {
    XKB_CONFIG_ROOT = fixed-keyboard-config + "/etc/X11/xkb";
  };
}