5

I have configured my keyboard layout by adding a call to setxkbmap to my .xinitrc. This works for my laptop's internal keyboard and for any external keyboard that is plugged in when the X server starts. If I plug in an external keyboard later, it uses the default US keymap.

How can I make sure that any keyboard that I plug in has my preferred layout?

2 Answers 2

8

As Gilles commented on Dominik R's answer yesterday, the udev approach only works for the root user and doesn't work well as a general, unprivileged solution. I'd suggest considering inputplug(1) by Andrew Shadura available in Debian as the package inputplug as well as at the project site.

inputplug(1) is a rather straightforward as a XINPUT event loop listener which will invoke a script with decoded event parameters as arguments. Since you're using .xinitrc, I imagine you're using a modest window manager / environment and a background listener of this sort should be pretty straightforward for you.

Another possibility is using udev in a less traditional way by writing a script parsing the output from "udevadm monitor" and invoking setxkbmap upon recognizing a matching device being connnected.

Good Luck!

2
  • 1
    I am using a modest input manager but I am a beginner at that so some example calls to inputplug would be much appreciated.
    – Thriveth
    Commented Sep 26, 2019 at 7:42
  • 1
    Added a complete example as an answer below. Commented Jul 9, 2021 at 20:53
3

inputplug, suggested by etherfish five years ago, is an excellent answer, but the answer was missing a complete example. So here is what I use in my .xinitrc to run setxkbmap exactly once in the beginning, and another time every time a new keyboard is plugged in:

{ echo "XIDeviceEnabled XISlaveKeyboard"; inputplug -d -c /bin/echo; } |
while read event
do
        case $event in
        XIDeviceEnabled*XISlaveKeyboard*)
                setxkbmap -option grp:switch,grp:shift_toggle,grp_led:scroll us,il ,lyx
                setxkbmap -option caps:none
                ;;
        esac
done &

The inputplug -d -c /bin/echo echos a message like

XIDeviceEnabled 11 XISlaveKeyboard Logitech K270

every time a keyboard is plugged in, and the while loop finds such messages and causes the relevant setxkbmap commands to run (in my example, I set a Hebrew keyboard mapping, and remove the Caps Lock feature which I hate). The extra echo "XIDeviceEnabled XISlaveKeyboard" in the beginning causes the loop to also find a "new keyboard" exactly once in the beginning. inputplug also has a "-0" option to print existing keyboards on startup, but this will usually print multiple keyboards and cause the setxkbmap to be needlessly run multiple times on startup.

4
  • 1
    Thank you for adding extra detail and an example!
    – etherfish
    Commented Jul 9, 2021 at 22:53
  • 1
    Author here. You can also directly call your script with -c, this is actually how it’s intended to be used — just put the case/esac into a separate script and run inputplug as a dæmon.
    – andrewsh
    Commented Jul 21, 2021 at 14:05
  • Yes, indeed it's also possible to pass a separate handler script to inputplug. However, since anyway I need to write code to run inputplug - in my .xinitrc - I wanted all the related code to be in one place, and not have to create a separate handler script somewhere else. Commented Jul 22, 2021 at 21:39
  • 2
    That seems like a fairly common use case, it may be worth having -c take - as argument, and inputplug would read the script on the standard input. It feels quite natural to then write inputplug -c - << EOF followed by the script.
    – Michaël
    Commented Apr 5, 2022 at 17:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .