你好,我正在写一个c++程序,我需要把剪贴板上的东西变成一个字符串变量。我找到了很多解决方案,但它们都是为windows编写的。有没有不使用QT库的方法?我发现了一些与X11相关的东西,但也不是很明确。
非常感谢
发布于 2014-12-09 12:23:37
你有没有试着先找到一个程序,而不是一个代码?我为你做了这件事,发现了很多使用直接X11调用的实现。我认为最有价值的是this,但你也可以阅读this。只要找到任何程序并查找源代码即可。尝试在维基百科上查找哪些应用程序使用x11剪贴板/选择系统。
以下程序专门在数据传输机制上运行:
xcutsel
将数据从选择传输到cut缓冲区,反之亦然
xclipboard
、glipper
(Gnome)、parcellite
(LXDE)和klipper
(KDE)都是剪贴板管理器,也许wmcliphist
也可以使用xcb
显示剪切缓冲区的内容,并允许用户对其进行操作。
xclip
、xsel
和xcopy
是将数据复制到X选择或从X选择复制数据的命令行程序。xcopy有一个详细选项,可以帮助调试X选择问题。parcellite还具有从命令行读取和写入特定X选择的能力。
synergy
是一个跨平台工具,允许您在运行多个操作系统的多台计算机之间共享剪贴板
xfce4-clipman-plugin
是一个“Xfce4面板的剪贴板历史插件”,同时也是一个剪贴板管理器xtranslate在多语言词典中查找X选择中的单词自动剪切同步剪切缓冲区和选择缓冲区
简而言之,在理论上,X11有两个“剪贴板”:实际上是一个键盘,用于选择--你立即选择的文本可以通过按下鼠标中键粘贴到你想要的任何地方,而实际的“键盘”是为了主/默认剪贴板的目的而制作的,作为不同类型的对象交换。
另外,在我的经历之后,我不会再和x11一起工作了。享受:)
发布于 2017-07-09 04:20:39
X11使用灵活的多缓冲区、多格式、异步应用程序端剪贴板协议。
大多数工具包都实现了它(GTK的gtk_clipboard_get()
、Qt的QApplication::clipboard()
、Tk的clipboard_get)。但您可以使用X11 API手动完成此操作,例如,如果您不使用工具包,或者如果您必须通过剪贴板缓冲区传递大量数据,而不同时将其全部保存在内存中。
理论
可能有很多缓冲区,但您只需要知道两个:
CLIPBOARD
是通常的显式缓冲区:您可以使用编辑/复制菜单复制内容,然后使用编辑/粘贴将其粘贴。menu.PRIMARY
选择是一种隐式鼠标选择功能:当使用鼠标光标选择文本时,文本将进入其中,在文本输入字段中单击鼠标中键时,文本将从中粘贴。主选择不需要按键,因此它对于在相邻的窗口之间复制小片段很有用。这个特性主要是unix特有的,但我见过putty、trillian和一些gtk应用程序在Windows操作系统上模拟它。此外,当用鼠标中键点击页面的非交互空白区域时,firefox还具有“粘贴并转到”功能。
为了优化这些东西,这些都是application-side缓冲区:应用程序只需告诉服务器“我拥有它”,而不是在每次更改时将整个剪贴板/选择推送到服务器。要获取buffer,您需要所有者将其内容提供给您。这样,即使是一个大的缓冲区也不会占用任何资源,直到它真正被请求。
在请求缓冲区时,您可以向所有者询问所需的特定格式。例如,从seamonkey浏览器复制的图像(右键单击图像并按“复制图像”)可以用不同的格式表示。如果您将其粘贴到终端中,它将显示为图像URL。如果您将其粘贴到libreoffice writer中,它将成为从该URL加载的图片。如果粘贴到gimp中,它将是图像本身。这是因为seamonkey很聪明,它为每个应用程序提供了它所要求的格式:终端使用文本字符串,libreoffice使用html,gimp使用图像数据。要请求文本格式,您需要使用回退到STRING
的UTF8_STRING
格式。
当您请求另一个应用程序准备缓冲区时,这可能需要一些时间,请求是asynchronous:所有者准备缓冲区,将其保存在指定位置(窗口属性用作临时存储),并在完成时通过SelectionNotify
事件通知您。
因此,要获取缓冲区:
CLIPBOARD
,PRIMARY
)、格式(UTF8_STRING
,STRING
)和窗口属性以将结果存储到XConvertSelection()
以请求缓冲区<代码>H227<代码>H128等待<代码>D29事件<代码>H230<代码>H131从窗口属性读取缓冲区内容<代码>H232<代码>F233朴素的实现
// 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 to的文本日志。而X11允许这样做!但数据必须以增量方式传递,并拆分成块。
如果请求的缓冲区太大,则owner会设置格式为INCR
的属性,而不是将其存储到窗口属性中。如果你删除了它,owner会假设你已经读过了,并将下一个块放在同一个属性中。这一过程一直持续到最后一个块被读取和删除。最后,owner设置大小为0的属性来标记数据的结尾。
因此,要读取大缓冲区,请删除INCR
属性并等待该属性再次出现(PropertyNotify
事件,状态为== 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;
}
例如,对于大于4000的缓冲区,xsel
工具使用INCR
传输。根据ICCCM的说法,这取决于应用程序选择一个合理的大小限制。
同样的代码也适用于PRIMARY
选择。将"CLIPBOARD“替换为"PRIMARY”以打印PRIMARY
选择内容。
参考文献
XPaste()
implementationsxsel
and -XPaste()
Lindsey
https://stackoverflow.com/questions/27378318
复制相似问题