【tkGo】实时记录您的剪贴板

1 背景

Make your clipboard data no longer easy to lose

2 环境

Python 3.7.3 64-bit

pywin32 224

3 win32clipboard

优点:速度快

缺点:不跨平台

  • 获取文本
import win32clipboard as clip

clip.OpenClipboard()  # 打开剪贴板
clip.SetClipboardText("这是复制的内容", clip.CF_UNICODETEXT)  # 复制
text = clip.GetClipboardData(clip.CF_UNICODETEXT)  # 粘贴
clip.CloseClipboard()  # 关闭剪贴板
print(text)
  • 获取复制文件的绝对路径
import win32clipboard as clip

clip.OpenClipboard()  # 打开剪贴板

if clip.IsClipboardFormatAvailable(clip.CF_HDROP):  # 判断剪贴板中是否包含指定格式的数据
    file_path = clip.GetClipboardData(clip.CF_HDROP)
    for item in file_path:
        print("文件路径 -> %s" % item)
else:
    print("请先复制文件!")

clip.CloseClipboard()  # 关闭剪贴板
  • 获取图片
import ctypes
from ctypes.wintypes import WORD, DWORD, LONG
import win32clipboard as clip


class BMPFileHeader(ctypes.Structure):  # BMP文件头结构体
    _pack_   = 1                     
    _fields_ = [
        ('bfType', WORD),
        ('bfSize', DWORD),
        ('bfReserved1', WORD),
        ('bfReserved2', WORD),
        ('bfOffBits', DWORD)
    ]

BMPFileHeaderSize = ctypes.sizeof(BMPFileHeader)

class BMPApinfogHeader(ctypes.Structure):  # 位图信息头结构体
    _pack_   = 1
    _fields_ = [
        ('biSize', DWORD),
        ('biWidth', LONG),
        ('biHeight', LONG),
        ('biPLanes', WORD),
        ('biBitCount', WORD),
        ('biCompression', DWORD),
        ('biSizeImage', DWORD),
        ('biXpelsPerMeter', LONG),
        ('biYpelsPerMeter', LONG),
        ('biClrUsed', DWORD),
        ('biClrImportant', DWORD)
    ]
    
BMPApinfogHeaderSize = ctypes.sizeof(BMPApinfogHeader)

ColorTableSize = 0


if __name__ == "__main__":

    clip.OpenClipboard()  # 打开剪贴板

    if clip.IsClipboardFormatAvailable(clip.CF_DIB):  # 判断剪贴板中是否包含指定格式的数据
        data = clip.GetClipboardData(clip.CF_DIB)  # 返回的是一个内存对象,包含BIT格式图片的信息
        clip.CloseClipboard()  # 关闭剪贴板
        
        bmp_file_header = BMPFileHeader()
        ctypes.memset(ctypes.pointer(bmp_file_header), 0, BMPFileHeaderSize)
        bmp_file_header.bfType = ord('B') | (ord('M') << 8)
        bmp_file_header.bfSize = BMPFileHeaderSize + len(data)
        bmp_file_header.bfOffBits = BMPFileHeaderSize + BMPApinfogHeaderSize + ColorTableSize
        
        with open("test.png", 'wb') as bmp_file:
            bmp_file.write(bmp_file_header)
            bmp_file.write(data)
    else:
        print("请先截图或者复制图片内容!")
  • 获取剪贴板序列号
import win32clipboard as clip


print(clip.GetClipboardSequenceNumber())

当剪贴板内容发生变化或被清空时,该序列号会递增。所以可以通过该序列号来监听剪贴板。

4 主要代码

  • 监听
def listen(self):
        while self.allow_listen:  # 是否允许监听,可通过 allow_listen 控制是否开启监听
            if not self.pause_listen:  # 是否暂停监听,可通过 pause_listen 控制是否暂停监听
                clip_sn = clip.GetClipboardSequenceNumber()  # 获取剪贴板序列号
                if clip_sn != self.last_clip_sn:  # 如果序列号和上次不一样,则代表剪贴板内容发生了变化
                    
                    try:
                        data = self.get_data()  # 获取剪贴板内容
                        if data[1] and len(data[1]) > self.max:  # 如果剪贴板内容太长,则直接跳过
                            pass
                        else:
                            self.print(data)  # 输出剪贴板内容
                            self.data.append(data)  # 将剪贴板内容存入列表
                            if len(self.data) > self.num:  # 如果列表中储存的内容超过限定个数,则删除最早的
                                del self.data[0]
                        self.last_clip_sn = clip_sn  # 记录剪贴板序列号
                    except Exception as e:  # 如果发生异常,则打印异常信息
                        print_exc()
                        self.print(e)

                time.sleep(self.listen_invl)  # 休眠指定时间,一般设为0.5秒就可以了
  • 获取剪贴板内容
def get_data(self):
        data_type = data_content = None
        self.open()  # 打开剪贴板
        if clip.IsClipboardFormatAvailable(clip.CF_HDROP):  # 如果是文件格式
            data_content = [file for file in clip.GetClipboardData(clip.CF_HDROP)]
            self.close()
            data_type = self.DATA_TYPE_FILE
        elif clip.IsClipboardFormatAvailable(clip.CF_DIB):  # 如果是图片格式
            if self.dir_img:  # 如果设置了图片目录,则将剪贴板的图片内容保存到该目录
                data = clip.GetClipboardData(clip.CF_DIB)
                self.close()
                self.last_img_path = data_content = self.save_img(data)  # 保存图片
            else:
                self.close()
            data_type = self.DATA_TYPE_IMG
        elif clip.IsClipboardFormatAvailable(clip.CF_UNICODETEXT):  # 如果是文本格式
            data_content = clip.GetClipboardData(clip.CF_UNICODETEXT).split("\r\n")
            self.close()
            data_type = self.DATA_TYPE_TEXT
        else:
            self.close()
            data_type = self.DATA_TYPE_OTHR
        
        return (data_type, data_content)

这里优先判断是否满足文件格式,因为有些剪贴板内容既可以是文件格式也可以是图片格式,比如你在网页上复制了某些图片。防止图片重复存储至本地,因为图片可能已经存在于你的浏览器的临时目录里了。

  • 保存图片
def save_img(self, data):
        cur_time = time.strftime('%Y%m%d_%H%M%S', time.localtime(time.time()))  # 当前时间
        img_dir = os.path.join(self.dir_img,cur_time.split("_")[0])  # 分日期存储图片
        if not os.path.exists(img_dir): os.mkdir(img_dir)
        imt_name = "{}{}{}".format(self.IMG_NAME_PRFX, cur_time, self.IMG_NAME_SFX)  # 图片名字
        imt_path = os.path.join(img_dir, imt_name)  # 图片具体路径

        bmp_file_header = BMPFileHeader()  # 创建文件头
        ctypes.memset(ctypes.pointer(bmp_file_header), 0, BMPFileHeaderSize)
        bmp_file_header.bfType = ord('B') | (ord('M') << 8)
        bmp_file_header.bfSize = BMPFileHeaderSize + len(data)
        bmp_file_header.bfOffBits = BMPFileHeaderSize + BMPApinfogHeaderSize + ColorTableSize
        
        with open(imt_path, 'wb') as bmp_file:  # 写入图片内容
            bmp_file.write(bmp_file_header)
            bmp_file.write(data)

        return imt_path

5 最终效果

6 完整代码

github.com/TheUncleWhoGrowsBeans/tkGo

发布了22 篇原创文章 · 获赞 4 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_35921007/article/details/104192489
今日推荐