首页 » 操作系统 » Windows » 正文

剪贴板内容格式检测 AutoHotkey

发布者:站点默认
2014/03/20 浏览数(4,526) 分类:Windows 评论(1)

当执行复制操作后,Windows 会同时保存多种格式的数据以保证各个软件能取到自己认识的格式。

为什么会有自定义剪贴板格式

标准格式的局限

虽然 windows 系统内置了一些常见的剪贴板格式(如文本、图片、文件等),但这些格式无法涵盖所有应用的需求。例如:

  • Word 可能需要传递带格式的文本(如 RTF、HTML)。
  • Photoshop 可能需要传递带有图层信息的图片数据。
  • Excel 可能需要传递带有公式和单元格格式的数据。

自定义格式的作用

当应用程序需要在剪贴板中存储特殊类型的数据,而这些数据没有对应的标准格式时,就会注册一个自定义格式(格式ID大于0xC000),并用这个格式来存储和读取数据。

应用程序通过 RegisterClipboardFormat 注册一个唯一的格式名,系统返回一个格式ID。之后应用可以用这个ID在剪贴板中存取数据。其他支持该格式的应用也可以识别和读取这些数据。

如果目标应用不认识这个自定义格式,就会忽略它,转而使用标准格式(如文本、图片等)。这样可以保证最大兼容性,同时又能支持高级功能。

举例:

Word 复制内容时,剪贴板里可能同时有:纯文本(CF_TEXT)、富文本(RTF)、HTML、Word自定义格式(如“MSWordDoc”)。

Photoshop 复制图片时,可能有:位图(CF_BITMAP)、自定义格式(如“Photoshop Image”)。

代码

#Requires AutoHotkey v2.0
#SingleInstance force

; 创建GUI窗口
myGui := Gui()
myGui.Title := "剪贴板内容格式检测"
myGui.SetFont("s10")

; 添加控件
myGui.Add("Text", , "复制内容后点击下方按钮:")
myGui.Add("Button", "w200 h30", "检测剪贴板数据类型").OnEvent("Click", DetectClipboard)
myGui.Add("Edit", "w500 h240 vResultText ReadOnly Multi WantReturn VScroll", "点击按钮开始检测...")

; 显示GUI
myGui.Show()

; 标准格式
stdFormats := Map(
    1, "CF_TEXT",         ; ANSI 编码的文本(最常见的文本格式,兼容性最好)
    2, "CF_BITMAP",       ; 图片内容(不是图片文件,是"二进制"图片内容)
    3, "CF_METAFILEPICT",
    4, "CF_SYLK",
    5, "CF_DIF",
    6, "CF_TIFF",
    7, "CF_OEMTEXT",      ; OEM 编码的文本,主要用于老式 DOS 程序或控制台程序,使用 OEM 代码页(如 437、936 等,DOS 下常用编码)
    8, "CF_DIB",          ; 图片内容(可以有透明度,但不一定会存入)
    9, "CF_PALETTE",
    10, "CF_PENDATA",
    11, "CF_RIFF",
    12, "CF_WAVE",
    13, "CF_UNICODETEXT", ; Unicode(UTF-16LE)编码的文本,支持所有语言和字符
    14, "CF_ENHMETAFILE",
    15, "CF_HDROP",       ; 文件(在资源管理器中复制文件)
    16, "CF_LOCALE",      ; 文本数据的语言/区域(如中文、英文、日文等),通常与 CF_TEXT 或 CF_UNICODETEXT 一起出现,帮助目标程序正确解释文本内容
    17, "CF_DIBV5"        ; 图片内容(含透明度和色彩信息的 CF_BITMAP)
)

; 检测剪贴板内容的函数
DetectClipboard(*) {
    try {
        if !DllCall("OpenClipboard", "ptr", 0)
            return "无法打开剪贴板"
        formats := []
        fmt := DllCall("EnumClipboardFormats", "uint", 0)
        while (fmt) {
            name := ""
            buf := Buffer(256, 0)
            if (fmt >= 0xC000) {
                ; 自定义格式
                if DllCall("GetClipboardFormatName", "uint", fmt, "ptr", buf, "int", 256)
                    name := "   OtherFormat: " StrGet(buf)
                else
                    name := "Unknown"
            } else {
                ; 标准格式
                name := "StandardFormat: " stdFormats[fmt]
            }
            value := GetClipboardText(fmt)
            name := value ? name . " [" . value . "]" : name
            formats.Push(name)
            fmt := DllCall("EnumClipboardFormats", "uint", fmt)
        }
        ; 关闭剪贴板
        DllCall("CloseClipboard")
        result := Join(formats)
    } catch Error as e {
        result := "检测失败: " . e.Message
    }
    ; 更新显示结果
    myGui["ResultText"].Value := "检测结果: `n" . result
}

GetClipboardText(typeCode) {
    text := ""
    if hMem := DllCall("GetClipboardData", "uint", typeCode, "ptr") {
        if (typeCode = 15) { ; CF_HDROP
            fileCount := DllCall("shell32\DragQueryFileW", "ptr", hMem, "uint", 0xFFFFFFFF, "ptr", 0, "uint", 0)
            files := []
            loop fileCount {
                len := DllCall("shell32\DragQueryFileW", "ptr", hMem, "uint", A_Index - 1, "ptr", 0, "uint", 0)
                buf := Buffer((len + 1) * 2)
                DllCall("shell32\DragQueryFileW", "ptr", hMem, "uint", A_Index - 1, "ptr", buf, "uint", len + 1)
                files.Push(StrGet(buf, "UTF-16"))
            }
            text := Join(files, ",")
        } else if (typeCode = 13) { ; CF_UNICODETEXT
            if pMem := DllCall("GlobalLock", "ptr", hMem, "ptr") {
                ; 读取Unicode字符串
                text := StrGet(pMem, "UTF-16")
                DllCall("GlobalUnlock", "ptr", hMem)
            }
        } else {
        }
    }
    return text
}

Join(arr, separator := "`n") {
    result := ""
    for v in arr
        result .= v . separator
    return RTrim(result, separator)
}

; 保持脚本运行
return
点击返回顶部
  1. 留言
  2. 联系方式