Trigger an event when clipboard content changes

怎甘沉沦 提交于 2019-11-27 10:24:35

问题


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 application spends all its time watching the clipboard.

Any ideas?


回答1:


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




回答2:


Python 3 code for the above answer (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)

PS- I couldn't add it as a comment due to low reputation points so, I'm adding this as an answer.




回答3:


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


来源:https://stackoverflow.com/questions/14685999/trigger-an-event-when-clipboard-content-changes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!