Trigger an event when clipboard content changes

前端 未结 2 1233
轮回少年
轮回少年 2020-12-13 01:03

I\'m trying to get the clipboard content using a Python script on my Mac Lion.

I\'m searching for an event or something similar, because if I use a loop, my applicat

相关标签:
2条回答
  • 2020-12-13 01:48

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

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

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

    0 讨论(0)
  • 2020-12-13 01:48

    Looking at pyperclip the meat of it on Macosx is :

    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
    

    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 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()
    
    0 讨论(0)
提交回复
热议问题