Setting keyboard layout on startup

Hi, I have my own keyboard layout that I use and I of course wish to set it on startup.
Working from Keyboard Layout Customization - NixOS Wiki I slimmed it down to the somewhat shorter
services.xserver.displayManager.sessionCommands = "${pkgs.xorg.xkbcomp}/bin/xkbcomp ${layout.xkm} $DISPLAY";,
but this did not work. nixos-rebuild switch is fine, but the layout is not loaded on startup.

I tried to copy-paste the entire snippet and change the bare minimum to start with, it did not work.
My memory is fuzzy, but there’s something in the back of my head saying that xkbcomp is iffy about when you run it, I believe I tried using it before. If you run it too early during startup, nothing will happen. I tried to confirm this and I see other people have similar issues with xkbcomp, but can’t find an explanation.

Inspired by that thought, I added
windowManager.i3.extraSessionCommands = "xkbcomp layout.xkm $DISPLAY";.
My hope was that this would be run later than whenever sessionCommands is run, and work. Sadly it did not work.
What I used to do in the good old imperative days (2 days ago) was to replace the appropriate file in usr/share/X11/xkb/symbols/ with a version containing my own layout, and I could then use setxkbmap as if my layout had always been there. This seems like the wrong thing to do in nix.
setxkbmap is nice, as I have never had any issues with it as I believe I have with xkbcomp.
Because of this, I tried the suggestion in this thread: xkb - What file is the setxkbmap option -rules meant to take, and how can I add keyboard variants to that file? - Ask Ubuntu
No luck.

Any suggestions for what I can try? I have the layout in both .xkb, .xkm formats, and as an addition to a setxkbmap file.
Similar thread that I didn’t want to bump, but here for reference: Setting custom keyboard layout in configuration.nix

I’m struggling with the same issue. xkbcomp mylayout.xkb outputfile does not do anything. The guides I can find online seem out-of-date.

1 Like

Does it not even create mylayout.xkm? I can set the layout just fine if I do it manually post-launch with xkbcomp layout.xkm $DISPLAY

I was completely wrong with my approach. I didn’t realize the knew Gnome desktop environment was using wayland instead of x11. xkbcomp failed and did not give any warnings/errors. It just simply did nothing on that setup. I changed to Cinnamon desktop that runs on x11 and xkbcomp mylayout.xkb $DISPLAY switched the keyboard layout as expected (with some warnings that could just be ignored).

To load my custom layout upon x11 startup I simply had to execute that xkbcomp mylayout.xkb $DISPLAY each time x11 starts. There is a built-in configuration parameter for that but I can’t remember the name and I’m not using my Nix box right now so I can’t check. It’s easy to find though.

Good luck!

Is it a solution related to the ones described here? https://www.reddit.com/r/NixOS/comments/cg102t/how_to_run_a_shell_command_upon_startup/
I added systemd.user.services.foo = { script = '' xkbcomp layout.xkm $DISPLAY xset r rate 200 50 ''; wantedBy = [ "graphical-session.target" ]; partOf = [ "graphical-session.target" ]; };
to configuration.nix but it did not work. Did you use something else?

The setting for running shell commands at the beginning of each display manager session is services.xserver.displayManager.sessionCommands.

Simply adding xkbcomp and/or xmodmap commands in there should be enough to load your custom keyboard layout. The xkb file must be in “full format” … not symbols only. You can get a template with current settings by running xkbcomp $DISPLAY output.xkb. I exported the xkb settings from my Manjaro box to my NixOS box using that command on the Manjaro box. It worked without any modifications/issues.

Uh, I thought that’s what I did but apparently not, because it works now.
For future reference, this is my entire xserver snippet

  services.xserver = {
    enable = true;
    desktopManager = {
      xterm.enable = false;
      xfce = {
        enable = true;
        noDesktop = true;
        enableXfwm = false;
      };
    };
    windowManager.i3.enable = true;
    displayManager.defaultSession = "xfce+i3";
    displayManager.sessionCommands = "xkbcomp layout.xkm $DISPLAY";
  };