我想用 python xlib 捕获 keydown 和 keyup 事件,但是当同时按下某些键时,keyup 事件会消失。
如果同时释放 2 个或更多键,则将有 2 个或更多按键事件,但只有 1 个按键释放事件。
为此,甚至不必同时释放键,例如,如果您快速输入此序列:
将只为 A 产生 1 个密钥释放
将产生 2 个 keyreleases
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()
Run Code Online (Sandbox Code Playgroud)
尽管这个问题已经有 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)
Run Code Online (Sandbox Code Playgroud)
请注意发布分支中的检查keys_pressed != 0:这是因为在松开键盘后,会捕获一个额外的发布事件(可能有一种方法可以防止这种情况,但这对我的用例来说并不重要......)
| 归档时间: |
|
| 查看次数: |
865 次 |
| 最近记录: |