如何在Go语言中向桌面剪贴板写入text/html类型内容?
解决Go语言写入text/html类型内容到剪贴板的问题
剪贴板的MIME类型支持需要调用对应系统的原生API,通用Go剪贴板包大多仅实现了text/plain格式。以下分平台给出直接实现方案:
Windows平台
Windows需要先注册"HTML Format"剪贴板格式,并按照特定头部规范组织HTML内容,再通过user32.dll的API写入:
package main import ( "fmt" "syscall" "unsafe" ) var ( user32 = syscall.NewLazyDLL("user32.dll") kernel32 = syscall.NewLazyDLL("kernel32.dll") openClipboard = user32.NewProc("OpenClipboard") emptyClipboard = user32.NewProc("EmptyClipboard") setClipboardData = user32.NewProc("SetClipboardData") closeClipboard = user32.NewProc("CloseClipboard") globalAlloc = kernel32.NewProc("GlobalAlloc") globalLock = kernel32.NewProc("GlobalLock") globalUnlock = kernel32.NewProc("GlobalUnlock") globalFree = kernel32.NewProc("GlobalFree") registerClipboardFormat = user32.NewProc("RegisterClipboardFormatW") ) func SetHTMLClipboardWindows(html string) error { // 注册HTML剪贴板格式 cfHTML, _, err := registerClipboardFormat.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("HTML Format")))) if cfHTML == 0 { return err } // 构建符合Windows剪贴板要求的带偏移标记的HTML内容 baseHeader := "Version:0.9\r\nStartHTML:00000000\r\nEndHTML:00000000\r\nStartFragment:00000000\r\nEndFragment:00000000\r\n" startHTML := len(baseHeader) + 2 endHTML := startHTML + len(html) + 2 startFragment := startHTML endFragment := endHTML - 2 fullContent := fmt.Sprintf("Version:0.9\r\nStartHTML:%08d\r\nEndHTML:%08d\r\nStartFragment:%08d\r\nEndFragment:%08d\r\n%s\r\n", startHTML, endHTML, startFragment, endFragment, html) // 分配全局可移动内存 hMem, _, err := globalAlloc.Call(0x0040|0x8000, uintptr(len(fullContent)+1)) // GMEM_MOVEABLE | GMEM_ZEROINIT if hMem == 0 { return err } defer globalFree.Call(hMem) // 锁定内存并写入内容 pMem, _, err := globalLock.Call(hMem) if pMem == 0 { return err } defer globalUnlock.Call(hMem) syscall.Copy(pMem, unsafe.Pointer(syscall.StringToUTF16Ptr(fullContent))) // 操作剪贴板写入数据 if _, _, err := openClipboard.Call(0); err != nil { return err } defer closeClipboard.Call() if _, _, err := emptyClipboard.Call(); err != nil { return err } if _, _, err := setClipboardData.Call(cfHTML, hMem); err != nil { return err } return nil }
macOS平台
通过cgo调用AppKit的NSPasteboard直接设置text/html类型:
package main /* #cgo LDFLAGS: -framework AppKit #include <stdlib.h> #include <AppKit/AppKit.h> void setHTMLClipboard(const char* html) { NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; [pasteboard declareTypes:@[NSPasteboardTypeHTML] owner:nil]; [pasteboard setString:[NSString stringWithUTF8String:html] forType:NSPasteboardTypeHTML]; } */ import "C" import "unsafe" func SetHTMLClipboardMacOS(html string) error { cHTML := C.CString(html) defer C.free(unsafe.Pointer(cHTML)) C.setHTMLClipboard(cHTML) return nil }
Linux平台(X11环境)
利用xclip命令直接写入指定MIME类型内容(需提前安装xclip,如apt install xclip):
package main import ( "os/exec" ) func SetHTMLClipboardLinux(html string) error { cmd := exec.Command("xclip", "-selection", "clipboard", "-t", "text/html") stdin, err := cmd.StdinPipe() if err != nil { return err } defer stdin.Close() if _, err := stdin.Write([]byte(html)); err != nil { return err } return cmd.Run() }
跨平台兼容
通过runtime.GOOS在运行时判断系统,调用对应平台的实现:
import ( "fmt" "runtime" ) func CopyHTMLToClipboard(html string) error { switch runtime.GOOS { case "windows": return SetHTMLClipboardWindows(html) case "darwin": return SetHTMLClipboardMacOS(html) case "linux": return SetHTMLClipboardLinux(html) default: return fmt.Errorf("unsupported OS: %s", runtime.GOOS) } }
内容的提问来源于stack exchange,提问作者Ruslan Melnychenko
相关产品推荐
相关产品推荐

