Change udev when USB keyboard is present


I want to add a piece to my configuration.nix so that the keyboard layout changes when a USB keyboard is present, and I was wondering if there is a NixOS way of accomplishing this. Currently, I have:

services.udev.extraRules = ''
  ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="feed", ATTRS{idProduct}=="0000", RUN+="${pkgs.coreutils}/bin/touch /run/usb-keyboard-connected"
  ACTION=="remove", SUBSYSTEM=="usb", ATTRS{idVendor}=="feed", ATTRS{idProduct}=="0000", RUN+="${pkgs.coreutils}/bin/rm /run/usb-keyboard-connected"
''; = {
  description = "Switch keyboard layout based on external keyboard connection";
  script = ''
    export DISPLAY=:0
    while true; do
      if [ -e /run/usb-keyboard-connected ]; then
        /run/current-system/sw/bin/runuser -l microbass -c "/run/current-system/sw/bin/setxkbmap us"
        /run/current-system/sw/bin/runuser -l microbass -c "/run/current-system/sw/bin/setxkbmap ie"
      sleep   10
  serviceConfig = {
    Type = "simple";
    Environment = "DISPLAY=:0 XAUTHORITY=/home/microbass/.Xauthority";
    User = "microbass";
    Group = "users"; 
    Restart = "always";
    RestartSec = "10";
  wantedBy = [ "" ];

but I’m getting permission errors on the above. Is there an option that I’m missing to trigger setxkbmap in userspace?

Thanks, as always!

Not sure about the setxkbmap permissions, but you can probably use SYSTEMD_WANTS to avoid the polling, and maybe StopWhenUnneeded to simplify further, something like:

services.udev.extraRules = ''
  SUBSYSTEM=="usb", ATTR{idVendor}=="feed", ATTR{idProduct}=="0000", TAG+="systemd", ENV{SYSTEMD_WANTS}="usb-keyboard.service"
''; = {
  unitConfig.StopWhenUnneeded = true;

  script = ''
    echo 'Connected'

  preStop = ''
    echo 'Disconnected'

The script etc. options don’t need a shebang as they use writeShellScriptBin which already adds one.

And in case you hadn’t seen, there should also be a way to set a different layout for each keyboard though I’m not personally familiar with that.