2012-02-08 20 views
14

Estoy escribiendo una aplicación de línea de comandos que escucha los eventos de liberación de la tecla Control en X Windows y alerta a otro proceso cuando los detecta.¿Escuchando eventos de teclado sin atraparlos?

Siendo nuevo en GNU/Linux, preferiría evitar perder el tiempo con GCC y, por lo tanto, estoy buscando una solución basada en scripts. Como conozco un poco de Python, me pareció natural buscar una solución basada en Python, y después de buscar en Internet ejemplos y leer documentos de Python Xlib, he creado estos programas que funcionan, pero con una advertencia: atrapa eventos en lugar de solo escucharlos (me refiero a que dichos eventos ya no se pasan a la aplicación a la que fueron dirigidos en primer lugar).

He rastreado los códigos de las teclas de control ejecutando "xev". Como he reasignado mis teclas modificadoras, en su sistema pueden ser diferentes.

Para simplificar, he omitido el código que trata sobre el proceso externo.

Gracias por su ayuda.

software:

  • Python 2.7.2

  • Python Xlib 0.15 RC1

  • Perl v5.10.1

    versión
  • Debian GNU/Linux: 6.0.3

  • Kernel v ersion: Debian Linux 2.6.32-5-686

EDIT: Lo que no puedo entender es que los eventos de teclado no se quedan atrapados menos que se transformen (en mis programas, esto significa que la línea de 'imprimir "KeyRelease" se ejecuta). Como en mi código no invoco ningún método ni en Xlib ni en el objeto de evento, no entiendo dónde se encuentra la diferencia de procesamiento.

EDIT2: Sugerencias sobre soluciones alternativas además de usar Xlib también son bienvenidas.

EDIT3: conozco Perl y también son bienvenidas las sugerencias sobre bibliotecas Perl que pueden ser útiles, siempre que no requieran versiones recientes de bibliotecas de sistemas, ya que Debian se retrasa notoriamente en cuanto a paquetes disponibles en su repositorios, y la compilación e instalación de las últimas versiones de las bibliotecas puede ser difícil si tienen muchas dependencias (he intentado instalar PyGTK, pero renuncié después de no hacer referencia a un GLib actualizado que había instalado).

#!/usr/bin/env python 

    from Xlib.display import Display 
    from Xlib import X 

    Control_R = 64 # Keycode for right Control. 
    Control_L = 108 # Keycode for left Control. 
    keycodes = [Control_R, Control_L] # Keycodes we are listening for. 

    # Handle X events. 
    def handle_event(event): 
     # Let us know whether this event is about a Key Release of 
     # one of the key we are interest in. 
     if event.type == X.KeyRelease: 
      keycode = event.detail 
      if keycode in keycodes: 
       print "KeyRelease" 

    # Objects needed to call Xlib. 
    display = Display() 
    root = display.screen().root 

    # Tell the X server we want to catch KeyRelease events. 
    root.change_attributes(event_mask = X.KeyReleaseMask) 

    # Grab those keys. 
    for keycode in keycodes: 
     root.grab_key(keycode, X.AnyModifier, 1, X.GrabModeAsync, X.GrabModeAsync) 

    # Event loop. 
    while 1: 
     event = root.display.next_event() 
     handle_event(event) 

Respuesta

2

Es necesario utilizar la extensión XRecord. Se puede usar con pyxlib (pykeylogger mencionado en la otra respuesta usa esto), o envolviendo libX11 y libXtst a través de ctypes (como lo hice en synaptiks).

Sin embargo, tenga en cuenta que la programación con xrecord (y hasta cierto punto también con XLib en general) es bastante difícil, porque la API está mal documentada, y es bastante barroca y contra-intuitiva.

+0

Gracias. Buscaré en XRecord. Sin embargo, agregué un par de notas a mi pregunta porque me parece que hay una solución a la vuelta de la esquina, ya que mi código no atrapa todos los eventos. –

11

Gracias a la biblioteca pykeylogger mencionado por Croad Langshan, y el código de ejemplo de utilidad proporcionada por Tim Alexander, el autor de dicha biblioteca, he sido capaz de cambiar mi programa para:

#!/usr/bin/env python 

    from pyxhook import HookManager 

    watched_keys = ["Control_R", "Control_L"] 

    def handle_event (event): 
     if event.Key in watched_keys: 
      print "KeyRelease" 


    hm = HookManager() 
    hm.HookKeyboard() 
    hm.KeyUp = handle_event 
    hm.start() 

Este programa logra mi objetivo sin ningún problema. Puede leer los campos del objeto "evento" para obtener más información sobre el evento (consulte el código fuente de "pyxhook.py").

1

Tenga en cuenta que la extensión XRecord continúa interrumpida en unas pocas distribuciones. La razón por la que no había vuelto atrás y actualicé esa biblioteca por un tiempo fue porque se rompió en Ubuntu para varias versiones. Hay una manera de hacerlo también con una superposición de XInput, (me dijeron) pero nunca lo hice porque no quería tratar con una superposición en lugar de conectar los eventos X directamente.

Comenta de nuevo si hay algún problema con el uso del código en pyxhook lib, intenté hacerlo tan simple/robusto como sea posible, pero es posible que haya extrañado cosas al armarlo. Fue hace un tiempo.

Cuestiones relacionadas