I have access to my friend's Raspbian (which is not entirely up to date). Still, I don't want to mess with the configuration of the device that is not mine, especially if it involves keyboard support; so the following answer is based on my work in Debian 9. I used Raspbian only to confirm the needed packages are available there. Some details may vary between Debian and Raspbian.
You need these packages:
lirc. Its common usage is to read from controllers (like infra red remotes) and send various commands to various compatible programs (like multimedia players). It can also run arbitrary system commands (e.g. scripts) via
irexec executable, this would be your case. In my Debian the
lirc package provides
irexec.service but in (outdated) Raspbian it seems to provide only the executable, not the service. I will address this later in the answer. And then there is…
inputlirc, zeroconf LIRC daemon using input event devices (like keys on a regular keyboard). We will use its daemon rather than the large
lirc package is still required because of
irexec we want to use).
input-utils, utilities useful to set things up.
sudo apt-get install lirc inputlirc input-utils
If you want to use a specific keyboard (rather than all available keyboards), find out which device it is:
In my case the device I wanted to use was a combo device, it registered as
/dev/input/event9. To see which one is the right device I used
sudo input-events 9 # for /dev/input/event9
I pressed keys I wanted to use and observed the output. I repeated for
event8. It turned out my device passes "normal" keys via
event9 and multimedia keys via
There's no guarantee the same device will get the same number in the future, after reboot. The OS however supplies symlinks for some devices in
/dev/input/by-id. Examine them:
ls -l /dev/input/by-id
These paths shouldn't change, you should prefer them during further configuration.
inputlircd is the daemon from the
inputlirc package. We want to use it to read from keyboard. I think the large LIRC daemon is not really required, so disabling
lircd.service may seem like a good idea. However there are some dependencies which would run LIRC anyway. Rerouting them would make this answer overly complicated, there's no point; so let's keep it as it is.
In my Debian there is
/etc/init.d/inputlirc file. Upon examining I see it uses options from
/etc/default/inputlirc. Set the right values there. My
/etc/default/inputlirc now looks like this:
# Options to be passed to inputlirc.
Note I used two devices in a form
/dev/input/by-id/something, although to monitor all connected keyboards
/dev/input/input* should be right (it was the out-of-the-box setting). You may want to use
-n and/or other options. Read
man 8 inputlircd.
After saving the file, enable and (re)start the service:
systemctl enable inputlirc.service
systemctl restart inputlirc.service
and check if it's running:
systemctl status inputlirc.service
In my Debian I have
/lib/systemd/system/irexec.service. My friend's Raspbian lacks the file (even though
lirc package is installed and
irexec is available). If you need to create it manually, this is its original content from my Debian:
Description=Handle events from IR remotes decoded by lircd(8)
; Hardening opts, see systemd.exec(5). Doesn't add much unless
; not running as root. If these are applicable or not depends on
; what commands irexec.lircrc invokes.
The file is owned by
root:root and the permissions are
644. I guess it's good to add
Requires=inputlirc.service in the
[Unit] section. I'm not an expert in dependencies, so this may be sub-optimal or not enough.
If you consult
man 1 irexec, you will see this
/etc/lirc/irexec.lircrc path that appears above is the config file. Put this snippet in the config file:
prog = irexec
button = KEY_MUTE
config = beep -r 5
systemctl restart irexec.service
irexec start to react to the mute key. Instead of
beep you can use
cd /scripts/ && ./toggle.sh. Now it you press the key, the tool will pass the command to
sh to execute.
To know the key name (e.g.
KEY_MUTE) you can peek what
inputlircd passes through the socket:
socat UNIX-CONNECT:/var/run/lirc/lircd STDOUT
Press keys you want to use and note the output. Names to use are in the third column.
- In my Debian the default socket for
/run/lirc/lircd is the same because of the symlink
/var/run -> /run). If in your case the two tools use different sockets, make them use a single one, it's crucial. There are options for this, see the respective manuals.
For versions up to 0.9.1
irexec used to wait until the executed program terminated. […] This is not required in 0.9.2+ which cannot wait for command completion.
This means you are able to run multiple instances of the script in parallel, just press the key fast enough. If this shouldn't happen, the command you run or the script itself must detect its previous instance(s) and wait or terminate. I would use a lockfile for this. The script itself may be the lockfile, like this:
config = cd /scripts/ && flock -w 1 ./scriptA.sh ./scriptA.sh
The solution doesn't suppress the "normal" action of the chosen key. You may be concerned about the key littering the login input on TTY1, or even password, if Enter gets hit. This may lead to login attempts. Workarounds:
switch to unused TTY;
[email protected] (see this; I haven't tested this though, I don't know if the OS doesn't switch to a used one automatically);
run some custom command instead (like in this answer, also not tested by me).
Pay attention as what user the relevant services run. There are also
ProtectSystem= options. These (along with few others) will limit what your script can do. And if some filesystem is encrypted or unmounted, the script won't be able to use it until it gets mounted properly (e.g. if your home directory gets decrypted as late as at the moment you log in, the script won't be able to interact with it until you log in).