不捕获键盘事件的情况下如何监听?

14

我正在编写一个命令行应用程序,它监听 X Windows 中的 Control 键释放事件,并在检测到这些事件时向另一个进程发出警报。

作为一名 GNU/Linux 新手,我想避免使用 GCC,并寻找基于脚本的解决方案。由于我了解一些 Python,因此选择基于 Python 的解决方案似乎是很自然的选择。经过在 Internet 上搜集示例和阅读 Python Xlib 文档后,我已经编写出了这个程序,它可以工作,但有一个缺点:它会捕获事件而不是仅仅监听它们(我的意思是这些事件不再传递给最初面向的应用程序)。

通过运行 "xev",我已经追踪到了 Control 键代码。由于我重新映射了我的修饰键,在您的系统上它们可能是不同的。

为了保持简单,我省略了处理外部进程的代码。

谢谢您的帮助。

软件:

  • Python 2.7.2

  • Python Xlib 0.15 RC1

  • Perl v5.10.1

  • Debian GNU/Linux 版本:6.0.3

  • 内核版本:Linux debian 2.6.32-5-686

编辑:我无法理解的是,除非它们被处理(在我的程序中,这意味着执行 'print "KeyRelease"' 这一行),否则键盘事件不会被捕获。由于在我的代码中我既没有调用任何 Xlib 的方法,也没有调用事件对象上的任何方法,所以我不明白处理差异出在哪里。

编辑2:除使用 Xlib 外,关于替代方案的建议也受欢迎。

编辑3:我也知道 Perl,并且欢迎有关可以帮助的 Perl 库的建议,只要它们不需要最新版本的系统库,因为 Debian 在其存储库中可用的软件包显然滞后,并且如果它们有许多依赖项,编译和安装最新版本的库可能很困难(我尝试安装 PyGTK,但在无法引用我已安装的最新 GLib 后放弃了)。

    #!/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)
4个回答

13

感谢Croad Langshan提到的pykeylogger库以及该库作者Tim Alexander提供的有用示例代码,我已经成功将我的程序更改为:

    #!/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()

这个程序可以完美地达到我的目标,没有任何问题。您可以阅读“event”对象的字段以获取有关事件的更多信息(请参见“pyxhook.py”的源代码)。


2
你需要使用 XRecord 扩展。它可以与 pyxlib 一起使用(其他答案中提到的 pykeylogger 使用此扩展),或者通过 ctypes 包装 libX11 和 libXtst(就像我在 synaptiks 中所做的那样)。
但是请注意,使用 xrecord 进行编程(在某种程度上也适用于 XLib 总体)有些困难,因为 API 文档很差,而且相当古怪和反直觉。

谢谢。我会研究XRecord。然而,我在我的问题中添加了一些注释,因为我认为解决方案就在眼前,因为我的代码没有捕获所有事件。 - Raffaele Ricciardi

1

你的评论让我能够回答我的问题。谢谢。 - Raffaele Ricciardi

1
请注意,XRecord扩展在一些发行版中仍然存在问题。我有一段时间没有更新过该库的原因是它在Ubuntu的多个版本中出现了问题。据说也可以通过XInput覆盖来完成,但我从未追求过这一点,因为我不想使用覆盖而是直接钩住X事件。
如果在使用pyxhook库中的代码时出现任何问题,请回复评论,我尽可能地使它简单/健壮,但在组合代码时可能会有遗漏。那是很久以前的事情了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接