Skip to content
Advertisement

Listening for global key-combinations in python on Linux

I just wrote a little program which downloads a new wallpaper from flickr every few minutes.

Now I want to add the capability to “like” a wallpaper, so it will occur more often than non-liked or disliked wallpapers.

I’d like to assign a global keyboard-shortcut to this function.

For example: If I press ctrl+7, it would execute some kind of “like” function in Python.

Are there any libraries for this (in JavaScript for example there’s a library where I can define shortcuts with shortcut("ctrl-b", someFunction);)

Otherwise, how would I go round doing this? I’ve seen this similar SO question, but it’s old.

Advertisement

Answer

I do not know of any libraries that are designed to be extended. However as your link stated the backend of pykeylogger gives an example of how to do it, but it does seem a little overcomplicated for you would need.

pykeylogger uses the python-xlib module to capture keypresses on the X display. Someone has already created a lighter example of how to go through this on pastebin. Below is the source from it copied here as-is.

from Xlib.display import Display
from Xlib import X
from Xlib.ext import record
from Xlib.protocol import rq

disp = None

def handler(reply):
    """ This function is called when a xlib event is fired """
    data = reply.data
    while len(data):
        event, data = rq.EventField(None).parse_binary_value(data, disp.display, None, None)

        # KEYCODE IS FOUND USERING event.detail
        print(event.detail)

        if event.type == X.KeyPress:
            # BUTTON PRESSED
            print("pressed")
        elif event.type == X.KeyRelease:
            # BUTTON RELEASED
            print("released")

# get current display
disp = Display()
root = disp.screen().root

# Monitor keypress and button press
ctx = disp.record_create_context(
            0,
            [record.AllClients],
            [{
                    'core_requests': (0, 0),
                    'core_replies': (0, 0),
                    'ext_requests': (0, 0, 0, 0),
                    'ext_replies': (0, 0, 0, 0),
                    'delivered_events': (0, 0),
                    'device_events': (X.KeyReleaseMask, X.ButtonReleaseMask),
                    'errors': (0, 0),
                    'client_started': False,
                    'client_died': False,
            }])
disp.record_enable_context(ctx, handler)
disp.record_free_context(ctx)

while 1:
    # Infinite wait, doesn't do anything as no events are grabbed
    event = root.display.next_event()

You will have to extend the handler to fit your needs for instead of just printing to screen, and then make it into a separate thread.

The (painful) alternative is to listen to the keyboard directly, without relying on external libraries or the X session. In linux everything is a file and your keyboard input will be in /dev/input that you could read as a file, for example open('/dev/input/even2', 'rb'), in the background. This is not suggested as it requires escalated permissions, figuring out which device is the keyboard, and then create your own keymapping. Just wanted to let you know what’s possible if necessary.

Edit: Also found Global keybinding on X using Python gtk3 which seems to have more example goodness.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement