Perhaps influenced by industrial mandatory practices, I wanted to add an emergency button to my home server in order to shut it down fast. For example in case of power shortage, I’d like to trigger a clean shutdown before the UPS runs out of power and without requiring a screen or keyboard attached. Therefore I bought an USB “emergency” button.
Example of USB emergency button
/sys/bus/usb/devices/
tree where keyboard are of Class 03 and Protocol 01. The following script gets the list:
for dev in /sys/bus/usb/devices/*-*:*
do
if [ -f $dev/bInterfaceClass ]
then
if [[ "$(cat $dev/bInterfaceClass)" == "03" && "$(cat $dev/bInterfaceProtocol)" == "01" ]]
then
echo "Keyboard detected: $dev"
fi
fi
done
Where to go now? After further searches I figured out that I had to handle low level events from devices, USB or not, to get input in headless mode.
Event sources are listed in /proc/bus/input/devices
. A keyboard is an event source of type 120013. This value corresponds to a bitmap of flags. Then, finding all devices emitting keyboard events boils down to the following single-liner:
grep -E 'Handlers|EV=|Bus=' /proc/bus/input/devices | grep -B2 'EV=120013' | grep -v -E 'EV=|--'
The resulting list contains vendor ID and product ID of both USB devices, like the emergency button and non USB like the keyboard of a laptop. Once the Vendor and Product ID are known, it is possible to find the corresponding event source by searching in the /dev/input/event
list.
Finally, when the right event file descriptor is found, it can be opened and read. It is however not so simple than getting characters from console: not only ona has to cope with key-codes instead of character values but also key bounce management is left to the user.
With all these findings, I managed to write a service (daemon) able to get button press and trigger a user defined script, for example a shutdown command. The result is available, along with tools to detect devices, in a dedicated repository.
If you know a simpler way to do, please contact me!