我想用python xlib捕获keydown和keyup事件,但是当同时按下某些键时,keyup事件会消失。
如果同时释放2个或更多键,则会有2个或更多个按键事件,但只有1个键释放事件。
为了实现这一点,甚至不必同时释放按键,例如,如果您快速输入此序列:
只能为A
提供1个密钥释放将产生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()
答案 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事件(可能有一种方法可以防止这种情况发生,但对于我的用例而言并不重要...)