剪贴板子系统(CategoryClipboard)
SDL 提供对系统剪贴板的完整访问能力,既能读取其他进程写入的剪贴板内容,也能将自身数据发布到剪贴板中。
SDL 剪贴板不仅支持文本,还能按 MIME 类型访问和发布任意格式的数据。
基础用法(文本)
获取/发布纯文本到系统剪贴板非常简单,只需分别调用 SDL_GetClipboardText() 和 SDL_SetClipboardText():
- 处理的是 UTF-8 编码 的 C 字符串;
- 数据传输和编码转换由 SDL 完全托管,无需手动处理。
剪贴板回调(非文本数据)
当剪贴板包含非文本数据时,逻辑会更复杂:
- 系统剪贴板可存储任意类型数据,甚至同一数据的多种格式(如绘图软件复制图片时,同时提供 BMP/JPG/PNG 格式);
- 读取非文本数据:
- 用
SDL_HasClipboardData()判断目标 MIME 类型是否存在; - 用
SDL_GetClipboardMimeTypes()获取剪贴板支持的所有 MIME 类型列表; - 用
SDL_GetClipboardData()指定 MIME 类型读取对应数据。
- 用
- 写入非文本数据:
调用SDL_SetClipboardData()时,无需直接传入数据,只需指定支持的 MIME 类型和回调函数;
仅当其他程序请求粘贴时,SDL 才会触发回调生成对应格式的数据——避免提前拷贝大量数据,也支持为同一内容提供多格式(如 PNG/JPG),仅在被请求时才编码。
主选择区(Primary Selection)
X11/Wayland 系统除常规剪贴板外,还有「主选择区」(选中但未显式复制的文本):
- SDL 提供
SDL_GetPrimarySelectionText()/SDL_SetPrimarySelectionText()操作该区域; - 无此概念的平台(如 Windows/macOS)也支持这些 API,但仅在应用内保存字符串,系统不会外部修改该内容。
函数
- SDL_ClearClipboardData:清空系统剪贴板的所有数据(包括所有 MIME 类型)
- SDL_GetClipboardData:按指定 MIME 类型读取剪贴板数据(返回数据缓冲区和长度)
- SDL_GetClipboardMimeTypes:获取剪贴板中可用的所有 MIME 类型列表(返回字符串数组)
- SDL_GetClipboardText:读取剪贴板中的 UTF-8 文本内容(最常用的文本读取接口)
- SDL_GetPrimarySelectionText:读取 X11/Wayland 主选择区的 UTF-8 文本(其他平台返回应用内缓存)
- SDL_HasClipboardData:判断剪贴板是否包含指定 MIME 类型的数据(返回布尔值)
- SDL_HasClipboardText:判断剪贴板是否包含文本数据(快捷接口,等价于检查 text/plain 类型)
- SDL_HasPrimarySelectionText:判断主选择区是否包含文本数据
- SDL_SetClipboardData:设置剪贴板的非文本数据(传入 MIME 类型列表和数据生成回调)
- SDL_SetClipboardText:设置剪贴板的 UTF-8 文本内容(最常用的文本写入接口)
- SDL_SetPrimarySelectionText:设置 X11/Wayland 主选择区的文本(其他平台仅缓存到应用内)
数据类型
- SDL_ClipboardCleanupCallback:剪贴板数据清理回调类型(释放
SDL_SetClipboardData生成的数据缓冲区) - SDL_ClipboardDataCallback:剪贴板数据生成回调类型(当其他程序请求粘贴时,生成指定 MIME 类型的数据)
结构体
- (无)
枚举
- (无)
宏
- (无)
FreeBASIC 示例代码
' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL 库)
#Include "SDL.bi"
' 非文本数据回调:生成 PNG 格式数据(示例)
Function ClipboardDataCallback Cdecl (ByVal mimetype As ZString Ptr, ByVal userdata As Any Ptr, ByVal size As UInteger Ptr) As UByte Ptr
' 模拟 PNG 数据(实际应从文件/内存读取真实数据)
Static As UByte pngData(0 To 10) = { &H89, &H50, &H4E, &H47, &H0D, &H0A, &H1A, &H0A, 0, 0, 0 }
*size = 11 ' 数据长度
Return @pngData(0)
End Function
' 数据清理回调:释放生成的剪贴板数据
Sub ClipboardCleanupCallback Cdecl (ByVal data As UByte Ptr, ByVal userdata As Any Ptr)
' 示例中使用静态数据,无需释放;实际应释放动态分配的内存
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "剪贴板数据已清理")
End Sub
' 主程序
Dim As ZString Ptr clipText
Dim As Integer hasText
Dim As ZString Ptr mimeTypes(0 To 0) ' MIME 类型列表
Dim As Integer quit = 0
Dim As SDL_Event evt
' 初始化 SDL
If (SDL_Init(SDL_INIT_VIDEO) < 0) Then
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败:%s", SDL_GetError())
End 1
End If
' 创建窗口(SDL 剪贴板 API 需初始化视频子系统,窗口可隐藏)
Dim As SDL_Window Ptr window = SDL_CreateWindow("SDL 剪贴板示例", _
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _
400, 300, SDL_WINDOW_SHOWN)
If (window = NULL) Then
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建窗口失败:%s", SDL_GetError())
SDL_Quit()
End 1
End If
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== 剪贴板操作示例 ===")
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按 C 复制文本 | 按 V 粘贴文本 | 按 P 设置非文本数据 | 按 ESC 退出")
' 主循环
While (quit = 0)
While (SDL_PollEvent(@evt))
Select Case evt.type
Case SDL_QUITEVENT
quit = 1
Case SDL_KEYDOWN
Select Case evt.key.keysym.sym
' 1. 复制文本到剪贴板
Case SDLK_c
If (SDL_SetClipboardText("SDL 剪贴板示例 - UTF-8 文本 🎮") = 0) Then
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "已复制文本到剪贴板")
Else
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "复制文本失败:%s", SDL_GetError())
End If
' 2. 粘贴剪贴板文本
Case SDLK_v
hasText = SDL_HasClipboardText()
If (hasText) Then
clipText = SDL_GetClipboardText()
If (clipText <> NULL) Then
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "剪贴板文本:%s", clipText)
SDL_free(clipText) ' 必须释放返回的字符串
End If
Else
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "剪贴板无文本数据")
End If
' 3. 设置非文本数据(PNG 格式)
Case SDLK_p
mimeTypes(0) = "image/png" ' 支持的 MIME 类型
If (SDL_SetClipboardData(1, @mimeTypes(0), _
@ClipboardDataCallback, @ClipboardCleanupCallback, NULL) = 0) Then
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "已设置 PNG 格式剪贴板数据")
' 检查是否存在该 MIME 类型
If (SDL_HasClipboardData("image/png")) Then
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "剪贴板包含 image/png 数据")
End If
Else
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "设置非文本数据失败:%s", SDL_GetError())
End If
' 退出程序
Case SDLK_ESCAPE
quit = 1
End Select
End Select
Wend
SDL_Delay(10)
Wend
' 清理资源
SDL_DestroyWindow(window)
SDL_Quit()
End 0
总结
- SDL 剪贴板核心接口分两类:
SDL_Get/SetClipboardText处理 UTF-8 文本(最常用),SDL_Get/SetClipboardData处理任意 MIME 类型数据; - FreeBASIC 中使用文本接口时,需注意
SDL_GetClipboardText返回的字符串必须用SDL_free释放,避免内存泄漏; - 非文本数据需通过回调函数生成,仅在被请求时才编码/拷贝数据,
SDL_HasClipboardData可提前判断目标格式是否存在。
评论一下?