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

Linux(X11)环境下用C语言读写剪贴板的实现方法

在Linux X11环境下用C操作CLIPBOARD剪贴板

X11的剪贴板系统基于**选区(selection)**机制,CLIPBOARD是其中一个标准选区,你提到的XInternAtom确实是获取该选区标识的关键函数——它用来将字符串形式的选区名称转换为X11内部的原子ID。下面直接给出读写CLIPBOARD的完整实现,避免依赖命令行或复杂的第三方源码。

一、向CLIPBOARD写入字符串

写入剪贴板的核心是成为CLIPBOARD选区的所有者,并响应其他程序的内容请求(通过SelectionRequest事件)。

完整代码示例

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <text-to-copy>\n", argv[0]);
        return 1;
    }
    const char *text = argv[1];
    Display *dpy = XOpenDisplay(NULL);
    if (!dpy) {
        fprintf(stderr, "Failed to open display\n");
        return 1;
    }
    Window win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1, 1, 0, 0, 0);
    
    // 获取CLIPBOARD和UTF8_STRING原子
    Atom clipboard = XInternAtom(dpy, "CLIPBOARD", False);
    Atom utf8_string = XInternAtom(dpy, "UTF8_STRING", False);

    // 设置当前窗口为CLIPBOARD的所有者
    XSetSelectionOwner(dpy, clipboard, win, CurrentTime);
    if (XGetSelectionOwner(dpy, clipboard) != win) {
        fprintf(stderr, "Failed to take ownership of CLIPBOARD\n");
        XCloseDisplay(dpy);
        return 1;
    }

    // 处理SelectionRequest事件,响应剪贴板内容请求
    XEvent ev;
    while (1) {
        XNextEvent(dpy, &ev);
        if (ev.type == SelectionRequest) {
            XSelectionRequestEvent *req = &ev.xselectionrequest;
            XSelectionNotifyEvent notify = {0};
            notify.type = SelectionNotify;
            notify.requestor = req->requestor;
            notify.selection = req->selection;
            notify.target = req->target;
            notify.time = req->time;

            if (req->target == utf8_string) {
                // 将文本数据发送给请求者
                XChangeProperty(dpy, req->requestor, req->property, utf8_string, 8,
                                PropModeReplace, (unsigned char *)text, strlen(text));
            } else if (req->target == XA_STRING) {
                // 兼容旧的STRING格式(仅ASCII)
                XChangeProperty(dpy, req->requestor, req->property, XA_STRING, 8,
                                PropModeReplace, (unsigned char *)text, strlen(text));
            } else {
                // 不支持的目标格式,设置property为None
                notify.property = None;
            }
            XSendEvent(dpy, req->requestor, False, 0, (XEvent *)&notify);
            XFlush(dpy);
            break; // 完成一次请求后退出,也可以保持监听
        }
    }

    XCloseDisplay(dpy);
    return 0;
}

编译命令

gcc clipboard-write.c -o clipboard-write -lX11

关键步骤说明

  1. XInternAtom:将"CLIPBOARD"和"UTF8_STRING"转换为X11内部的原子ID,这是X11中标识选区和数据格式的标准方式。
  2. XSetSelectionOwner:让当前创建的临时窗口成为CLIPBOARD选区的所有者,只有所有者才能响应剪贴板内容请求。
  3. SelectionRequest事件处理:当其他程序(如终端、编辑器)请求剪贴板内容时,X11会发送该事件,我们需要通过XChangeProperty将文本数据传递给请求者,并发送SelectionNotify事件确认。

二、从CLIPBOARD读取字符串

读取剪贴板需要向当前的CLIPBOARD所有者发送内容请求,等待SelectionNotify事件后提取数据。

完整代码示例

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    Display *dpy = XOpenDisplay(NULL);
    if (!dpy) {
        fprintf(stderr, "Failed to open display\n");
        return 1;
    }
    Window win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1, 1, 0, 0, 0);
    
    Atom clipboard = XInternAtom(dpy, "CLIPBOARD", False);
    Atom utf8_string = XInternAtom(dpy, "UTF8_STRING", False);
    Atom property = XInternAtom(dpy, "MY_CLIPBOARD_PROPERTY", True); // 临时属性

    // 请求转换CLIPBOARD内容到UTF8_STRING格式
    XConvertSelection(dpy, clipboard, utf8_string, property, win, CurrentTime);
    XFlush(dpy);

    // 等待SelectionNotify事件
    XEvent ev;
    char *text = NULL;
    while (1) {
        XNextEvent(dpy, &ev);
        if (ev.type == SelectionNotify) {
            XSelectionNotifyEvent *notify = &ev.xselection;
            if (notify->property != None) {
                Atom actual_type;
                int actual_format;
                unsigned long nitems, bytes_after;
                unsigned char *data = NULL;
                // 获取属性中的数据
                XGetWindowProperty(dpy, win, notify->property, 0, 1024*1024, False,
                                   AnyPropertyType, &actual_type, &actual_format,
                                   &nitems, &bytes_after, &data);
                if (data) {
                    text = (char *)malloc(nitems + 1);
                    strncpy(text, (char *)data, nitems);
                    text[nitems] = '\0';
                    XFree(data);
                }
                XDeleteProperty(dpy, win, notify->property);
            }
            break;
        }
    }

    if (text) {
        printf("%s\n", text);
        free(text);
    } else {
        fprintf(stderr, "Failed to read clipboard content\n");
    }

    XCloseDisplay(dpy);
    return 0;
}

编译命令

gcc clipboard-read.c -o clipboard-read -lX11

关键步骤说明

  1. XConvertSelection:向CLIPBOARD的当前所有者发送请求,要求将内容转换为UTF8_STRING格式,并存储到我们指定的临时属性中。
  2. XGetWindowProperty:在收到SelectionNotify事件后,从临时属性中提取剪贴板数据,注意要处理内存分配和释放。
  3. 临时属性:使用XInternAtom创建一个唯一的临时属性,避免与其他程序的属性冲突。

注意事项

  • 必须链接libX11库(编译时加-lX11)。
  • UTF8_STRING是推荐的格式,支持全字符集;XA_STRING仅支持ASCII,用于兼容旧程序。
  • 写入剪贴板的程序需要保持运行直到其他程序获取内容,或者可以修改代码保持长期监听(比如循环不break)。

内容的提问来源于stack exchange,提问作者BowPark

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 18:23:14