0

我正在编写一个组件,它必须监视 CLIPBOARD 中 X11 窗口的变化。

auto display = XOpenDisplay(NULL);
auto screen = DefaultScreen(mdisplay);
auto root_window = RootWindow(display, screen);
clipboard = XInternAtom(display, "CLIPBOARD", 0);
window = XCreateSimpleWindow(mdisplay, root_window, 0, 0, 1, 1, 0, 0, 0);
while(true) {
    XEvent event = {0};
    XNextEvent(display, &event);
    switch(event.type) {
        case SelectionNotify: {
            // do something
        }
        break;
        case SelectionRequest: { // triggered after performing copy
            auto target_name = XGetAtomName(display, event.xselectionrequest.target);
            auto selection_name = XGetAtomName(display, event.xselectionrequest.selection);
            auto property_name = XGetAtomName(display, event.xselectionrequest.property);
            Log("Event SelectionRequest: owner: %ld, requestor: %ld, selection: %s, target: %s(%d), property: %s",
                    event.xselectionrequest.owner, 
                    event.xselectionrequest.requestor,
                    selection_name,
                    target_name,
                    event.xselectionrequest.target,
                    property_name);

            if(x_event.xselectionrequest.selection != clipboard) {
                Log("%s: Warning: event selection not matching\n", __func__);
                break;
            }
        }
        break;
    }
}

问题是当我尝试检查事件时,SelectionRequest我看到的只是

Event SelectionRequest: owner: 33554433, requestor: 18874649, selection: CLIPBOARD, target: TARGETS(344), property: GDK_SELECTION

我正在执行的操作是从 Chrome 浏览器中复制一些文本。谁能告诉我为什么我没有看到这个文本,unicode,字符串类型,而是GDK_SELECTION

PS:碰巧我只看到过一次这些格式(文本、Unicode、字符串类型),但再也没有看到过。

4

1 回答 1

0

要读取剪贴板中的数据,您需要:

  • 以 TARGETS 作为目标原子调用 XConvertSelection
  • 等待 SelectionNotify 事件并使用 XGetWindowProperty 读取可用目标
  • 使用首选目标调用 XConvertSelection
  • 等待 SelectionNotify 事件并使用 XGetWindowProperty 读取可用数据

有关更多信息,请查看此答案

发布听到幼稚的实现仅用于描述主要思想。

// 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;
}
于 2022-02-11T10:44:54.403 回答