📜  linux x11 复制粘贴事件 - C++ (1)

📅  最后修改于: 2023-12-03 15:02:42.963000             🧑  作者: Mango

Linux X11 复制粘贴事件 - C++

简介

本文介绍了在 Linux 平台使用 X11 库处理复制粘贴事件的方法。使用 C++ 语言编写程序。

X11 复制粘贴事件说明

在 X11 中,复制粘贴事件分为两种类型:Selection 和 Clipboard。其中 Selection 事件是在 X 窗口之间传递文本时使用的事件。而 Clipboard 事件,则是在不同的应用程序之间传递文本时使用的事件。

在 X11 中,复制粘贴事件通过 Selection 和 Clipboard 窗口互相传递数据。当用户复制文本时,该文本会存储到 Selection 或 Clipboard 窗口中。而当用户将文本粘贴到另一个应用程序中时,则会从 Selection 或 Clipboard 窗口中读取对应的数据。

程序实现

下面是一个使用 X11 库处理复制粘贴事件的示例程序。

#include <X11/Xlib.h>
#include <iostream>

using namespace std;

int main() {
    Display* display = XOpenDisplay(NULL);
    if (display == NULL) {
        cerr << "Cannot open display" << endl;
        exit(1);
    }

    int screen = DefaultScreen(display);
    Window root = RootWindow(display, screen);

    // 设置 Selection 窗口
    Atom selectionAtom = XInternAtom(display, "PRIMARY", False);
    Window selectionWindow = XCreateSimpleWindow(display, root, 0, 0, 1, 1, 0, 0, 0);
    XSetSelectionOwner(display, selectionAtom, selectionWindow, CurrentTime);

    // 设置 Clipboard 窗口
    Atom clipboardAtom = XInternAtom(display, "CLIPBOARD", False);
    Window clipboardWindow = XCreateSimpleWindow(display, root, 0, 0, 1, 1, 0, 0, 0);

    // 监听 X11 事件
    XEvent event;
    while (true) {
        XNextEvent(display, &event);
        if (event.type == SelectionRequest) {
            // Selection 请求事件
            XSelectionRequestEvent& requestEvent = event.xselectionrequest;

            XSelectionEvent responseEvent;
            responseEvent.type = SelectionNotify;
            responseEvent.display = requestEvent.display;
            responseEvent.requestor = requestEvent.requestor;
            responseEvent.selection = requestEvent.selection;
            responseEvent.target = requestEvent.target;
            responseEvent.time = requestEvent.time;

            if (requestEvent.target == XA_STRING || requestEvent.target == XInternAtom (display, "UTF8_STRING", False)) {
                // 获取 Selection 窗口存储的数据
                XTextProperty text;
                XGetTextProperty(display, selectionWindow, &text, selectionAtom);
                const char** list;
                int count;
                Xutf8TextPropertyToTextList(display, &text, &list, &count);

                // 将数据复制到请求者的窗口
                if (count > 0) {
                    responseEvent.property = requestEvent.property;
                    XChangeProperty(display, requestEvent.requestor, requestEvent.property, requestEvent.target, 8, PropModeReplace, (unsigned char*)list[0], strlen(list[0]));
                    responseEvent.target = requestEvent.target;
                    responseEvent.property = requestEvent.property;
                }

                // 释放资源
                XFreeStringList(list);
            } else {
                // 不支持该格式的数据类型
                responseEvent.property = None;
            }

            // 发送 Selection 响应事件
            XSendEvent(display, requestEvent.requestor, False, 0, (XEvent*)&responseEvent);
        } else if (event.type == SelectionClear) {
            // Selection 清空事件
            XSelectionClearEvent& clearEvent = event.xselectionclear;

            if (clearEvent.selection == selectionAtom) {
                // 清空 Selection 窗口存储的数据
                XSetSelectionOwner(display, selectionAtom, None, CurrentTime);
            } else if (clearEvent.selection == clipboardAtom) {
                // 清空 Clipboard 窗口存储的数据
                XSetSelectionOwner(display, clipboardAtom, None, CurrentTime);
            }
        } else if (event.type == SelectionNotify) {
            // Selection 响应事件
            XSelectionEvent& selectionEvent = event.xselection;

            if (selectionEvent.property != None) {
                // 获取 Selection 窗口存储的数据
                Atom actualType;
                int actualFormat;
                unsigned long itemCount, bytesAfter;
                unsigned char *data;
                XGetWindowProperty(display, selectionEvent.requestor, selectionEvent.property, 0, (~0L), False, AnyPropertyType, &actualType, &actualFormat, &itemCount, &bytesAfter, &data);
                XFree(data);
            }
        } else if (event.type == ClientMessage) {
            // ClientMessage 事件
            XClientMessageEvent& clientEvent = event.xclient;

            if (clientEvent.message_type == XInternAtom(display, "WM_PROTOCOLS", true) && clientEvent.format == 32 && clientEvent.data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", False)) {
                // 退出程序
                XCloseDisplay(display);
                exit(0);
            }
        }
    }
}
解析

主程序使用 X11 库创建了 Selection 和 Clipboard 窗口,并通过 Selection 和 Clipboard 窗口监听和处理复制粘贴事件。主要有以下几个步骤:

  1. 打开 X11 显示。
  2. 获取默认屏幕和根窗口。
  3. 设置 Selection 窗口,并将其设置为 Selection 事件的所有者。
  4. 设置 Clipboard 窗口。
  5. 监听 X11 事件。
  6. 处理 Selection 请求事件,获取 Selection 窗口存储的数据,并将其复制到请求者的窗口。
  7. 处理 Selection 清空事件,清空 Selection 或 Clipboard 窗口存储的数据。
  8. 处理 Selection 响应事件,获取请求者窗口存储的数据。
  9. 处理 ClientMessage 事件,当该事件表示需要退出时,关闭 X11 显示并退出程序。
参考链接