2013-08-04 10 views
5

voglio implementare accordi chiave su una tastiera normale e ho pensato di usare python xlib. affinché funzioni, il programma deve ingoiare globalmente tutti gli eventi chiave e solo in un secondo momento consentirne il passaggio.acquisisce globalmente, ignora e invia keyjevents con python xlib, riconosce l'input falso

il mio test corrente prende semplicemente il tasto "1". se questo tasto viene premuto, chiama un gestore che invia "x" alla finestra focalizzata tramite xtest.fake_input. perché sto solo prendendo il tasto "1", non dovrebbe esserci un problema, giusto? ma in qualche modo il gestore viene chiamato di nuovo, perché "x" è stato premuto. infatti, nel momento in cui digito "1" il programma sta ascoltando tutte le chiavi. questo potrebbe avere qualcosa a che fare con chiamando

display.allow_events(X.ReplayKeyboard, X.CurrentTime) 

dopo aver toccato un evento, ma se non faccio questo, tutto si blocca.

per il programma finale il cambiamento nel comportamento di ascolto non è veramente rilevante, ma devo essere in grado di distinguere gli eventi falsi dagli eventi utente. per fare questo sto solo facendo avanzare velocemente display.next_event(), ma questo non è l'ideale, perché l'utente potrebbe digitare in quel momento esatto e di quei tasti che andrebbero persi.

ho provato rilasciando il KeyGrab durante la trasmissione e lo svuotamento del EventQueue via

display.flush() 
display.sync() 

ma che non fa nulla.

quindi, qualche idea su come riconoscere o ignorare gli eventi di input falsi e perché sto improvvisamente ascoltando tutti i tasti premuti (e le versioni)?

xlib è molto frustrante.

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

risposta

4

ho trovato il problema. im quasi certo che xtest.fake_input fa qualcosa di strano, perché quando invio tasti e -releases manualmente (con qualche codice i found), funziona

ecco un esempio, che ingoia solo il tasto "1" sul tasto di pressione e invia "x" sulla rilasciare il tasto alla finestra focalizzata:

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() 
+0

Questo sembra bloccarsi in silenzio dopo un certo tempo o dopo il mashing 1 e altri tasti con repliche chiave (non può dire quale). Anche un altro utente ha segnalato questo, ma il suo commento è stato cancellato perché è stato pubblicato come risposta. – ninjagecko

+0

@ninjagecko Ho lo stesso problema. Inoltre non ho capito quale combinazione di tasti. Ma ho fallito dopo 20 minuti e dopo un minuto e mezzo. Sembra essere casuale o dipendente dall'uso della tastiera/del mouse. – Munchhausen

Problemi correlati