How To... | Why not..? | Scripts | Patches | ![]() |
Last update: 2021-01-03
This article shows you how you can get the extra multimedia keys working. For this I use only software that is part of the base system - with the exception of the media player moc.
The latest update on this article happened for two reasons: OpenBSD has changed from mixerctl(1) to sndioctl(1) as the preferred tool for controlling the mixer from user space. And I have changed from mpv to moc as my music player ;-)
The keyboard I use at home is Das Keyboard 4 Ultimate. It has the following extra keys available:
Key | Description / Action |
---|---|
☾ | Sleep / Hibernate / Shutdown |
🔇 | Mute / unmute the speakers |
Wheel | Volume up / down |
|<< |
Previous track |
>|| |
Play / Pause |
>>| |
Next track |
First, you must find out which USB HID devices are detected by OpenBSD during boot. Use dmesg(8) together with grep(1) to get the list:
$ dmesg | grep uhidev
uhidev0 at uhub2 port 2 configuration 1 interface 0 "Logitech USB Receiver" rev
2.00/12.03 addr 3
uhidev0: iclass 3/1
ukbd0 at uhidev0: 8 variable keys, 6 key codes
uhidev1 at uhub2 port 2 configuration 1 interface 1 "Logitech USB Receiver" rev
2.00/12.03 addr 3
uhidev1: iclass 3/1, 8 report ids
ums0 at uhidev1 reportid 2: 16 buttons, Z and W dir
uhid0 at uhidev1 reportid 3: input=4, output=0, feature=0
uhid1 at uhidev1 reportid 4: input=1, output=0, feature=0
uhid2 at uhidev1 reportid 8: input=1, output=0, feature=0
uhidev2 at uhub2 port 2 configuration 1 interface 2 "Logitech USB Receiver" rev
2.00/12.03 addr 3
uhidev2: iclass 3/0, 33 report ids
uhid3 at uhidev2 reportid 16: input=6, output=6, feature=0
uhid4 at uhidev2 reportid 17: input=19, output=19, feature=0
uhid5 at uhidev2 reportid 32: input=14, output=14, feature=0
uhid6 at uhidev2 reportid 33: input=31, output=31, feature=0
uhidev3 at uhub2 port 4 configuration 1 interface 0 "Metadot - Das Keyboard Das
Keyboard" rev 2.00/1.00 addr 4
uhidev3: iclass 3/1
ukbd1 at uhidev3: 8 variable keys, 6 key codes
uhidev4 at uhub2 port 4 configuration 1 interface 1 "Metadot - Das Keyboard Das
Keyboard" rev 2.00/1.00 addr 4
uhidev4: iclass 3/0, 3 report ids
uhid7 at uhidev4 reportid 1: input=0, output=0, feature=7
uhid8 at uhidev4 reportid 2: input=1, output=0, feature=0
uhid9 at uhidev4 reportid 3: input=3, output=0, feature=0
The uhid(4) devices are the ones you are looking for. In my case the devices uhid8 and uhid9 are relevant because there is no driver attached to these devices. And these devices provide HID descriptors of the type input.
On a fresh installation of OpenBSD you will find only four uhid(4)
devices in /dev/
:
$ ls /dev/uhid*
/dev/uhid0 /dev/uhid1 /dev/uhid2 /dev/uhid3
If your dmesg(8) shows more uhid(4) devices than are available in /dev
you will have to create the extra devices manually. Those devices are
only accessible if a matching device file exists in /dev
:
$ cd /dev
$ for i in $(jot -ns " " - 4 9) ; do
> doas ./MAKEDEV uhid$i
> done
$
Only the user root
has read and write access to the newly created
devices. Make sure your regular user has read and write access to the
device that is used for the special keys:
$ doas chown <user> /dev/uhid9
The OpenBSD tool usbhidctl(1) is able to read and display the data it receives from uhid(4) devices. The tool will try to translate the received report descriptors into human readable strings.
I use script(1) to collect the output of usbhidctl(1) in a file:
$ script -c "usbhidctl -l -f /dev/uhid9" usbkeys.txt
Script started, output file is usbkeys.txt
You should define an order to press the keys. The translation doesn't always give you meaningful names for each key you press. And the amount of data you get for each key press/key release event can be bigger than you might expect.
When you are done pressing keys you can quit script(1) with ^C. The next step is to filter out the relevant information. Use grep(1) for this task:
^CScript done, output file is usbkeys.txt
$ grep =1 usbkeys.txt
Consumer_Control.Mute=1
Consumer_Control.Scan_Previous_Track=1
Consumer_Control.Play/Pause=1
Consumer_Control.Scan_Next_Track=1
Consumer_Control.Volume_Decrement=1
Consumer_Control.Volume_Increment=1
$
Lucky me, Das Keyboard gives me proper names for the keys I've pressed. That must not be the case with all the keyboards out there. My former keyboard Logitech K800 produced some weird output.
You can use the captured data to prepare the config file for usbhidaction(1).
$ grep =1 usbkeys.txt | sed 's/_Control//;s/\./:/;s/=/\ /' > usbhidaction.conf
$ cat usbhidaction.conf
Consumer:Mute 1
Consumer:Scan_Previous_Track 1
Consumer:Play/Pause 1
Consumer:Scan_Next_Track 1
Consumer:Volume_Decrement 1
Consumer:Volume_Increment 1
Now you can the command to execute for each key as a separate line below the key. You can also insert comments beginning with a #. When you have finished the file should look similar to mine:
# Das Keyboard 4 Ultimate
Consumer:Mute 1
sndioctl output.mute=!
Consumer:Scan_Previous_Track 1
/usr/local/bin/mocp -r
Consumer:Play/Pause 1
/usr/local/bin/mocp -G
Consumer:Scan_Next_Track 1
/usr/local/bin/mocp -f
Consumer:Volume_Decrement 1
sndioctl output.level=-0.01
Consumer:Volume_Increment 1
sndioctl output.level=+0.01
To test your configuration you can start usbhidaction(1) manually:
$ usbhidaction -c /etc/usbhidaction.conf -f /dev/uhid9
At the time of writing this, there is no rc.d(8) script for usbhidaction(1) yet. You can use this one:
#!/bin/ksh
#
# $OpenBSD: usbhidaction,v 1.4 2019/08/25 15:47:51 user Exp $
daemon="/usr/bin/usbhidaction"
. /etc/rc.d/rc.subr
rc_cmd $1
Save the above lines to /etc/rc.d/usbhidaction
and run the following
commands:
$ doas chmod 555 /etc/rc.d/usbhidaction
$ doas rcctl enable usbhidaction
$ doas rcctl set usbhidaction user <user>
$ doas rcctl set usbhidaction flags -c /etc/usbhidaction.conf -f /dev/uhid9
Replace with the login name of the user usbhidaction should run as. That's it, folks!
|<<
, >||
and >>|
don't work for meOpenBSD provides a central volume control with sndioctl(1).
But there is no central control for |<<
, >||
and >>|
. If you like
it or not, you have to find a way to send the right commands to your
favorite media player.
I use moc as my audio player. It can be
controlled from the command line by parameters once it is running.
You can see the commands above in my usbhidaction.conf
.
Whenever I press |<<
, >||
or >>|
usbhidaction(1) will execute the
matching command and if moc is running, it will react on it.
This key is not reported on the same uhid(4) device as the other keys on
the keyboard. It comes with its own uhid(4) device, usually the one with
the lower number, in my example this is /dev/uhid8
instead of
/dev/uhid9
.