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 *)¬ify); XFlush(dpy); break; // 完成一次请求后退出,也可以保持监听 } } XCloseDisplay(dpy); return 0; }
编译命令
gcc clipboard-write.c -o clipboard-write -lX11
关键步骤说明
XInternAtom:将"CLIPBOARD"和"UTF8_STRING"转换为X11内部的原子ID,这是X11中标识选区和数据格式的标准方式。XSetSelectionOwner:让当前创建的临时窗口成为CLIPBOARD选区的所有者,只有所有者才能响应剪贴板内容请求。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
关键步骤说明
XConvertSelection:向CLIPBOARD的当前所有者发送请求,要求将内容转换为UTF8_STRING格式,并存储到我们指定的临时属性中。XGetWindowProperty:在收到SelectionNotify事件后,从临时属性中提取剪贴板数据,注意要处理内存分配和释放。- 临时属性:使用
XInternAtom创建一个唯一的临时属性,避免与其他程序的属性冲突。
注意事项
- 必须链接
libX11库(编译时加-lX11)。 UTF8_STRING是推荐的格式,支持全字符集;XA_STRING仅支持ASCII,用于兼容旧程序。- 写入剪贴板的程序需要保持运行直到其他程序获取内容,或者可以修改代码保持长期监听(比如循环不break)。
内容的提问来源于stack exchange,提问作者BowPark
相关产品推荐
相关产品推荐

