剪贴板内容更改时触发事件

时间:2013-02-04 11:38:56

标签: python multithreading macos events clipboard

我正在尝试使用Mac Lion上的Python脚本获取剪贴板内容。

我正在搜索类似的事件,因为如果我使用循环,我的应用程序会花费所有时间来查看剪贴板。

有什么想法吗?

4 个答案:

答案 0 :(得分:16)

您是否考虑过使用无限循环并在尝试之间“休眠”? 我使用pyperclip作为一个简单的PoC,它就像一个魅力,Windows和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)

而不是print,做任何你想做的事。如果你需要多线程的帮助把它放到后台线程中,请告诉我。

修改

这是一个完整的多线程示例。

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

我创建了threading.Thread的子类,重写方法run__init__并创建此类的实例。通过调用watcher.start()(而非run()!),您可以启动该主题。

为了安全地停止线程,我等待-c(键盘中断)并告诉线程自行停止。

在类的初始化中,您还有一个参数pause来控制尝试之间等待的时间。

使用我的示例中的类ClipboardWatcher,将回调替换为您所做的,例如lambda x: bitly(x, username, password)

答案 1 :(得分:3)

上述答案的Python 3代码(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-由于信誉度低,我无法将其添加为评论,因此,我将其添加为答案。

答案 2 :(得分:1)

在Macosx上查看pyperclip它的内容是:

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

这些对我有用,你怎么样?

我不太关注你在循环中的评论。


编辑添加了'orrid民意调查示例,该示例显示changeCount()如何在每个copy上粘贴到粘贴板。它仍然不是OP想要的,因为似乎没有事件或通知修改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()

答案 3 :(得分:0)

简单!

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
current_clipboard = macGetClipboard()
while True:
   clipboard = macGetClipboard()
   
   if clipboard != current_clipboard:
       print(clipboard)
       macSetClipboard("my new string")
       print(macGetClipboard())
       break