# Clipboard, ClipboardAll 以及 OnClipboardChange

Clipboard 是一个内置变量，存储了当前 Windows 剪贴板中可以以文本形式表现的内容。相应的，ClipboardAll 存储了剪贴板中的所有内容，例如图片以及带格式的文本。

Clipboard 中的每行文本通常都以回车和换行(CR+LF)结尾，在脚本中可表示为 `r`n。文件(例如那些用 Control-C 从资源管理器中复制的文件)是用文本形式表现的：每当在脚本中引用 Clipboard 变量时，它们都会被自动转换为它们的文件名称(带完整路径)。要逐个提取文件的话，参照下例：

    Loop, parse, clipboard, `n, `r
    {
     MsgBox, 4, , 第 %A_Index% 个文件是 %A_LoopField%。`n`n是否继续?
     IfMsgBox, No, break
    }

要将文件名按字母顺序排列，使用 Sort 命令。要将剪贴板上的文件名写入文件，可用 FileAppend, %clipboard%`r`n, C:\My File.txt。要改变让脚本试着保持打开剪贴板的这个时间 -- 例如在另一个程序使用剪贴板时 -- 请用 #ClipboardTimeOut 命令。

基础示例：

    clipboard = my text ;给予剪贴板全新的内容。
    clipboard = ;清空剪贴板。
    clipboard = %clipboard% ;将任何复制的文件、HTML 或者其它带格式的文本转换为纯文本。
    clipboard = %clipboard% 添加的文本。 ;在剪贴板中追加些文本。
    StringReplace, clipboard, clipboard, ABC, DEF, All ;将剪贴板中所有的 ABC 替换为 DEF (同时也将剪贴板中的内容转换为纯文本)。

使用 ClipWait 命令改善脚本的可靠性：

    clipboard = ;首先清空剪贴板，使 ClipWait 命令能检测到文本何时被复制到了剪贴板中。
    Send ^c
    ClipWait ;等待文本被复制到剪贴板中。
    MsgBox Control-C 复制了下列内容到剪贴板中：`n`n%clipboard%

## ClipboardAll (存储以及恢复剪贴板的所有内容)

ClipboardAll 存储了剪贴板中的所有内容(例如图片以及带格式的文本)。它最常用来存储剪贴板的内容以便脚本为了某个操作能临时使用剪贴板。当这个操作结束时，脚本再像下面这样将剪贴板原本的内容恢复：

    ClipSaved := ClipboardAll ;将剪贴板的所有内容存储到你选的一个变量里。
    ;... 这里放临时使用剪贴板的脚本，例如用转换 Unicode 命令粘贴 Unicode 编码的文本...
    Clipboard := ClipSaved ;恢复剪贴板原本的内容。注意使用的是 Clipboard (不是 ClipboardAll)。
    ClipSaved = ;释放内存以防原来剪贴板里是巨大的内容。

ClipboardAll 中的内容也可以存成一个文件(在这种模式下，FileAppend 命令会覆盖已存在的文件)：
FileAppend, %ClipboardAll%, C:\Company Logo.clip ; 文件扩展名无关紧要。

要在之后将文件重新读取回剪贴板(或读取到一个变量中)，参照下例：
FileRead, Clipboard, *c C:\Company Logo.clip ;注意必须在文件名之前使用 *c。

注意

在上面所描述的情况之外调用 ClipboardAll 都会返回空值。另外，ClipboardAll 不能写在逗号分隔的表达式中；也就是说，它必须独占一行，例如 ClipSaved := ClipboardAll。

赋值了 ClipboardAll 的变量将用二进制格式来存储数据，因此使用 MsgBox 或类似命令查看其内容时会显示乱码。并且，修改二进制变量的内容(例如使用 StringReplace 命令)会将其还原为普通变量，结果会丢失其存储的剪贴板数据。在 v1.0.46 及之后的版本中，二进制变量可以通过数值传递给函数(之前它们只能使用引用传递的方式)。

如果 ClipboardAll 不能获取剪贴板中的一个或多个对象(格式化的)，那么它们将被省略，而所有剩余的对象仍然会被存储。获取行为会根据 #ClipboardTimeOut 命令的设定再次尝试(而不是只尝试一次)。

一个包含了剪贴板数据的变量可以被复制到另一个变量中，例如：ClipSaved2 := ClipSaved

ClipWait 命令可以用来检测剪贴板何时有内容(包括非文本数据也可选)。

StringLen 命令可以用来显示赋值了 ClipboardAll 的变量的总大小。

赋值了 ClipboardAll 的变量可以使用 <> 和 = 运算符来相互比较(但不能直接与 ClipboardAll 进行比较)。在下例中，首先检查每个变量的大小。如果根据大小不能进行判断，就将两个变量的内容进行比较：

    if ClipSaved1 <> %ClipSaved2% ;这里必须使用老式的 IF 语句，不能使用表达式。
    MsgBox 两个变量中存储的剪贴板的内容不相同。

将 ClipboardAll 的内容存储到一个变量时，变量大小不受 #MaxMem 命令设置的最大内存限制。

一个存储了剪贴板内容的文件由四个字节的格式类型，接着四个字节的数据块大小，接着那个格式的数据块而组成。如果剪贴板包含多种格式的内容(大部分时候都是这样)，前面所述的三个组成部分会重复下去，直到存储了所有的格式。文件最后以一个四个字节的 0 格式类型结束。

已知局限：当剪贴板中有 Microsoft Excel 单元格的内容时，获取 ClipboardAll 会导致 Excel 弹出 "找不到打印机" 的对话框。

## OnClipboardChange

如果存在名称为 OnClipboardChange 的标签，那么当任何程序(甚至是脚本自身)更改了剪贴板的内容的时候，该标签下的脚本都会自动执行。在脚本加载的时候该标签同样会执行一次。

内置变量 A_EventInfo 包含：
0 如果剪贴板当前为空；
1 如果剪贴板中的内容能够以文本形式表达(包括从资源管理器中复制的文件)；
2 如果整个剪贴板里是非文本内容，例如一幅图片。

下面的例子就是一个可用的脚本。它会在剪贴板内容每次改变的时候短暂地显示一个提示。

    #Persistent
    return

    OnClipboardChange:
    ToolTip 剪贴板中的数据类型为：%A_EventInfo%
    Sleep 1000
    ToolTip ;关闭提示。
    return

如果正在执行 OnClipboardChange 标签下的脚本时剪贴板中的内容发生了变化，那么那个提示事件将会丢失。如果需要避免这种情况，在 OnClipboardChange 标签下的首行使用 Critical。不过，在 OnClipboardChange 线程运行这个时段产生的其它线程(例如按了个热键)也会被缓冲或延迟。

如果脚本本身更改了剪贴板的内容，则脚本中的 OnClipboardChange 标签往往不会立即执行；就是说，更改剪贴板的命令的下一行命令很可能会提前执行。要强制让 OnClipboardChange 标签立即执行的话，可以在更改了剪贴板之后添加一个短暂的延时例如 Sleep 20。

相关内容：OnExit, OnMessage(), RegisterCallback()

翻译：okey3m 修正：天堂之门 menk33@163.com 2008年10月26日