问题描述:
Avalonia的剪切板IClipboard实现目前(Ver11.3.10)在UOS国产系统下不能成功将文件写入剪切板,在桌面文件夹粘贴时会报错:
尝试了Avalonia的DataObject旧方法和直接用C#操纵X11,也试了xclip-copyfile命令行,均未能成功,最后曲线救国,采用自编译可执行文件,在软件里调用成功,实现在软件内选择文件复制,然后在桌面文件夹粘贴OK。
以下是需要的代码:
- 一、实现思路
- 使用X11库与系统剪切板交互
- 将文件路径转换为URI格式
- 设置剪切板数据为x-special/gnome-copied-files格式
- 二、完整代码
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <X11/Xlib.h>
- #include <X11/Xatom.h>
- // 将文件路径转换为文件URI
- char* file_to_uri(const char* filepath) {
- // 简单的实现,实际应该进行URL编码
- int length = strlen(filepath) + 8; // "file://" + 原路径 + '\0'
- char* uri = malloc(length);
- if (uri == NULL) return NULL;
-
- snprintf(uri, length, "file://%s", filepath);
- return uri;
- }
- // 设置文件到剪切板
- int set_file_to_clipboard(const char* filepath) {
- Display* display = XOpenDisplay(NULL);
- if (!display) {
- fprintf(stderr, "无法打开X显示\n");
- return 1;
- }
-
- Window window = XCreateSimpleWindow(display,
- DefaultRootWindow(display),
- 0, 0, 1, 1, 0, 0, 0);
-
- // 获取剪切板原子
- Atom clipboard = XInternAtom(display, "CLIPBOARD", False);
- Atom targets_atom = XInternAtom(display, "TARGETS", False);
- Atom text_atom = XInternAtom(display, "TEXT", False);
- Atom utf8_atom = XInternAtom(display, "UTF8_STRING", False);
- Atom x_special_atom = XInternAtom(display, "x-special/gnome-copied-files", False);
- Atom uri_list_atom = XInternAtom(display, "text/uri-list", False);
-
- // 转换为URI格式
- char* uri = file_to_uri(filepath);
- if (!uri) {
- fprintf(stderr, "无法创建URI\n");
- XCloseDisplay(display);
- return 1;
- }
-
- // 创建剪切板数据
- // GNOME格式: copy\nfile://path
- int copy_cmd_len = strlen("copy\n") + strlen(uri) + 1;
- char* copy_cmd = malloc(copy_cmd_len);
- if (!copy_cmd) {
- free(uri);
- XCloseDisplay(display);
- return 1;
- }
- snprintf(copy_cmd, copy_cmd_len, "copy\n%s", uri);
-
- // URI列表格式: file://path
- char* uri_list = malloc(strlen(uri) + 2); // uri + \n + \0
- if (!uri_list) {
- free(uri);
- free(copy_cmd);
- XCloseDisplay(display);
- return 1;
- }
- snprintf(uri_list, strlen(uri) + 2, "%s\n", uri);
-
- // 设置剪切板所有权
- XSetSelectionOwner(display, clipboard, window, CurrentTime);
-
- if (XGetSelectionOwner(display, clipboard) != window) {
- fprintf(stderr, "无法获取剪切板所有权\n");
- free(uri);
- free(copy_cmd);
- free(uri_list);
- XCloseDisplay(display);
- return 1;
- }
-
- // 等待剪切板请求
- XEvent event;
- while (1) {
- XNextEvent(display, &event);
-
- if (event.type == SelectionRequest) {
- XSelectionRequestEvent* req = &event.xselectionrequest;
- XSelectionEvent notify = {0};
-
- notify.type = SelectionNotify;
- notify.display = req->display;
- notify.requestor = req->requestor;
- notify.selection = req->selection;
- notify.target = req->target;
- notify.property = req->property;
- notify.time = req->time;
-
- if (req->target == x_special_atom) {
- // 设置x-special/gnome-copied-files格式
- XChangeProperty(req->display, req->requestor, req->property,
- utf8_atom, 8, PropModeReplace,
- (unsigned char*)copy_cmd, strlen(copy_cmd));
- notify.property = req->property;
- XSendEvent(req->display, req->requestor, False, 0, (XEvent*)¬ify);
- }
- else if (req->target == uri_list_atom) {
- // 设置text/uri-list格式
- XChangeProperty(req->display, req->requestor, req->property,
- utf8_atom, 8, PropModeReplace,
- (unsigned char*)uri_list, strlen(uri_list));
- notify.property = req->property;
- XSendEvent(req->display, req->requestor, False, 0, (XEvent*)¬ify);
- }
- else if (req->target == targets_atom) {
- // 返回支持的格式
- Atom targets[] = { x_special_atom, uri_list_atom, text_atom, utf8_atom };
- XChangeProperty(req->display, req->requestor, req->property,
- XA_ATOM, 32, PropModeReplace,
- (unsigned char*)targets, sizeof(targets)/sizeof(targets[0]));
- notify.property = req->property;
- XSendEvent(req->display, req->requestor, False, 0, (XEvent*)¬ify);
- }
- else if (req->target == text_atom || req->target == utf8_atom) {
- // 纯文本格式(文件路径)
- XChangeProperty(req->display, req->requestor, req->property,
- utf8_atom, 8, PropModeReplace,
- (unsigned char*)filepath, strlen(filepath));
- notify.property = req->property;
- XSendEvent(req->display, req->requestor, False, 0, (XEvent*)¬ify);
- }
- else {
- // 不支持的目标
- notify.property = None;
- XSendEvent(req->display, req->requestor, False, 0, (XEvent*)¬ify);
- }
- }
- else if (event.type == SelectionClear) {
- break;
- }
- }
-
- // 清理
- free(uri);
- free(copy_cmd);
- free(uri_list);
- XDestroyWindow(display, window);
- XCloseDisplay(display);
-
- printf("文件 '%s' 已复制到剪切板\n", filepath);
- printf("现在可以在文件管理器中右键粘贴或使用Ctrl+V粘贴\n");
-
- return 0;
- }
- int main(int argc, char* argv[]) {
- if (argc != 2) {
- fprintf(stderr, "用法: %s <文件路径>\n", argv[0]);
- fprintf(stderr, "示例: %s /home/user/example.txt\n", argv[0]);
- return 1;
- }
-
- // 检查文件是否存在
- FILE* file = fopen(argv[1], "r");
- if (!file) {
- fprintf(stderr, "错误: 文件 '%s' 不存在或无法读取\n", argv[1]);
- return 1;
- }
- fclose(file);
-
- return set_file_to_clipboard(argv[1]);
- }
- 三、编译方法
- # 安装必要的开发库
- sudo apt-get install libx11-dev
- # 编译程序
- gcc -o set-file-clipboard set-file-clipboard.c -lX11
- 四、使用方法
- # 设置文件到剪切板
- ./set-file-clipboard /path/to/your/file.txt
复制代码 View Code
- #region UOS(dde-file-manager)剪切文件
- public static async Task SetFilesToClipboard(List<string> filePaths)
- {
- if (filePaths == null || filePaths.Count == 0)
- return;
-
- // 每个带空格的文件路径都需要用引号包围
- var arguments = string.Join(" ", filePaths.Select(fp =>
- $""{fp.Replace(""", "\\"")}""
- ));
- const string exePath = "set-files-to-clipboard";
- if (!File.Exists(exePath))
- throw new FileNotFoundException($"可执行文件不存在: {exePath}");
-
- if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- try
- {
- var mode = File.GetUnixFileMode(exePath);
- if ((mode & UnixFileMode.UserExecute) == 0)
- {
- File.SetUnixFileMode(exePath,
- mode | UnixFileMode.UserExecute |
- UnixFileMode.GroupExecute |
- UnixFileMode.OtherExecute);
- LogHelper.Info($"已为 {exePath} 设置执行权限");
- }
- }
- catch (Exception ex)
- {
- LogHelper.Error($"设置权限失败: {ex.Message}");
- }
- }
-
- var process = new Process
- {
- StartInfo = new ProcessStartInfo
- {
- FileName = exePath,
- Arguments = arguments,
- UseShellExecute = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true
- }
- };
-
- LogHelper.Info($"执行命令: {process.StartInfo.FileName} {arguments}");
-
- process.Start();
- var output = await process.StandardOutput.ReadToEndAsync();
- var error = await process.StandardError.ReadToEndAsync();
- await process.WaitForExitAsync();
-
- if (process.ExitCode != 0)
- {
- throw new Exception($"设置剪切板失败: {error}");
- }
-
- LogHelper.Info(output);
- }
- #endregion
复制代码 View Code关键词:复制,剪切,粘贴文件,文件管理器,Avalonia,Clipboard,dde-file-manager,UOS,Linux
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |