我想在普通键盘上实现关键的和弦,我想我使用的是python xlib。 为了使这个工作,程序必须全局吞下所有的关键事件,然后才允许它们通过。
我目前的测试只是抓住了“1”键。如果按下该键,它将调用一个处理程序,该处理程序通过xtest.fake_input将“x”发送到聚焦窗口。因为我只抓住“1”键,不应该有问题吧? 但不知何故,处理程序再次被调用,因为“x”被按下了。事实上,当我输入“1”时,程序正在监听所有键。 这可能与调用
有关display.allow_events(X.ReplayKeyboard, X.CurrentTime)
处理完事件后,如果我不这样做,一切都会冻结。
对于最终的程序,监听行为的变化并不真正相关,但我必须能够将虚假事件与用户事件区分开来。为了做到这一点,我只是快速转发display.next_event(),但这不是理想的,因为用户可能会在那个确切的时刻打字而且那些键击会丢失。
我尝试通过
发送和清空事件队列时释放keygrabdisplay.flush()
display.sync()
但这没有做任何事情。
所以,任何想法如何识别或忽略虚假输入事件以及为什么我突然听到所有按键(和发布)?
xlib非常令人沮丧。
from Xlib.display import Display
import Xlib
from Xlib import X
import Xlib.XK
import sys
import signal
display = None
root = None
def handle_event(aEvent):
print "handle!"
send_key("x")
def send_key(emulated_key):
global display,root
print "send key"
# ungrabbing doesnt help
root.ungrab_key(10,X.AnyModifier)
window = display.get_input_focus()._data["focus"]
# Generate the correct keycode
keysym = Xlib.XK.string_to_keysym(emulated_key)
keycode = display.keysym_to_keycode(keysym)
# Send a fake keypress via xtestaaa
Xlib.ext.xtest.fake_input(window, Xlib.X.KeyPress, keycode)
Xlib.ext.xtest.fake_input(window, Xlib.X.KeyRelease, keycode)
display.flush()
display.sync()
# fast forward those two events,this seems a bit hacky,
# what if theres another keyevent coming in at that exact time?
while display.pending_events():
display.next_event()
#
root.grab_key(10, X.AnyModifier, True,X.GrabModeSync, X.GrabModeSync)
def main():
# current display
global display,root
display = Display()
root = display.screen().root
# we tell the X server we want to catch keyPress event
root.change_attributes(event_mask = X.KeyPressMask)
# just grab the "1"-key for now
root.grab_key(10, X.AnyModifier, True,X.GrabModeSync, X.GrabModeSync)
# while experimenting everything could freeze, so exit after 10 seconds
signal.signal(signal.SIGALRM, lambda a,b:sys.exit(1))
signal.alarm(10)
while 1:
event = display.next_event()
print "event"
#if i dont call this, the whole thing freezes
display.allow_events(X.ReplayKeyboard, X.CurrentTime)
handle_event(event)
if __name__ == '__main__':
main()
答案 0 :(得分:5)
这是一个例子,它只在按键上吞下“1”键,并在keyrelease上发送“x”到焦点窗口:
from Xlib.display import Display
import Xlib
from Xlib import X
import Xlib.XK
import sys
import signal
import time
display = None
root = None
def handle_event(event):
print "handle!"
if (event.type == X.KeyRelease):
send_key("x")
# from http://shallowsky.com/software/crikey/pykey-0.1
def send_key(emulated_key):
shift_mask = 0 # or Xlib.X.ShiftMask
window = display.get_input_focus()._data["focus"]
keysym = Xlib.XK.string_to_keysym(emulated_key)
keycode = display.keysym_to_keycode(keysym)
event = Xlib.protocol.event.KeyPress(
time = int(time.time()),
root = root,
window = window,
same_screen = 0, child = Xlib.X.NONE,
root_x = 0, root_y = 0, event_x = 0, event_y = 0,
state = shift_mask,
detail = keycode
)
window.send_event(event, propagate = True)
event = Xlib.protocol.event.KeyRelease(
time = int(time.time()),
root = display.screen().root,
window = window,
same_screen = 0, child = Xlib.X.NONE,
root_x = 0, root_y = 0, event_x = 0, event_y = 0,
state = shift_mask,
detail = keycode
)
window.send_event(event, propagate = True)
def main():
# current display
global display,root
display = Display()
root = display.screen().root
# we tell the X server we want to catch keyPress event
root.change_attributes(event_mask = X.KeyPressMask|X.KeyReleaseMask)
# just grab the "1"-key for now
root.grab_key(10, 0, True,X.GrabModeSync, X.GrabModeSync)
signal.signal(signal.SIGALRM, lambda a,b:sys.exit(1))
signal.alarm(10)
while 1:
event = display.next_event()
print "event"
handle_event(event)
display.allow_events(X.AsyncKeyboard, X.CurrentTime)
if __name__ == '__main__':
main()