|
1 | | -use crate::Error; |
2 | | -use rdev::{Event, EventType, grab}; |
| 1 | +use crate::Result; |
3 | 2 | use screen_capture::{CursorPosition, MonitorCursorPositionConfig}; |
4 | 3 | use std::{ |
5 | | - sync::atomic::{AtomicBool, AtomicU64, Ordering}, |
6 | | - time::Duration, |
| 4 | + sync::atomic::Ordering, |
| 5 | + {io::Read, os::unix::net::UnixStream, time::Duration}, |
7 | 6 | }; |
8 | 7 |
|
9 | | -static CURSOR_GRAP_THREAD_RUNNING: AtomicBool = AtomicBool::new(false); |
10 | | -static CURSOR_POSITION: AtomicU64 = AtomicU64::new(u64::MAX); |
11 | | - |
12 | 8 | pub fn monitor_cursor_position( |
13 | 9 | config: MonitorCursorPositionConfig, |
14 | 10 | mut callback: impl FnMut(CursorPosition) + Send + 'static, |
15 | | -) -> Result<(), Error> { |
16 | | - if !CURSOR_GRAP_THREAD_RUNNING.load(Ordering::Relaxed) { |
17 | | - std::thread::spawn(move || { |
18 | | - CURSOR_GRAP_THREAD_RUNNING.store(true, Ordering::Relaxed); |
19 | | - log::info!("start long run cursor grap thread..."); |
| 11 | +) -> Result<()> { |
| 12 | + let socket_path = "/tmp/wayshot-cursor.sock"; |
20 | 13 |
|
21 | | - let callback = move |event: Event| -> Option<Event> { |
22 | | - if let EventType::MouseMove { x, y } = event.event_type { |
23 | | - // log::debug!("cursor position: (x, y) = ({x}, {y})"); |
24 | | - let cur_pos = (((x as u64) << 32) & 0xffff_ffff_0000_0000) | (y as u64); |
25 | | - CURSOR_POSITION.store(cur_pos, Ordering::Relaxed); |
26 | | - } |
| 14 | + loop { |
| 15 | + if config.stop_sig.load(Ordering::Relaxed) { |
| 16 | + log::info!("exit monitor cursor thread..."); |
| 17 | + break; |
| 18 | + } |
27 | 19 |
|
28 | | - Some(event) |
29 | | - }; |
| 20 | + match UnixStream::connect(socket_path) { |
| 21 | + Ok(mut stream) => { |
| 22 | + log::info!("Connected to server process"); |
30 | 23 |
|
31 | | - // The grab function use the evdev library to intercept events, |
32 | | - // so they will work with both X11 and Wayland In order for this to work, |
33 | | - // the process running the listen or grab loop needs to either run as root (not recommended), |
34 | | - // or run as a user who's a member of the input group (recommended) Note: on some distros, |
35 | | - // the group name for evdev access is called plugdev, and on some systems, both groups can exist. |
36 | | - // When in doubt, add your user to both groups if they exist. |
37 | | - // commands: `sudo usermod -aG input $USER` or `sudo usermod -aG plugdev $USER` |
38 | | - if let Err(e) = grab(callback) { |
39 | | - log::warn!("cursor monitor failed: {e:?}"); |
| 24 | + if let Err(e) = process_mouse_positions(&mut stream, &config, &mut callback) { |
| 25 | + log::warn!("process mouse positions failed: {e}"); |
| 26 | + } |
40 | 27 | } |
| 28 | + Err(e) => log::warn!("UnixStream connect `{socket_path}` failed: {e}"), |
| 29 | + } |
41 | 30 |
|
42 | | - CURSOR_GRAP_THREAD_RUNNING.store(false, Ordering::Relaxed); |
43 | | - log::info!("exit long run cursor grap thread..."); |
44 | | - }); |
| 31 | + std::thread::sleep(Duration::from_secs(3)); |
45 | 32 | } |
46 | 33 |
|
47 | | - let mut last_pos = CURSOR_POSITION.load(Ordering::Relaxed); |
48 | | - loop { |
49 | | - if config.stop_sig.load(Ordering::Relaxed) { |
50 | | - log::info!("exit monitor cursor thread..."); |
51 | | - break; |
52 | | - } |
| 34 | + Ok(()) |
| 35 | +} |
53 | 36 |
|
54 | | - let cur_pos = CURSOR_POSITION.load(Ordering::Relaxed); |
55 | | - if last_pos == cur_pos || cur_pos == u64::MAX { |
56 | | - std::thread::sleep(Duration::from_millis(5)); |
57 | | - continue; |
58 | | - }; |
| 37 | +fn process_mouse_positions( |
| 38 | + stream: &mut UnixStream, |
| 39 | + config: &MonitorCursorPositionConfig, |
| 40 | + callback: &mut (impl FnMut(CursorPosition) + Send + 'static), |
| 41 | +) -> Result<()> { |
| 42 | + loop { |
| 43 | + let pos = receive_position(stream)?; |
| 44 | + let x = ((pos >> 32) & 0x0000_0000_ffff_ffff) as i32; |
| 45 | + let y = (pos & 0x0000_0000_ffff_ffff) as i32; |
59 | 46 |
|
60 | | - last_pos = cur_pos; |
| 47 | + log::debug!("Received mouse position: ({}, {})", x, y); |
61 | 48 |
|
62 | 49 | let position = CursorPosition { |
63 | | - x: ((cur_pos >> 32) & 0x0000_0000_ffff_ffff) as i32, |
64 | | - y: (cur_pos & 0x0000_0000_ffff_ffff) as i32, |
| 50 | + x, |
| 51 | + y, |
65 | 52 | output_x: config.screen_info.position.x, |
66 | 53 | output_y: config.screen_info.position.y, |
67 | 54 | output_width: config.screen_info.logical_size.width, |
68 | 55 | output_height: config.screen_info.logical_size.height, |
69 | 56 | }; |
70 | 57 |
|
71 | 58 | callback(position); |
72 | | - } |
73 | 59 |
|
74 | | - Ok(()) |
| 60 | + std::thread::sleep(Duration::from_millis(5)); |
| 61 | + } |
75 | 62 | } |
76 | 63 |
|
| 64 | +fn receive_position(stream: &mut UnixStream) -> Result<u64> { |
| 65 | + let mut buffer = [0u8; 8]; |
| 66 | + stream.read_exact(&mut buffer)?; |
| 67 | + let value = u64::from_ne_bytes(buffer); |
| 68 | + Ok(value) |
| 69 | +} |
0 commit comments