Desencadenar un evento cuando cambia el contenido del portapapeles

Estoy tratando de obtener el contenido del portapapeles utilizando un script Python en mi Mac Lion.

Estoy buscando un evento o algo similar, porque si uso un bucle, mi aplicación pasa todo el tiempo mirando el portapapeles.

¿Algunas ideas?

¿Has pensado en usar un bucle sin fin y “dormir” entre bashs? Utilicé pyperclip para un simple PoC y funcionó como un encanto, y Windows y Linux.

import time import sys import os sys.path.append(os.path.abspath("SO_site-packages")) import pyperclip recent_value = "" while True: tmp_value = pyperclip.paste() if tmp_value != recent_value: recent_value = tmp_value print "Value changed: %s" % str(recent_value)[:20] time.sleep(0.1) 

En lugar de la print , haz lo que quieras. Si necesita ayuda con los subprocesos múltiples para poner esto en un hilo de fondo, por favor dígame.

EDITAR

Aquí hay un ejemplo completo de multiproceso.

 import time import threading import pyperclip def is_url_but_not_bitly(url): if url.startswith("http://") and not "bit.ly" in url: return True return False def print_to_stdout(clipboard_content): print "Found url: %s" % str(clipboard_content) class ClipboardWatcher(threading.Thread): def __init__(self, predicate, callback, pause=5.): super(ClipboardWatcher, self).__init__() self._predicate = predicate self._callback = callback self._pause = pause self._stopping = False def run(self): recent_value = "" while not self._stopping: tmp_value = pyperclip.paste() if tmp_value != recent_value: recent_value = tmp_value if self._predicate(recent_value): self._callback(recent_value) time.sleep(self._pause) def stop(self): self._stopping = True def main(): watcher = ClipboardWatcher(is_url_but_not_bitly, print_to_stdout, 5.) watcher.start() while True: try: print "Waiting for changed clipboard..." time.sleep(10) except KeyboardInterrupt: watcher.stop() break if __name__ == "__main__": main() 

Creo una subclase de subprocesos. __init__ , sobrescribo los métodos run y __init__ y creo una instancia de esta clase. Al llamar a watcher.start() (no run() !), watcher.start() el subproceso.

Para detener el hilo de forma segura, espero a que -c (Interrupción del teclado) y le diga al hilo que se detenga.

En la inicialización de la clase, también tiene una pause parámetro para controlar cuánto tiempo esperar entre bashs.

Use la clase ClipboardWatcher como en mi ejemplo, reemplace la callback con lo que hace, por ejemplo, lambda x: bitly(x, username, password) .

Código de Python 3 para la respuesta anterior ( https://stackoverflow.com/a/14687465/4258588 ):

 import time import sys import os sys.path.append(os.path.abspath("SO_site-packages")) import pyperclip recent_value = "" while True: tmp_value = pyperclip.paste() if tmp_value != recent_value: recent_value = tmp_value print("Value changed: %s" % str(recent_value)[:20]) time.sleep(0.1) 

PD: no podría agregarlo como un comentario debido a los puntos de baja reputación, así que estoy agregando esto como respuesta.

Mirar el pyperclip la carne en Macosx es:

 import os def macSetClipboard(text): outf = os.popen('pbcopy', 'w') outf.write(text) outf.close() def macGetClipboard(): outf = os.popen('pbpaste', 'r') content = outf.read() outf.close() return content 

Esto me funciona, ¿cómo te va?

No acabo de seguir tu comentario sobre estar en un bucle.


EDITAR Se agregó el ejemplo de ‘orrid polling’ que muestra cómo changeCount() topa con cada copy en la mesa de trabajo. Aún no es lo que quiere el OP, ya que no parece haber ningún evento o notificación de modificaciones al NSPasteboard .

 from LaunchServices import * from AppKit import * import os from threading import Timer def poll_clipboard(): pasteboard = NSPasteboard.generalPasteboard() print pasteboard.changeCount() def main(): while True: t = Timer(1, poll_clipboard) t.start() t.join() if __name__ == "__main__": main()