Multiple keyboard layouts on OpenBSD
930 words, 5 minutes
My ThinkPad P14s Gen 5 AMD has a French (ISO AZERTY). But it is connected to a dock and I mainly use an external (USB) keyboard with an ANSI US layout.
Because I’d rather not type with an US layout on an FR keyboard, and vice-versa, I have configured my OpenBSD OS to deal with both, nearly automagically.
The BIOS
It is possible to set a keyboard layout in the BIOS. This allows typing the FDE passphrase with a proper keyboard layout. Unfortunately, AFAIK, it is not possible to switch keyboard layouts from there.
So I’m stucked with typing the passphrase with whatever layout was configured in the BIOS.
The OpenBSD console
The OpenBSD console can be managed using wsconsctl(8) and its wsconsctl.conf(5) configuration file. As far as I understood, it can only be managed using high privileges. But the configuration is not modified that often when the proper setup is achieved.
I’m not sure why I have that many keyboard references. But looking at dmesg(8), I can identify the ones I need to modify.
# dmesg | grep -B 5 wskbd | more
(...)
pckbd0 at pckbc1 (kbd slot)
wskbd0 at pckbd0: console keyboard
(...)
uhidev0 at uhub6 port 4 configuration 1 interface 5 "DELL DELL Slim Soundbar SB522A" rev 2.00/0.00 addr 4
uhidev0: iclass 3/0, 185 report ids
ucc0 at uhidev0 reportid 1: 3 usages, 3 keys, enum
wskbd1 at ucc0 mux 1
(...)
uhidev1 at uhub5 port 2 configuration 1 interface 0 "NuPhy NuPhy Field75" rev 2.00/2.02 addr 5
uhidev1: iclass 3/1
ukbd0 at uhidev1: 8 variable keys, 5 key codes
wskbd2 at ukbd0 mux
(...)
uhidev5 at uhub5 port 4 configuration 1 interface 0 "Logitech USB Receiver" rev 2.00/24.11 addr 7
uhidev5: iclass 3/1
ukbd2 at uhidev5: 8 variable keys, 6 key codes
wskbd5 at ukbd2 mux
(...)
uhidev6 at uhub5 port 4 configuration 1 interface 1 "Logitech USB Receiver" rev 2.00/24.11 addr 7
uhidev6: iclass 3/1, 8 report ids
ums2 at uhidev6 reportid 2: 16 buttons, Z and W dir
wsmouse5 at ums2 mux 0
ucc2 at uhidev6 reportid 3: 767 usages, 20 keys, array
wskbd6 at ucc2 mux 1
(...)
wsdisplay0 at amdgpu0 mux 1: console (std, vt100 emulation), using wskbd0
wskbd1: connecting to wsdisplay0
wskbd2: connecting to wsdisplay0
wskbd3: connecting to wsdisplay0
wskbd4: connecting to wsdisplay0
wskbd5: connecting to wsdisplay0
wskbd6: connecting to wsdisplay0
The Soundbar has no keyboard; that’s probably the wheel switches that advertise themselves as keyboards. I also only have one single Logitech USB dongle and only a mouse is connected to it. I used to have a keyboard connected there but it is turned off for years now.
Anyway, the keyboards I’m really interested in are wskbd0 and wskbd2.
# doas wsconsctl keyboard keyboard2
keyboard.type=pc-xt
keyboard.bell.pitch=400
keyboard.bell.period=100
keyboard.bell.volume=50
keyboard.bell.pitch.default=400
keyboard.bell.period.default=100
keyboard.bell.volume.default=50
wsconsctl: Use explicit arg to view keyboard.map.
keyboard.repeat.del1=400
keyboard.repeat.deln=100
keyboard.repeat.del1.default=400
keyboard.repeat.deln.default=100
keyboard.ledstate=0
keyboard.encoding=us
keyboard.backlight=0.00%
keyboard2.type=usb
keyboard2.bell.pitch=400
keyboard2.bell.period=100
keyboard2.bell.volume=50
keyboard2.bell.pitch.default=400
keyboard2.bell.period.default=100
keyboard2.bell.volume.default=50
wsconsctl: Use explicit arg to view keyboard2.map.
keyboard2.repeat.del1=400
keyboard2.repeat.deln=100
keyboard2.repeat.del1.default=400
keyboard2.repeat.deln.default=100
keyboard2.ledstate=0
keyboard2.encoding=us
keyboard2.backlight=0.00%
Issuing the relevant wsconsctl command, I can tell OpenBSD that the
laptop’s keyboard should use FR and the USB one should use US.
# doas wsconsctl keyboard.encoding=fr keyboard2.encoding=us
keyboard.encoding -> fr
keyboard2.encoding -> us
After making sure I didn’t wreck anything, I modified the configuration file so that the changes apply at the next reboot too.
# doas vi /etc/wsconsctl.conf
keyboard.encoding=fr # ThinkPad keyboard is FR
keyboard2.encoding=us # NuPhy keyboard is US
It should be noted that this only work in the console. From xenodm(1)
and Xorg(1), both keyboard use the default encoding.
The OpenBSD Xorg session
With the above configuration applied, every new connection to X11 is made using the FR keyboard layout. Great with the ThinkPad keyboard; not with the external USB one.
Once connected to an X11 session, from an X terminal, issuing setxkbmap us allows switching to the US layout. But that doesn’t solve the login
phase issue.
Informations are detailed in xorg.conf(5) and XKB-Config(7). I thought I
could create a configuration that matches every keyboards and sets a
relevant layout. But as far as I understood the documentation, OpenBSD
exposes only one keyboard device to Xenocara. So things like
MatchDevicePath didn’t work.
So I went for an all-in-one multi layout X11 configuration. Every
keyboards are set the same way. And I can switch from layout to layout
using the "<Win> + <space>" key binding.
# vi /usr/X11R6/share/X11/xorg.conf.d/99-keyboards.conf
Section "InputClass"
Identifier "Multi Layout Keyboard(s)"
MatchIsKeyboard "on"
Option "XkbLayout" "us,us,fr"
Option "XkbVariant" "euro,alt-intl,azerty"
Option "XkbOptions" "grp:win_space_toggle"
EndSection
The “us/euro” layout provides the “€” sign using "<AltGr> + <5>".
The “us/alt-intl” layout provides accented characters in ways that feels
natural to me ("<'> + <e> = <é>"). And, TBH, in the same way MS
Windows provides accented characters for US layouts; which is
memory-muscle-proof when I have to use such $WORK laptops with my
external keyboard.
The “fr/azerty” layout is just that.
The nice thing is that the layout switch works inside xenodm and is compatible with Xfce xkb layout switcher panel plug-in.
Final words
This configuration polishes previous experimentation that were described in 2020 and in 2021 .
In case I ever need it, the configuration can be displayed in the terminal:
# setxkbmap -query
rules: base
model: pc105
layout: us,us,fr
variant: euro,alt-intl,azerty
options: grp:win_space_toggle
Should creating a configuration file is not wanted, it can still be applied using the command line:
# setxkbmap -layout us,us,fr \
-variant euro,alt-intl,azerty \
-option terminate:ctrl_alt_bksp \
-option grp:win_space_toggle
Note that such configuration was also implemented as-is on FreeBSD and Slackware Linux. So that’s a great plus for me.
And… that’s all for now.