Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于ClipboardWatcherContext.start_watch()方法的一点疑问。 #4

Closed
HaroldLoui opened this issue Mar 7, 2024 · 11 comments · Fixed by #6
Closed

关于ClipboardWatcherContext.start_watch()方法的一点疑问。 #4

HaroldLoui opened this issue Mar 7, 2024 · 11 comments · Fixed by #6
Labels
bug Something isn't working

Comments

@HaroldLoui
Copy link

作者你好,由于start_watch()会阻塞当前线程,因此我将它放进新的线程中执行,结果无法监听到剪贴板的内容了,且同时无法shutdown。以下是我的代码:

use clipboard_rs::{Clipboard, ClipboardContext, ClipboardWatcher, ClipboardWatcherContext};
use std::{
    sync::{Arc, Mutex},
    thread,
    time::Duration,
};
struct ClipboardManager {
    ctx: Arc<Mutex<ClipboardContext>>,
    watcher: Arc<Mutex<ClipboardWatcherContext>>,
}

impl ClipboardManager {
    fn new() -> Self {
        ClipboardManager {
            ctx: Arc::new(Mutex::new(ClipboardContext::new().unwrap())),
            watcher: Arc::new(Mutex::new(ClipboardWatcherContext::new().unwrap())),
        }
    }
}

fn main() {
    let manager = ClipboardManager::new();

    let ctx = Arc::clone(&manager.ctx);
    let watcher = Arc::clone(&manager.watcher);
    let start_handle = thread::spawn(move || {
        let mut watcher = watcher.lock().unwrap();
        watcher.add_handler(Box::new(move || {
            let content = ctx.lock().unwrap().get_text().unwrap();
            println!("read:{}", content);
        }));

        println!("start watch!");
        watcher.start_watch();
    });

    let watcher = Arc::clone(&manager.watcher);
    let watcher_shutdown = watcher.lock().unwrap().get_shutdown_channel();
    let stop_handle = thread::spawn(move || {
        thread::sleep(Duration::from_secs(10));
        println!("stop watch!");
        watcher_shutdown.stop();
    });

    println!("main");
    stop_handle.join().unwrap();
    start_handle.join().unwrap();
}

还请作者帮忙看下是不是我的写法有问题,我又应该怎么去声明一个全局的watcher让它能够在任何地方都能够监听到剪贴板的内容和随时进行shutdown操作。

@ChurchTao
Copy link
Owner

@HaroldLoui
请问你的操作系统环境,我使用你的代码运行是没问题的。我是 arm64 的 MacOS
image

@ChurchTao
Copy link
Owner

@HaroldLoui
由于你的疑问,我改版了 watcher 的用法,使其更加易于与其他类型结合起来。你可以看这个 pr,有疑问敬请提出,我会在下个版本使用这个PR #6

@HaroldLoui
Copy link
Author

@HaroldLoui 请问你的操作系统环境,我使用你的代码运行是没问题的。我是 arm64 的 MacOS

我那个代码是在win11下跑的,确实无法正常运行。后来改成使用mpsc::channel()shutdown发送给结束线程后,倒是可以正常运行了。

@HaroldLoui
Copy link
Author

另外这段代码在我的ArchLinux上也可以跑得通。

@ChurchTao
Copy link
Owner

@HaroldLoui 请问你的操作系统环境,我使用你的代码运行是没问题的。我是 arm64 的 MacOS

我那个代码是在win11下跑的,确实无法正常运行。后来改成使用mpsc::channel()shutdown发送给结束线程后,倒是可以正常运行了。

@HaroldLoui 可以麻烦你用这个分支跑一下 watcher 的 demo 吗? dev-watcher-api-change 我从你是使用场景上,发现了我原本的 callback 写法局限性很大,从而做的一次改版,你看下这种 API 方式能不能满足你的需求

use clipboard_rs::{
	Clipboard, ClipboardContext, ClipboardHandler, ClipboardWatcher, ClipboardWatcherContext,
};
use std::{thread, time::Duration};

