You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 02:40:01