【效率】调用Win10自带剪贴板历史

Win10自带的剪贴板相信大家都有用过,但是不能用快捷键直接粘贴,着实遗憾。

【效率】调用Win10自带剪贴板历史

虽说ahk可以简单地实现高度自定义的剪贴板,但既然系统给我们提供了一个现成的,为何不利用呢?
微软提供了相应的接口,ahk可以调用这个接口,实现读取和修改的功能,让它变得更强大。
虽然比起自己写的剪贴板来说,自由度可能会低一点,但也十分足够了。
由于是调用了系统自带的剪贴板,脚本并不负责记录,所以可以读取脚本打开之前就存在的历史,这就不需要我们随时保持脚本的打开状态。

完整代码放在最后,下面放示例:

; 获取当前第一条历史记录的文本内容
text := WinClip.History.Item[0].Content.GetText()
; 显示当前剪贴板的Html格式内容
MsgBox text := WinClip.Content.GetHtml()
; 保存当前历史记录的最后一条,并获取它的文本内容,时间戳, 和它的一个可用格式
history := WinClip.History ; 保存当前所有记录
num := history.Count ;获取记录的数量
lastItem := history.Item[num - 1] ; 获取最后一条记录
MsgBox lastItem.Timestamp ; 显示时间戳
lastContent := lastItem.Content ; 获取这条记录的内容
MsgBox lastContent.AvailableFormats[1] ; 显示内容的其中一个有效格式
if lastContent.Contains("Text") ; 检查内容中是否包含文本
	MsgBox lastContent.GetText() ; 显示内容中的文本
; 修改剪贴板
WinClip.Clear() ; 清空当前剪贴板,效果等同 A_Clipboard := ""
WinClip.History.Item[1].Push() ; 将第2条历史记录设置为当前剪贴板内容
WinClip.History.Item[2].Delete() ; 将第3条历史记录删除
; 自定义当前剪贴板文本,与A_Clipboard := "xxx"不同的是,通过设置第二第三条可选参数可决定是否加入历史记录和是否允许跨设备同步
WinClip.SetText("设置文本但不记录历史", false)
WinClip.ClearHistory() ;清空所有历史记录
; 直接粘贴指定历史记录,然后后恢复原来的内容
f1::{
	WinClip.History.Item[1].Push()
	Send("^v"), Sleep(20)
	WinClip.History.Item[0].Push()
}
f2::{
	WinClip.History.Item[2].Push()
	Send("^v"), Sleep(20)
	WinClip.History.Item[0].Push()
}
f3::{
	WinClip.History.Item[3].Push()
	Send("^v"), Sleep(20)
	WinClip.History.Item[0].Push()
}

完整代码:

class WinClip {
	static pIClipboardStatic := CreateInterface("Windows.ApplicationModel.DataTransfer.Clipboard", "{C627E291-34E2-4963-8EED-93CBB0EA3D70}")
	static pIClipboardStatic2 := CreateInterface("Windows.ApplicationModel.DataTransfer.Clipboard", "{D2AC1B6A-D29F-554B-B303-F0452345FE02}")
	static pIClipboardContentOptions := CreateInstance("Windows.ApplicationModel.DataTransfer.ClipboardContentOptions", "{E888A98C-AD4B-5447-A056-AB3556276D2B}")
	; 获取当前剪贴板内容
	static Content => (ComCall(6, this.pIClipboardStatic, "ptr*", &pIDataPackageView := 0), IDataPackageView(pIDataPackageView))
	; 获取当前历史记录集合
	static History{
		get{
			ComCall(6, this.pIClipboardStatic2, "uint*", &pIAsyncOperation := 0)
			pIClipboardHistoryItemsResult := WaitForAsync(pIAsyncOperation)
			ComCall(7, pIClipboardHistoryItemsResult, "ptr*", &pIReadOnlyList := 0)
			ObjRelease(pIClipboardHistoryItemsResult)
			return IReadOnlyListForClipboardHistoryItem(pIReadOnlyList)
		}
	}
	; 检查是否启用了历史记录
	static IsHistoryEnabled => (ComCall(10, this.pIClipboardStatic2, "char*", &bRes := 0), bRes)
	; 检查是否启用了多设备同步
	static IsRoamingEnabled => (ComCall(11, this.pIClipboardStatic2, "char*", &bRes := 0), bRes)
	; 清空当前剪贴板
	static Clear() => (ComCall(9, this.pIClipboardStatic))
	; 使设置在剪贴板的数据的原始应用程序关闭后可用
	static Flush() => (ComCall(8, this.pIClipboardStatic))
	; 清空历史记录
	static ClearHistory() => (ComCall(7, this.pIClipboardStatic2, "char*", &bRes := 0), bRes)
	; 为当前剪贴板设置文本,可选择是否加入历史记录和是否允许多设备同步
	static SetText(text, isAllowedInHistory := "", isRoamable := ""){
		A_Clipboard := ""
		ComCall(7, this.pIClipboardContentOptions, "char", (isRoamable  = 1 || isRoamable = 0) ? isRoamable : this.IsHistoryEnabled)
		ComCall(9, this.pIClipboardContentOptions, "char", (isAllowedInHistory = 1 || isAllowedInHistory = 0) ? isAllowedInHistory : this.IsHistoryEnabled)
		dataPackage := CreateDataPackage(), dataPackage.SetText(text)
		ComCall(12, this.pIClipboardStatic2, "ptr", dataPackage, "ptr", this.pIClipboardContentOptions, "char*", &bRes := 0)
		this.Flush()
		return bRes
	}
}

