python xlib xgrabkey keyrelease事件未触发

时间:2013-08-10 10:00:05

标签: python input xlib

我想用python xlib捕获keydown和keyup事件,但是当同时按下某些键时,keyup事件会消失。

如果同时释放2个或更多键,则会有2个或更多个按键事件,但只有1个键释放事件。

为了实现这一点,甚至不必同时释放按键,例如,如果您快速输入此序列:

  1. 按A
  2. 按B
  3. 发布A
  4. 发布B
  5. 只能为A

    提供1个密钥释放
    1. 按A
    2. 按B
    3. 发布B
    4. 发布A
    5. 将产生2个关键释放

      from Xlib import X,XK
      from Xlib.display import Display
      import signal,sys
      
      root = None
      display = None
      
      def grab_keyname(n):
          global root
          keysym = XK.string_to_keysym(n)
          keycode = display.keysym_to_keycode(keysym)
          root.grab_key(keycode, X.AnyModifier, False,X.GrabModeSync, X.GrabModeAsync)
      
      def main():
          # current display
          global display,root
          display = Display()
          root = display.screen().root
      
      
          root.change_attributes(event_mask = X.KeyPressMask|X.KeyReleaseMask)
      
          grab_keyname("j")
          grab_keyname("k")
          grab_keyname("l")
      
          signal.signal(signal.SIGALRM, lambda a,b:sys.exit(1))
          signal.alarm(4)
      
          while True:
              event = display.next_event()
              print event.type
      
      main()
      

1 个答案:

答案 0 :(得分:1)

即使这个问题已有7年历史了,对任何绊脚石的解决方案:

这是Xorg中的一个“错误”(显然是故意的),它导致键盘释放在按键释放时停止,并仅在再次按下按钮时才重新开始。因此,介于两者之间的任何事件(->第二个键释放事件)都将丢失。参见https://bugs.freedesktop.org/show_bug.cgi?id=99280

建议的解决方案是有一个计数器,该计数器指示仍然按下了多少键,如果仍然有待按下的键,则手动抓住键盘。另外,在上次发布事件结束后,键盘需要取消锁定。

实现可能如下所示:

keys_pressed = 0
# ...
event = display.next_event()
if event.type == X.KeyPress:
    keys_pressed += 1
elif event.type == X.KeyRelease:
    if keys_pressed != 0:
        keys_pressed -= 1
        if keys_pressed == 0:
            display.flush()
            display.ungrab_keyboard(X.CurrentTime)
        else:
            root.grab_keyboard(False, X.GrabModeAsync, X.GrabModeAsync, X.CurrentTime)

请注意对release分支中的keys_pressed != 0进行检查:这是因为在取消键盘松动之后,又捕获了一个另外的release事件(可能有一种方法可以防止这种情况发生,但对于我的用例而言并不重要...)