#Introduction to Hotkeys
On most modern Linux systems, the Desktop Environment (e.g. Gnome, KDE) handles hotkeys: mapping single keys, or keyboard combinations, to do certain things. Some common hotkey examples are:
- The “Mute Audio” key (available on most laptops) mutes the audio output.
Alt + Tab
switches between your open windowsSuper + T
opens up a terminal
If you don’t run a Desktop Environment and instead just run a window manager (e.g. bspwm
, i3
, openbox
) like me, you may find yourself configuring your own hotkeys. Since I run sxhkd
, the “simple X hotkey daemon,” (pro tip: it’s not simple) to manage my hotkeys.
Regardless of your setup, it’s sometimes annoying when you want to customize what a hotkey does, only to find out that some process is grabbing that hotkey and preventing you from using it.
#Error Messages in sxhkd
An example of this hotkey conflict is shown when starting sxhkd
:
Could not grab key 121 with modfield 0: the combination is already grabbed.
Could not grab key 122 with modfield 0: the combination is already grabbed.
Could not grab key 123 with modfield 16: the combination is already grabbed.
As it pretty clearly states, some other process has “already grabbed” some of the hotkeys you’re trying to use. Specifically, keycodes 121, 122, and 123, which just so happen to be my laptop’s volume keys. Later on we’ll talk about what a keycode means.
#Accessing Logs to Find the Processes
To find out which processes are grabbing which keys, we need to read some system logs. The log we’re looking for will be in different places depending on how your system is set up. It may be logged in one or both of these places:
#1. Xorg Log
If you’re running X
, you can check the Xorg
logs. To find the location of your Xorg
log, run:
bash
$ lsof -c Xorg | grep ".log"
Xorg 1234 user 7w REG 123,4 1234567 1234567 /home/user/.local/share/xorg/Xorg.0.log
Within the output, you should see a path like /home/user/.local/share/xorg/Xorg.0.log
. Once you have this path, you can watch updates to the log using tail -f
like so:
bash
$ tail -f /home/user/.local/share/xorg/Xorg.0.log
In addition, you can pipe the output to less
to be able to search it, which may come in handy:
bash
$ tail -f /home/user/.local/share/xorg/Xorg.0.log | less
#2. journald
Log
If you’re on a system that uses the systemd
init system (most modern systems do), the information you’re looking for is logged using journald
. You can use journalctl
to access and read the journal:
bash
$ journalctl -f
The -f
flag “continuously prints new entires as they are appended to the journal.” (man journalctl
)
#Identifying the Keycode
You must know the keycode of the key in question. The easiest way to find the key’s keycode is using the xev
program:
bash
$ xev
xev
will open a blank, white window and record everything you press. Press the key you want to check (in my case it was my laptop’s “mute audio” key).
Once you’ve pressed the key, you will see output in the terminal running xev
that looks like this (you may have to scroll up):
bash
KeyRelease event, serial 30, synthetic NO, window 0xc000001,
root 0x1a2, subw 0x0, time 147487441, (-1333,-530), root:(590,562),
state 0x0, keycode 121 (keysym 0x1008ff12, XF86AudioMute), same_screen YES,
XLookupString gives 0 bytes:
XFilterEvent returns: False
As stated in the output, the key is called XF86AudioMute
, and the keycode is 121
.
#Logging the Key Grabs
Whichever way you’ve chosen to read the logs, the information is the same. Now that you’ve opened and are watching the logs with either tail -f
or journalctl -f
, we need to fill the log with information on your system’s current key grabs.
There is a special key in X
called XF86LogGrabInfo
that allows you to log all grab information about your keys. No keyboard has a physical XF86LogGrabInfo
key that you can press, so you have to simulate pressing it using xdotool
while at the same time simulating the key you want to press:
bash
$ KEYCODE=121
$ xdotool keydown $KEYCODE; xdotool key XF86LogGrabInfo; xdotool keyup $KEYCODE
$KEYCODE
contains the keycode we found earlier.
#Analyzing Logs to Identify Process
Now, look at your logs. Search for activating key <keycode>
where <keycode>
is the keycode you found earlier.
Hint: if you’re viewing the log in
less
, you can hit/
to search for a string.
bash
Active grab 0x41a0a67f (core) on device 'Virtual core keyboard' (3):
[123456.123] client pid 2737 /usr/bin/kglobalaccel5
[123456.123] at 147059396 (from passive grab) (device frozen, state 6)
[123456.123] core event mask 0x3
[123456.123] passive grab type 2, detail 0x79, activating key 121
[123456.123] owner-events true, kb 0 ptr 1, confine 0, cursor 0x0
In my example, the keycode I was looking for was 121
, and it’s clear that pid 2737 /usr/bin/kglobalaccel5
is the program that’s currently grabbing that key. You can do some research and see why the program is grabbing that key.
#Conclusion
You can use this method to determine which pid’s/processes are grabbing your keys. For those of you that use sxhkd
, you may have to kill these processes in order to use those keys in a hotkey.