I'm using the following lines in my ~/.xprofile
on Ubuntu 20.04 to map Capslock to ESC and Ctrl:
# make CapsLock behave like Ctrl:
setxkbmap -option ctrl:nocaps
# make short-pressed Ctrl behave like Escape:
xcape -e 'Control_L=Escape'
which works perfectly fine for me.
My issue is that it does not survive suspend/resume reliably. For this, I've tried 2 different solutions:
1. Via a script capsmap
put into /usr/lib/systemd/system-sleep/
#!/bin/bash
case "$1" in
pre)
#code execution BEFORE sleeping/hibernating/suspending
;;
post)
#code execution AFTER resuming
/usr/bin/echo "executing: /usr/bin/setxkbmap -option ctrl:nocaps"
/usr/bin/setxkbmap -option ctrl:nocaps
/usr/bin/echo "executing: /usr/bin/xcape -e 'Control_L=Escape'"
/usr/bin/xcape -e 'Control_L=Escape'
;;
esac
exit 0
I've made the script executable with sudo chmod +x capsmap
and can see from the logs that it is called at the appropriate time:
$ journalctl
...
Okt 09 13:29:12 nb systemd-sleep[401221]: System resumed.
Okt 09 13:29:12 nb kernel: Bluetooth: hci0: Device revision is 5
Okt 09 13:29:12 nb kernel: Bluetooth: hci0: Secure boot is enabled
Okt 09 13:29:12 nb kernel: Bluetooth: hci0: OTP lock is enabled
Okt 09 13:29:12 nb kernel: Bluetooth: hci0: API lock is enabled
Okt 09 13:29:12 nb kernel: Bluetooth: hci0: Debug lock is disabled
Okt 09 13:29:12 nb kernel: Bluetooth: hci0: Minimum firmware build 1 week 10 2014
Okt 09 13:29:12 nb kernel: Bluetooth: hci0: Found device firmware: intel/ibt-11-5.sfi
Okt 09 13:29:12 nb systemd-sleep[401287]: executing: /usr/bin/setxkbmap -option ctrl:nocaps
Okt 09 13:29:12 nb systemd-sleep[401288]: Cannot open display "default display"
Okt 09 13:29:12 nb systemd-sleep[401291]: executing: /usr/bin/xcape -e 'Control_L=Escape'
Okt 09 13:29:12 nb systemd-sleep[401293]: Unable to connect to X11 display. Is $DISPLAY set?
Okt 09 13:29:12 nb systemd[1]: systemd-suspend.service: Succeeded.
Okt 09 13:29:12 nb systemd[1]: Finished Suspend.
Okt 09 13:29:12 nb systemd[1]: Stopped target Sleep.
Okt 09 13:29:12 nb systemd[1]: Reached target Suspend.
Okt 09 13:29:12 nb systemd[1]: Stopped target Suspend.
...
However, the mapping only sometimes applies. Quite often, Capslock just behaves as normal.
2. Via a systemd service
I've added a service file capsmap.service
to etc/systemd/system/
with the following content:
[Unit]
Description=Map Capslock to ESC and Ctrl
After=suspend.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/capsmap
TimeoutSec=0
StandardOutput=syslog
[Install]
WantedBy=multi-user.target suspend.target
with the file /usr/local/bin/capsmap
as
#!/bin/bash
# make CapsLock behave like Ctrl:
/usr/bin/echo "executing: /usr/bin/setxkbmap -option ctrl:nocaps"
/usr/bin/setxkbmap -option ctrl:nocaps
# make short-pressed Ctrl behave like Escape:
/usr/bin/echo "executing: /usr/bin/xcape -e 'Control_L=Escape'"
/usr/bin/xcape -e 'Control_L=Escape'
exit 0
then enabled the service with sudo systemctl enable capsmap.service
.
Also in this case, I can see with journalctl
that the script was executed successfully, but the normal Capslock behavior is still present.
$journalctl
...
Okt 09 13:07:56 nb systemd[1]: Stopped target Suspend.
Okt 09 13:07:56 nb NetworkManager[1049]: <info> [1633777676.0331] manager: sleep: wake requested (sleeping: yes enabled: yes)
Okt 09 13:07:56 nb ModemManager[1137]: <info> [sleep-monitor] system is resuming
Okt 09 13:07:56 nb NetworkManager[1049]: <info> [1633777676.0332] device (enp0s31f6): state change: activated -> unmanaged (reason 'sleeping', sys-iface-state: 'managed')
Okt 09 13:07:56 nb systemd[1761]: Stopped target Bluetooth.
Okt 09 13:07:56 nb upowerd[1344]: treating change event as add on /sys/devices/pci0000:00/0000:00:14.0/usb1/1-8
Okt 09 13:07:56 nb capsmap[378798]: executing: /usr/bin/setxkbmap -option ctrl:nocaps
Okt 09 13:07:56 nb systemd[1761]: Reached target Bluetooth.
Okt 09 13:07:56 nb NetworkManager[1049]: <info> [1633777676.0498] dhcp4 (enp0s31f6): canceled DHCP transaction
Okt 09 13:07:56 nb capsmap[378799]: Cannot open display "default display"
Okt 09 13:07:56 nb NetworkManager[1049]: <info> [1633777676.0498] dhcp4 (enp0s31f6): state changed bound -> done
Okt 09 13:07:56 nb avahi-daemon[1041]: Withdrawing address record for 192.168.178.54 on enp0s31f6.
Okt 09 13:07:56 nb avahi-daemon[1041]: Leaving mDNS multicast group on interface enp0s31f6.IPv4 with address 192.168.178.54.
Okt 09 13:07:56 nb avahi-daemon[1041]: Interface enp0s31f6.IPv4 no longer relevant for mDNS.
Okt 09 13:07:56 nb avahi-daemon[1041]: Withdrawing address record for fe80::778b:d324:d55d:a503 on enp0s31f6.
Okt 09 13:07:56 nb avahi-daemon[1041]: Leaving mDNS multicast group on interface enp0s31f6.IPv6 with address fe80::778b:d324:d55d:a503.
Okt 09 13:07:56 nb avahi-daemon[1041]: Interface enp0s31f6.IPv6 no longer relevant for mDNS.
Okt 09 13:07:56 nb systemd[1]: Started Load/Save RF Kill Switch Status.
Okt 09 13:07:56 nb capsmap[378800]: executing: /usr/bin/xcape -e 'Control_L=Escape'
Okt 09 13:07:56 nb NetworkManager[1049]: <info> [1633777676.0545] manager: NetworkManager state is now CONNECTED_GLOBAL
Okt 09 13:07:56 nb capsmap[378805]: Unable to connect to X11 display. Is $DISPLAY set?
Okt 09 13:07:56 nb kernel: kauditd_printk_skb: 9 callbacks suppressed
Okt 09 13:07:56 nb kernel: audit: type=1107 audit(1633777676.068:1737): pid=1047 uid=103 auid=4294967295 ses=4294967295 subj=unconfined msg='apparmor="DENIED" operation="dbus_signal" bus="system" path="/org/freedesktop/NetworkManager/ActiveConnection/30" interface="org.fr>
exe="/usr/bin/dbus-daemon" sauid=103 hostname=? addr=? terminal=?'
Okt 09 13:07:56 nb kernel: audit: type=1107 audit(1633777676.068:1738): pid=1047 uid=103 auid=4294967295 ses=4294967295 subj=unconfined msg='apparmor="DENIED" operation="dbus_signal" bus="system" path="/org/freedesktop/NetworkManager/ActiveConnection/30" interface="org.fr>
exe="/usr/bin/dbus-daemon" sauid=103 hostname=? addr=? terminal=?'
Okt 09 13:07:56 nb audit[1047]: USER_AVC pid=1047 uid=103 auid=4294967295 ses=4294967295 subj=unconfined msg='apparmor="DENIED" operation="dbus_signal" bus="system" path="/org/freedesktop/NetworkManager/ActiveConnection/30" interface="org.freedesktop.NetworkManager.Connec>
exe="/usr/bin/dbus-daemon" sauid=103 hostname=? addr=? terminal=?'
Okt 09 13:07:56 nb audit[1047]: USER_AVC pid=1047 uid=103 auid=4294967295 ses=4294967295 subj=unconfined msg='apparmor="DENIED" operation="dbus_signal" bus="system" path="/org/freedesktop/NetworkManager/ActiveConnection/30" interface="org.freedesktop.NetworkManager.Connec>
exe="/usr/bin/dbus-daemon" sauid=103 hostname=? addr=? terminal=?'
Okt 09 13:07:56 nb systemd[1]: capsmap.service: Succeeded.
...