Trigger an event when clipboard content changes
Have you thought about using an endless loop and "sleeping" between tries?I used pyperclip for a simple PoC and it worked like a charm, and Windows and Linux.
import timeimport sysimport ossys.path.append(os.path.abspath("SO_site-packages"))import pypercliprecent_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)
Instead of the print
, do whatever you want. If you need help with multithreading to put this into a background thread, please tell me.
EDIT
Here is a complete multithreading example.
import timeimport threadingimport pyperclipdef is_url_but_not_bitly(url): if url.startswith("http://") and not "bit.ly" in url: return True return Falsedef 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 = Truedef 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() breakif __name__ == "__main__": main()
I create a subclass of threading.Thread, override the methods run
and __init__
and create an instance of this class. By calling watcher.start()
(not run()
!), you start the thread.
To safely stop the thread, I wait for -c (Keyboard-interrupt) and tell the thread to stop itself.
In the initialization of the class, you also have a parameter pause
to control how long to wait between tries.
Use the class ClipboardWatcher like in my example, replace the callback with what you do, e.g., lambda x: bitly(x, username, password)
.
Looking at pyperclip
the meat of it on Macosx is :
import osdef 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
These work for me how do you get on?
I don't quite follow your comment on being in a loop.
EDIT Added 'orrid polling example that shows how changeCount()
bumps up on each copy
to the pasteboard. It's still not what the OP wants as there seems no event or notification for modifications to the NSPasteboard
.
from LaunchServices import *from AppKit import *import osfrom threading import Timerdef 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()
simple!
import osdef 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 contentcurrent_clipboard = macGetClipboard()while True: clipboard = macGetClipboard() if clipboard != current_clipboard: print(clipboard) macSetClipboard("my new string") print(macGetClipboard()) break