struct Manager {
	ctx: ClipboardContext,
}

impl Manager {
	pub fn new() -> Self {
		let ctx = ClipboardContext::new().unwrap();
		Manager { ctx }
	}
}

impl ClipboardHandler for Manager {
	fn on_clipboard_change(&mut self) {
		println!(
			"on_clipboard_change, txt = {}",
			self.ctx.get_text().unwrap()
		);
	}
}

fn main() {
	let manager = Manager::new();

	let mut watcher = ClipboardWatcherContext::new().unwrap();

	let watcher_shutdown = watcher.add_handler(manager).get_shutdown_channel();

	thread::spawn(move || {
		thread::sleep(Duration::from_secs(5));
		println!("stop watch!");
		watcher_shutdown.stop();
	});

	println!("start watch!");
	watcher.start_watch();
}

@ChurchTao ChurchTao added the question Further information is requested label Mar 8, 2024
@HaroldLoui
Copy link
Author

可以,不过周末只能在我个人的ArchLinux上跑了,win11环境得等到周一我去公司的电脑上跑才行,那上面才有rust环境。

@HaroldLoui
Copy link
Author

这个分支我跑了,我的Arch上没有问题,win11环境得等我周一回公司后才能测试了。另外我对这个新Api的ClipboardHandler Trait有个个人的看法,应该再增加两个不需要重写的方法startstop来开启和停止监听剪贴板,使用者只需要重写on_clipboard_change方法,对剪贴板的内容进行定制化的操作(如保存到数据库或在Tauri中发送事件给前端,亦或进行简单的打印等等)。

@HaroldLoui
Copy link
Author

已在windows上测试,结果还是不行:

[dependencies]
clipboard-rs = {git = "https://github.com/ChurchTao/clipboard-rs", branch = "dev-watcher-api-change"}
use clipboard_rs::{
    Clipboard, ClipboardContext, ClipboardHandler, ClipboardWatcher, ClipboardWatcherContext,
};
use std::{thread, time::Duration};

struct Manager {
    ctx: ClipboardContext,
}

impl Manager {
    pub fn new() -> Self {
        let ctx = ClipboardContext::new().unwrap();
        Manager { ctx }
    }
}

impl ClipboardHandler for Manager {
    fn on_clipboard_change(&mut self) {
        println!(
            "on_clipboard_change, txt = {}",
            self.ctx.get_text().unwrap()
        );
    }
}

fn main() {
    let manager = Manager::new();

    let mut watcher = ClipboardWatcherContext::new().unwrap();

    let watcher_shutdown = watcher.add_handler(manager).get_shutdown_channel();

    thread::spawn(move || {
        thread::sleep(Duration::from_secs(10));
        println!("stop watch!");
        watcher_shutdown.stop();
    });

    let start = thread::spawn(move || {
        println!("start watch!");
        watcher.start_watch();
    });

    start.join().unwrap();
}

您给的代码可以跑通,但将watcher丢入新线程后便无法停止监听,也无法监听到剪贴板的内容。

@ChurchTao
Copy link
Owner

没错,我重现了你的问题,我暂时还么找到原因,不过下个版本中我会修复它,届时我会通知你

@ChurchTao
Copy link
Owner

@HaroldLoui
好消息,我已经解决了你描述的问题,问题出在 Windows 的监听器对象在 rust 中,不是线程安全的,我做了相应的优化,改成了非阻塞的方案,目前按照你的代码应该可以运行了,可以请你在这个分支中测试一下你的代码吗?https://github.com/ChurchTao/clipboard-rs/tree/dev-watcher-api-change

@ChurchTao ChurchTao added bug Something isn't working and removed question Further information is requested labels Mar 13, 2024
@ChurchTao ChurchTao linked a pull request Mar 14, 2024 that will close this issue
@ChurchTao
Copy link
Owner

@HaroldLoui 新版本已经发了,我暂时先关闭这个 issue了,如果还有问题,可以重新打开😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants