/home/posts/hotkeys-grabbed

Determining which Process is Grabbing your Keys

Published on

#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:

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.

Meet the Author

John Allbritten

Nashville, TN

I love learning new technologies, and I have a passion for open source. As I learn things, my notes turn into articles to share.

Related Posts