Chapter 120 · 输入系统

剪贴板

ClipboardSetText / ClipboardGetText 实现与系统剪贴板的文本交换,支持 Ctrl+C / Ctrl+V。

120

概念

剪贴板是输入框、文本编辑器的必备功能:
• SetText:将文本写入系统剪贴板(Ctrl+C / Ctrl+X)
• GetText:从系统剪贴板读取文本(Ctrl+V)
XGE 封装了平台差异(Windows OLE / X11 / Wayland), 统一为 UTF-8 字符串接口。

API 速查

函数说明
void xgeClipboardSetText(const char* sText)写入剪贴板
const char* xgeClipboardGetText(void)读取剪贴板

编译本章示例

gcc -O2 -I. -o ch120.exe ch120_main.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch120.exe

示例:输入框 Ctrl+C / V / X

void handleClipboard(void) {
    /* 修饰键状态取自键盘事件的 iMods 位域 */
    int ctrl = (g_tLastKey.iMods & XGE_KEY_MOD_CTRL);
    if (!ctrl) return;

    // Ctrl+C:复制选中文本
    if (xgeKeyPressed('C')) {
        if (selStart != selEnd) {
            char* sel = getSelectedText();
            xgeClipboardSetText(sel);
        }
    }

    // Ctrl+X:剪切
    if (xgeKeyPressed('X')) {
        if (selStart != selEnd) {
            char* sel = getSelectedText();
            xgeClipboardSetText(sel);
            deleteSelection();
        }
    }

    // Ctrl+V:粘贴
    if (xgeKeyPressed('V')) {
        const char* text =
            xgeClipboardGetText();
        if (text && text[0]) {
            insertTextAtCursor(text);
        }
    }

    // Ctrl+A:全选
    if (xgeKeyPressed('A')) {
        selStart = 0;
        selEnd = textLen;
    }
}

完整代码

将以下代码保存为 ch120_main.c,编译后运行即可看到剪贴板复制粘贴效果:

#include "xge.h"
#include <string.h>

static xge_font g_font = NULL;
static char g_buf[256] = "Hello XGE!";
static int g_cursor = 10;
static int g_selStart = 0, g_selEnd = 0;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x081114FF);

    /* 修饰键状态取自键盘事件的 iMods 位域 */
    int ctrl = (g_tLastKey.iMods & XGE_KEY_MOD_CTRL);

    if (ctrl && xgeKeyPressed('C')) {
        // Ctrl+C: 复制全部
        xgeClipboardSetText(g_buf);
    }
    if (ctrl && xgeKeyPressed('V')) {
        // Ctrl+V: 粘贴
        const char* text = xgeClipboardGetText();
        if (text && text[0]) {
            int len = (int)strlen(text);
            if (g_cursor + len < 255) {
                memcpy(g_buf + g_cursor, text, len);
                g_cursor += len;
                g_buf[g_cursor] = 0;
            }
        }
    }
    if (ctrl && xgeKeyPressed('A')) {
        // Ctrl+A: 全选
        g_selStart = 0;
        g_selEnd = (int)strlen(g_buf);
    }

    // 普通输入
    uint32_t ch;
    while ((ch = xgeTextGet()) != 0) {
        if (ch == 8 && g_cursor > 0) {
            memmove(g_buf+g_cursor-1, g_buf+g_cursor,
                strlen(g_buf+g_cursor)+1);
            g_cursor--;
        } else if (ch >= 32 && g_cursor < 255) {
            memmove(g_buf+g_cursor+1, g_buf+g_cursor,
                strlen(g_buf+g_cursor)+1);
            g_buf[g_cursor++] = (char)ch;
        }
    }

    // 绘制
    xgeShapeRectFill((xge_rect_t){48,148,504,44}, 0x1A2A2FFF);
    xgeShapeRectStroke((xge_rect_t){(xge_rect_t){50, 150, 500, 40}}, 2, 0x4FD8C2FF)
    xgeTextDraw(g_font, g_buf, 60, 158, 0xFFFFFFFF);

    xgeTextDraw(g_font, "Ctrl+C:Copy Ctrl+V:Paste Ctrl+A:SelectAll",
        50, 80, 0xAAAAAAFF);
    xgeTextDraw(g_font, "Type to edit, Backspace to delete",
        50, 110, 0xAAAAAAFF);

    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth  = 800;
    d.iHeight = 600;
    d.sTitle  = "ch120 - Clipboard";
    d.iFlags  = XGE_INIT_VSYNC;
    xgeInit(&d);

    g_font = xgeFontLoad("res/font/default.ttf", 24);
    xgeRun(onFrame, NULL);

    xgeFontFree(g_font);
    xgeUnit();
    return 0;
}

代码讲解

  • xgeClipboardSetText:将文本写入系统剪贴板(UTF-8)。
  • xgeClipboardGetText:从系统剪贴板读取,可能返回 NULL。
  • Ctrl+C/V/A:组合键检测(KeyDown Ctrl + KeyPressed 字母)。
  • memmove:安全插入/删除字符(内存可能重叠)。
  • 生命周期:GetText 返回的指针由引擎管理,不可 free。

要点与陷阱

  • 编码:SetText/GetText 均为 UTF-8,引擎内部转换。
  • 生命周期:GetText 返回的指针由引擎管理,不可 free。
  • 空剪贴板:GetText 可能返回 NULL 或空串,需检查。
  • 仅文本:当前 API 只支持纯文本,不支持图片/富文本。

进阶练习

  1. 实现多行文本编辑器的完整剪贴板操作。
  2. 右键菜单集成:复制/粘贴/剪切菜单项。

已验证实现

权威源码为 examples/tutorial_capture/ch120_main1.c。它把 "XGE clipboard: 你好" 写入系统剪贴板,立即读回并复制到应用自己的缓冲区,再以 UTF-8 字符串相等断言验证。返回的 xgeClipboardGetText() 指针应视为临时平台数据,控件必须立即复制,而不能长期保存。

XGE clipboard UTF-8 round trip screenshot
图:真实运行的剪贴板往返测试。程序写入、读回并复制 UTF-8 文本,绿色 PASS 表示应用缓冲区得到相同内容。