Linux系统下基于Dart实现剪贴板变更监控的方案问询
在Linux下用Dart监控剪贴板变更
这里提供两种不依赖第三方Dart剪贴板包的实现方案,基于Linux原生工具和系统API:
方案1:轮询xclip命令(快速实现)
这种方式简单直接,通过定期调用xclip获取剪贴板内容,对比历史值判断是否变更。
前置依赖
确保系统已安装xclip:
- Debian/Ubuntu:
sudo apt install xclip - Fedora/RHEL:
sudo dnf install xclip
Dart代码示例
import 'dart:io'; import 'dart:async'; void main() { startClipboardMonitor(); } void startClipboardMonitor() { String? lastContent; // 调整检查间隔,平衡响应速度和系统开销 Timer.periodic(const Duration(milliseconds: 500), (timer) async { try { final processResult = await Process.run( 'xclip', ['-selection', 'clipboard', '-o'], runInShell: true, ); if (processResult.exitCode != 0) { print('获取剪贴板失败: ${processResult.stderr}'); return; } final currentContent = processResult.stdout.toString().trim(); if (currentContent != lastContent && currentContent.isNotEmpty) { lastContent = currentContent; // 触发自定义操作 onClipboardChanged(currentContent); } } catch (e) { print('监控出错: $e'); } }); } void onClipboardChanged(String content) { print('剪贴板已更新:'); print(content); // 在这里添加你的业务逻辑,比如解析内容、调用接口等 }
注意事项
- 间隔时间:建议设置在300-1000ms之间,避免过于频繁的系统调用
- 空内容处理:判断
currentContent.isNotEmpty避免剪贴板清空时重复触发 - 权限:确保程序有执行
xclip的权限
方案2:监听X11剪贴板事件(高效无轮询)
如果需要实时监控且不想有轮询开销,可以直接和X11服务器交互,监听剪贴板的选择变更事件。这种方式需要用Dart的ffi调用Xlib库。
步骤说明
添加
ffi依赖到pubspec.yaml:dependencies: ffi: ^2.1.0Dart代码示例(核心框架)
import 'dart:ffi'; import 'package:ffi/ffi.dart'; // 绑定Xlib核心函数 typedef XOpenDisplayC = Pointer<Void> Function(Pointer<Utf8>); typedef XOpenDisplayDart = Pointer<Void> Function(Pointer<Utf8>); typedef XNextEventC = Void Function(Pointer<Void>, Pointer<Void>); typedef XNextEventDart = void Function(Pointer<Void>, Pointer<Void>); typedef XDefaultRootWindowC = Int32 Function(Pointer<Void>); typedef XDefaultRootWindowDart = int Function(Pointer<Void>); typedef XSelectInputC = Void Function(Pointer<Void>, Int32, Int64); typedef XSelectInputDart = void Function(Pointer<Void>, int, int); // X11事件掩码常量 const int PropertyChangeMask = 0x00002000; void main() { final xlib = DynamicLibrary.open('libX11.so.6'); // 初始化Xlib函数 final xOpenDisplay = xlib.lookupFunction<XOpenDisplayC, XOpenDisplayDart>('XOpenDisplay'); final xNextEvent = xlib.lookupFunction<XNextEventC, XNextEventDart>('XNextEvent'); final xDefaultRootWindow = xlib.lookupFunction<XDefaultRootWindowC, XDefaultRootWindowDart>('XDefaultRootWindow'); final xSelectInput = xlib.lookupFunction<XSelectInputC, XSelectInputDart>('XSelectInput'); final display = xOpenDisplay(nullptr); if (display == nullptr) { print('无法连接到X11显示'); return; } final rootWindow = xDefaultRootWindow(display); // 监听根窗口的属性变化事件(剪贴板变更会触发这类事件) xSelectInput(display, rootWindow, PropertyChangeMask); print('开始实时监听剪贴板...'); // 分配内存存储X11事件 final eventBuffer = malloc.allocate<Void>(128); // XEvent结构体大小约128字节 while (true) { xNextEvent(display, eventBuffer); // 解析事件,判断是否为剪贴板相关的属性变更 // 完整实现需要解析event.type和对应的property原子值 checkAndHandleClipboardChange(); } } Future<void> checkAndHandleClipboardChange() async { // 触发变更时,用xclip获取最新内容 final result = await Process.run('xclip', ['-selection', 'clipboard', '-o'], runInShell: true); if (result.exitCode == 0) { final content = result.stdout.toString().trim(); if (content.isNotEmpty) { print('剪贴板实时更新: $content'); // 执行自定义操作 } } }
注意事项
- 完整实现需要解析X11的
PropertyNotify事件,判断是否是剪贴板相关的属性变更(需要通过XInternAtom获取CLIPBOARD原子值) - 该方案无轮询开销,响应实时,但需要对X11的选择机制有基础了解
- 不同Linux发行版的Xlib库路径可能不同,
libX11.so.6是通用路径
内容的提问来源于stack exchange,提问作者Bhaskar
相关产品推荐
相关产品推荐

