Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Listening to keyboard events without trapping them?

I'm writing an command-line application which listens for Control key release events in X Windows and alerts another process when it detects them.

Being new to GNU/Linux, I'd prefer avoiding to fumble with GCC and therefore I'm looking for a scripting-based solution. Since I know a bit of Python, it seemed natural to go for a Python-based solution, and after scavenging the Internet for examples and reading Python Xlib docs, I've put together this programs which works, but with a caveat: it traps events instead of just listening for them (I mean such events are not passed anymore to the application which they were directed to in the first place).

I've tracked down Control key codes by running "xev". Since I've remapped my modifier keys, on your system they may be different.

To keep things simple, I've left out the code which deals with the external process.

Thank you for your help.

Software:

  • Python 2.7.2

  • Python Xlib 0.15 RC1

  • Perl v5.10.1

  • Debian GNU/Linux version: 6.0.3

  • Kernel version: Linux debian 2.6.32-5-686

EDIT: What I can't figure out is that keyboard events do not get trapped unless they are processed (in my programs, this means the line 'print "KeyRelease"' gets executed). Since in my code I don't call any method either on Xlib or on the event object, I don't understand where the difference in processing lies.

EDIT2: Suggestions about alternative solutions besides using Xlib are also welcome.

EDIT3: I know Perl too, and suggestions about Perl libraries which could help are welcome too, as long as they don't require recent versions of system libraries, since Debian notoriously lags behind when it comes to packages available in its repositories, and compiling and installing last versions of libraries can be difficult if they have many dependencies (I've tried installing PyGTK, but gave up after failing to reference an up-to-date GLib I had installed).

    #!/usr/bin/env python

    from Xlib.display import Display
    from Xlib import X

    Control_R  = 64 # Keycode for right Control.
    Control_L  = 108 # Keycode for left Control.
    keycodes = [Control_R, Control_L] # Keycodes we are listening for.

    # Handle X events.
    def handle_event(event):
        # Let us know whether this event is about a Key Release of
        # one of the key we are interest in.
        if event.type == X.KeyRelease:
            keycode = event.detail
            if keycode in keycodes:
                print "KeyRelease"

    # Objects needed to call Xlib.
    display = Display()
    root = display.screen().root

    # Tell the X server we want to catch KeyRelease events.
    root.change_attributes(event_mask = X.KeyReleaseMask)

    # Grab those keys.
    for keycode in keycodes:
        root.grab_key(keycode, X.AnyModifier, 1, X.GrabModeAsync, X.GrabModeAsync)

    # Event loop.
    while 1:
        event = root.display.next_event()
        handle_event(event)
like image 295
Raffaele Ricciardi Avatar asked Feb 08 '12 23:02

Raffaele Ricciardi


People also ask

How do I use keyboard events?

There are three different keyboard events in JavaScript: keydown : Keydown happens when the key is pressed down, and auto repeats if the key is pressed down for long. keypress : This event is fired when an alphabetic, numeric, or punctuation key is pressed down. keyup : Keyup happens when the key is released.

What are the keyboard event fired?

Explanation: The keydown and keyup are the keyboard events are fired when the user presses or releases a key on the keyboard. They are generated for modifier keys, function keys, and alphanumeric keys. 2.

When you trigger a key in a keyboard What value does it return?

The keyboard event object has two important properties: key and code properties that allow you to detect which key has been pressed. The key property returns the value of the key pressed while the code represents a physical key on the keyboard.


2 Answers

Thanks to the pykeylogger library mentioned by Croad Langshan, and to the helpful example code provided by Tim Alexander, the author of such library, I've been able to change my program to:

    #!/usr/bin/env python

    from pyxhook import HookManager

    watched_keys = ["Control_R", "Control_L"]

    def handle_event (event):
        if event.Key in watched_keys:
            print "KeyRelease"


    hm = HookManager()
    hm.HookKeyboard()
    hm.KeyUp = handle_event
    hm.start()

This program accomplishes my goal without any issue. You can read the fields of the "event" object for further information about the event (see source code of "pyxhook.py").

like image 69
Raffaele Ricciardi Avatar answered Sep 21 '22 08:09

Raffaele Ricciardi


You need to use the XRecord extension. It can be used with pyxlib (pykeylogger mentioned in the other answer uses this), or by wrapping libX11 and libXtst via ctypes (as I did in synaptiks).

Note however, that programming with xrecord (and to some degree also with XLib in general) is somehwat hard, because the API is badly documented, and quite baroque and counter-intuitive.

like image 39
lunaryorn Avatar answered Sep 22 '22 08:09

lunaryorn