您好我正在编写一个c ++程序,我需要将剪贴板上的内容变为字符串变量。我找到了很多解决方案,但所有解决方案都是针对Windows编写的。有没有使用QT库的方法?我找到了与X11相关的东西,但不是很清楚。
非常感谢
答案 0 :(得分:10)
X11使用灵活的多缓冲区多格式异步应用程序端剪贴板协议。
大多数工具包都实现了它(GTK的gtk_clipboard_get()
,Qt的QApplication::clipboard()
,Tk的clipboard_get)。但您可以使用X11 API手动执行此操作,例如,如果您不使用工具包,或者您必须通过剪贴板缓冲区传递大量数据,而不是同时将其全部保留在内存中。
可能有很多缓冲区,但您只需知道两个:
CLIPBOARD
是通常的显式缓冲区:您可以使用“编辑/复制”菜单复制该内容,然后使用“编辑/粘贴”菜单将其粘贴。PRIMARY
选择是一种隐含的鼠标选择功能:当使用鼠标光标选中时,文本会进入其中,并在文本输入字段的中间点击时粘贴它。主要选择不需要按键,因此在彼此相邻的窗口之间复制小片段非常有用。这个功能大多是特定于unix的,但我看过putty,trillian和一些gtk应用程序在Windows操作系统上模拟它。此外,当中间单击页面的空非交互空间时,firefox具有“粘贴和放置”功能。
优化那些应用程序端缓冲区:不是每次更改时都将整个剪贴板/选择推送到服务器,应用程序只是告诉服务器“我拥有它”。要获取缓冲区,请让所有者向您提供其内容。这样,即使大型缓冲区在实际请求之前也不会占用任何资源。
请求缓冲区时,请向所有者询问您需要的特定格式。例如,从seamonkey浏览器复制的图像(右键单击图像并按“复制图像”)可以用不同的格式表示。如果将其粘贴到终端中,它将显示为图像URL。如果将其粘贴到libreoffice writer中,它将成为从该URL加载的图片。如果粘贴在gimp中,它就是图像本身。这是有效的,因为seamonkey是智能的,并为每个应用程序提供它要求的格式:终端的文本字符串,libreoffice的html和gimp的图像数据。要请求文本格式,您需要UTF8_STRING
格式并回退到STRING
。
当您要求另一个应用程序准备缓冲区时,可能需要一些时间,请求是异步:所有者准备缓冲区,将其保存在指定位置(窗口属性用作临时存储)并在完成后通知SelectionNotify
事件。
所以要获得缓冲区:
CLIPBOARD
,PRIMARY
),格式
(UTF8_STRING
,STRING
)和将结果存储到XConvertSelection()
以请求缓冲区SelectionNotify
活动// gcc -o xclipget xclipget.c -lX11
#include <stdio.h>
#include <limits.h>
#include <X11/Xlib.h>
Bool PrintSelection(Display *display, Window window, const char *bufname, const char *fmtname)
{
char *result;
unsigned long ressize, restail;
int resbits;
Atom bufid = XInternAtom(display, bufname, False),
fmtid = XInternAtom(display, fmtname, False),
propid = XInternAtom(display, "XSEL_DATA", False),
incrid = XInternAtom(display, "INCR", False);
XEvent event;
XConvertSelection(display, bufid, fmtid, propid, window, CurrentTime);
do {
XNextEvent(display, &event);
} while (event.type != SelectionNotify || event.xselection.selection != bufid);
if (event.xselection.property)
{
XGetWindowProperty(display, window, propid, 0, LONG_MAX/4, False, AnyPropertyType,
&fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);
if (fmtid == incrid)
printf("Buffer is too large and INCR reading is not implemented yet.\n");
else
printf("%.*s", (int)ressize, result);
XFree(result);
return True;
}
else // request failed, e.g. owner can't convert to the target format
return False;
}
int main()
{
Display *display = XOpenDisplay(NULL);
unsigned long color = BlackPixel(display, DefaultScreen(display));
Window window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0,0, 1,1, 0, color, color);
Bool result = PrintSelection(display, window, "CLIPBOARD", "UTF8_STRING") ||
PrintSelection(display, window, "CLIPBOARD", "STRING");
XDestroyWindow(display, window);
XCloseDisplay(display);
return !result;
}
这适用于许多简单案例。这里缺少的一件事是支持增量读取大缓冲区。我们加上吧!
某些应用可能需要复制/粘贴100千兆字节的文本日志。而X11允许这样!但是数据必须以递增方式传递,分成几个块。
如果请求的缓冲区太大,而不是将其存储到window属性中,则owner会设置格式为INCR
的属性。如果删除它,则所有者假定您已阅读它,并将下一个块放在同一属性中。这一直持续到读取和删除最后一个块为止。最后,owner设置大小为0的属性以标记数据的结尾。
所以要读取大缓冲区,删除INCR
属性并等待属性再次出现(PropertyNotify
event,state == PropertyNewValue
),读取并删除它,等待它再次出现,依此类推,直到它出现零大小。
// gcc -o xclipget xclipget.c -lX11
#include <stdio.h>
#include <limits.h>
#include <X11/Xlib.h>
Bool PrintSelection(Display *display, Window window, const char *bufname, const char *fmtname)
{
char *result;
unsigned long ressize, restail;
int resbits;
Atom bufid = XInternAtom(display, bufname, False),
fmtid = XInternAtom(display, fmtname, False),
propid = XInternAtom(display, "XSEL_DATA", False),
incrid = XInternAtom(display, "INCR", False);
XEvent event;
XSelectInput (display, window, PropertyChangeMask);
XConvertSelection(display, bufid, fmtid, propid, window, CurrentTime);
do {
XNextEvent(display, &event);
} while (event.type != SelectionNotify || event.xselection.selection != bufid);
if (event.xselection.property)
{
XGetWindowProperty(display, window, propid, 0, LONG_MAX/4, True, AnyPropertyType,
&fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);
if (fmtid != incrid)
printf("%.*s", (int)ressize, result);
XFree(result);
if (fmtid == incrid)
do {
do {
XNextEvent(display, &event);
} while (event.type != PropertyNotify || event.xproperty.atom != propid || event.xproperty.state != PropertyNewValue);
XGetWindowProperty(display, window, propid, 0, LONG_MAX/4, True, AnyPropertyType,
&fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);
printf("%.*s", (int)ressize, result);
XFree(result);
} while (ressize > 0);
return True;
}
else // request failed, e.g. owner can't convert to the target format
return False;
}
int main()
{
Display *display = XOpenDisplay(NULL);
unsigned long color = BlackPixel(display, DefaultScreen(display));
Window window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0,0, 1,1, 0, color, color);
Bool result = PrintSelection(display, window, "CLIPBOARD", "UTF8_STRING") ||
PrintSelection(display, window, "CLIPBOARD", "STRING");
XDestroyWindow(display, window);
XCloseDisplay(display);
return !result;
}
例如xsel
工具使用INCR
传输大于4000的缓冲区。根据ICCCM,应用程序可以选择合理的大小限制。
相同的代码适用于PRIMARY
选择。将“CLIPBOARD”替换为“PRIMARY”以打印PRIMARY
选择内容。
XCopy()
和XPaste()
实施xsel
和xclip
来源答案 1 :(得分:2)
您是否首先尝试找不到代码而是找到带有实现的程序?我为你做了这个,发现很多使用直接X11调用的实现。我认为最有价值的是this,但您也可以阅读this。找到任何程序并查找源代码。尝试在维基百科上查看哪些应用程序使用x11剪贴板/选择系统。
以下程序专门用于数据传输 机制:
xcutsel
将数据从选择传输到剪切缓冲区,反之亦然
xclipboard
,glipper
(Gnome),parcellite
(LXDE)和klipper
(KDE)是 剪贴板管理员,也许wmcliphist
以及xcb
显示的内容 剪切缓冲区并允许用户操作它们xselection,
xclip
,xsel
和xcopy
是将数据复制到或的命令行程序 来自X选择。 xcopy有一个详细的选项,可以帮助调试X. 选择问题。 parcellite也有能力读取和 从命令行写入特定的X选择。
synergy
是一个跨平台工具,可让您共享剪贴板 运行多个操作系统的多台计算机
xfce4-clipman-plugin
是Xfce4的&#34;剪贴板历史插件 面板&#34;还有一个剪贴板管理器xtranslate查找中的单词 多语言词典中的Xselection autocutsel同步切割缓冲区 和选择缓冲区
很简单,从理论上讲,X11有2&#34;剪贴板&#34;:实际上是一个键盘和选择 - 你可以通过按下鼠标中键来实时选择你所选择的文字。键盘&#34;用于主/缺省剪贴板目的,由不同类型的对象交换。
P.S。根据我的经验,我不再使用x11了。享受:)