class IReadOnlyList extends InterfaceBase {
	; 检索指定索引的项目,0为第一个项目
	Item[index] => (ComCall(6, this, "int", index, "ptr*", &pItem := 0), pItem)
	; 检索此列表的项目数量
	Count => (ComCall(7, this, "uint*", &count := 0), count)
}

class IReadOnlyListForClipboardHistoryItem extends IReadOnlyList {
	Item[index] => (ComCall(6, this, "int", index, "ptr*", &pItem := 0), IClipboardHistoryItem(pItem))
}

class IClipboardHistoryItem extends InterfaceBase {
	; 此记录的ID
	Id => (ComCall(6, this, "ptr*", &pId:= 0), StrGet(pId + 28))
	; 时间戳
	Timestamp => (ComCall(7, this, "ptr*", &dateTime := 0), DateAdd(16010101000000, dateTime / 1e7, "S"))
	; 内容
	Content => (ComCall(8, this, "ptr*", &pIDataPackageView := 0), IDataPackageView(pIDataPackageView))
	; 删除此记录
	Delete() => (ComCall(8, WinClip.pIClipboardStatic2, "ptr", this, "char*", &bRes := 0), bRes)
	; 将此记录放到当前剪贴板
	Push() => (ComCall(9, WinClip.pIClipboardStatic2, "ptr", this, "char*", &bRes := 0), !bRes)
}

class IDataPackageView extends InterfaceBase {
	; 获取此内容支持的格式
	AvailableFormats{
		get{
			ComCall(9, this, "ptr*", &pIReadOnlyList := 0)
			formatsReadOnlyList := IReadOnlyList(pIReadOnlyList)
			formats := []
			loop formatsReadOnlyList.Count
				formats.Push(StrGet(formatsReadOnlyList.Item[A_Index - 1] + 28))
			return formats
		}
	}
	; 检查是否包含某种格式
	Contains(standardFormat) => (ComCall(10, this, "ptr", CreateHString(standardFormat), "char*", &bRes := 0), bRes)
	; 获取文本
	GetText(){
		try ComCall(12, this, "uint*", &pIAsyncOperation := 0)
		catch
			return
		return StrGet(WaitForAsync(pIAsyncOperation) + 28)
	}
	; 获取Html
	GetHtml(){
		try ComCall(15, this, "uint*", &pIAsyncOperation := 0)
		catch
			return
		return StrGet(WaitForAsync(pIAsyncOperation) + 28)
	}
	; 获取富文本
	GetRtf(){
		try ComCall(17, this, "uint*", &pIAsyncOperation := 0)
		catch
			return
		return StrGet(WaitForAsync(pIAsyncOperation) + 28)
	}
}

class IDataPackage extends InterfaceBase {
	SetText(text) => ComCall(16, this, "ptr", CreateHString(text))
}

class InterfaceBase {
	__New(ptr) => this.Ptr := ptr
	__Delete() => ObjRelease(this.Ptr)
}

class HString {
	__New(ptr) => this.Ptr := ptr
	__Delete() => DllCall("Combase\WindowsDeleteString", "ptr", this)
	GetStr() => StrGet(this.Ptr + 28)
}

CreateDataPackage() => IDataPackage(CreateInstance("Windows.ApplicationModel.DataTransfer.DataPackage", "{61EBF5C7-EFEA-4346-9554-981D7E198FFE}").Ptr)

CreateHString(str) => (DllCall("Combase\WindowsCreateString", "wstr", str, "uint", StrLen(str), "ptr*", &hStr := 0), HString(hStr))

CreateInterface(name, uuid){
	if res := DllCall("ole32\CLSIDFromString", "wstr", uuid, "ptr", pClsid := Buffer(16), "uint")
		throw Error("CLSIDFromString failed: " res)
	DllCall("Combase\WindowsCreateString", "wstr", name, "uint", StrLen(name), "ptr*", &hString := 0)
	if res := DllCall("Combase\RoGetActivationFactory", "ptr", hString, "ptr", pClsid, "ptr*", &pInterface := 0, "uint"){
		DllCall("Combase\WindowsDeleteString", "ptr", hString)
		throw Error("RoGetActivationFactory failed: " res)
	}
	DllCall("Combase\WindowsDeleteString", "ptr", hString)
	return pInterface
}

CreateInstance(name, uuid){
	DllCall("Combase\RoActivateInstance", "ptr", CreateHString(name), "ptr*", &instance := 0, "uint")
	return ComObjQuery(instance, uuid)
}

WaitForAsync(pIAsyncOperation){
	IAsyncInfo := ComObjQuery(pIAsyncOperation, "{00000036-0000-0000-C000-000000000046}")
	status := 0
	while !status
		ComCall(7, IAsyncInfo, "uint*", &status)
	if status != 1
		throw Error("AsyncOpertion Error")
	ComCall(8, pIAsyncOperation, "ptr*", &pResult := 0)
	ObjRelease(pIAsyncOperation)
	return pResult
}

给TA捐赠
共{{data.count}}人
人已捐赠
其他案例

imageput桌面快捷显示图片

2021-12-15 6:26:58

其他应用教程案例

超级命令【super-command】

2021-12-16 22:02:50

4 条回复 A文章作者 M管理员
  1. ty

    6666

  2. greatYear

    WinClip 第45行 Item[index] => (ComCall(6, this, “int”, index, “ptr*”, &pItem := 0), IClipboardHistoryItem(pItem)) 错误,(0x8000000B)该操作尝试访问的数据超出了有效范围。

个人中心
购物车
优惠劵
有新私信 私信列表
搜索