【问题标题】:Listening to keyboard events without trapping them?监听键盘事件而不捕获它们?
【发布时间】:2012-03-01 11:07:30
【问题描述】:

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

作为 GNU/Linux 的新手,我宁愿避免摸索 GCC,因此我正在寻找基于脚本的解决方案。由于我对 Python 有所了解,因此选择基于 Python 的解决方案似乎很自然,并且在搜索 Internet 以获取示例并阅读 Python Xlib 文档之后,我整理了这个可行的程序,但有一个警告:它陷阱事件而不是仅仅监听它们(我的意思是这些事件不再传递给它们最初被定向到的应用程序)。

我通过运行“xev”找到了控制键代码。由于我重新映射了修饰键,因此在您的系统上它们可能会有所不同。

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

感谢您的帮助。

软件:

  • 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 或事件对象上调用任何方法,所以我不明白处理的区别在哪里。

EDIT2:也欢迎提出关于使用 Xlib 之外的替代解决方案的建议。

EDIT3:我也知道 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)

【问题讨论】:

    标签: python perl keyboard-events xlib keyrelease


    【解决方案1】:

    感谢 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()
    

    这个程序毫无问题地完成了我的目标。您可以阅读“事件”对象的字段以获取有关事件的更多信息(参见“pyxhook.py”的源代码)。

    【讨论】:

      【解决方案2】:

      您需要使用 XRecord 扩展。它可以与 pyxlib 一起使用(其他答案中提到的 pykeylogger 使用这个),或者通过 ctypes 包装 libX11 和 libXtst(就像我在 synaptiks 中所做的那样)。

      但是请注意,使用 xrecord(在某种程度上也使用一般的 XLib)进行编程有些困难,因为 API 的文档记录很差,而且非常巴洛克且违反直觉。

      【讨论】:

      • 谢谢。我会调查XRecord。但是,我在我的问题中添加了一些注释,因为在我看来,解决方案指日可待,因为我的代码不会捕获所有事件。
      【解决方案3】:

      大概这个项目必须有解决这个问题的代码:

      http://sourceforge.net/apps/mediawiki/pykeylogger/index.php?title=Main_Page

      【讨论】:

      • 您的评论让我能够为我的问题制定答案。谢谢。
      【解决方案4】:

      请注意,XRecord 扩展在一些发行版中继续被破坏。我有一段时间没有回去更新那个库的原因是因为它在 Ubuntu 中被多个版本破坏了。也有一种方法可以使用 XInput 覆盖(有人告诉我),但我从未追求过,因为我不想处理覆盖而不是直接挂钩 X 事件。

      如果在使用 pyxhook 库中的代码时遇到任何问题,请回复评论,我试图使其尽可能简单/健壮,但是在将它们放在一起时我可能会遗漏一些东西。那是不久前的事了。

      【讨论】:

        猜你喜欢
        • 2014-09-01
        • 2011-07-25
        • 2018-04-15
        • 2021-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多