Keep one macOS cursor density snapshot and retry failed captures

This commit is contained in:
fufesou
2026-09-13 17:15:28 +08:00
parent 8869a440da
commit 3629db2aa0
2 changed files with 33 additions and 7 deletions

View File

@@ -37,6 +37,9 @@ use std::{
mod cursor;
#[cfg(test)]
mod cursor_poll_tests;
// macOS boolean_t is defined as `int` in <mach/boolean.h>
type BooleanT = hbb_common::libc::c_int;
@@ -567,10 +570,10 @@ fn unsafe_get_cursor() -> ResultType<Option<u64>> {
if seed == LATEST_SEED {
return Ok(None);
}
let c = get_cursor_id(seed.1)?;
LATEST_SEED = seed;
Ok(Some(c.1))
}
let c = get_cursor_id()?;
Ok(Some(c.1))
}
pub fn reset_input_cache() {
@@ -579,7 +582,7 @@ pub fn reset_input_cache() {
}
}
fn get_cursor_id() -> ResultType<(id, u64, f64)> {
fn get_cursor_id(scale: f64) -> ResultType<(id, u64)> {
unsafe {
let c: id = msg_send![class!(NSCursor), currentSystemCursor];
if c == nil {
@@ -622,19 +625,25 @@ fn get_cursor_id() -> ResultType<(id, u64, f64)> {
hcursor += (r + g + b + a) * (255 << i) as f64;
}
}
let scale = cursor::scale()?;
Ok((c, cursor::cache_id(hcursor as _, scale), scale))
Ok((c, cursor::cache_id(hcursor as _, scale)))
}
}
pub fn get_cursor_data(hcursor: u64) -> ResultType<CursorData> {
autoreleasepool(|| unsafe_get_cursor_data(hcursor))
let result = autoreleasepool(|| unsafe_get_cursor_data(hcursor));
if result.is_err() {
// A failed capture must be retried even if the seed and density stay unchanged.
reset_input_cache();
}
result
}
// https://github.com/stweil/OSXvnc/blob/master/OSXvnc-server/mousecursor.c
fn unsafe_get_cursor_data(hcursor: u64) -> ResultType<CursorData> {
unsafe {
let (c, hcursor2, scale) = get_cursor_id()?;
// Keep the poll's density if the pointer crosses displays before capture.
let scale = LATEST_SEED.1;
let (c, hcursor2) = get_cursor_id(scale)?;
if hcursor != hcursor2 {
bail!("cursor changed");
}

View File

@@ -0,0 +1,17 @@
use super::*;
#[test]
fn capture_failure_invalidates_the_density_poll() {
let previous = unsafe { LATEST_SEED };
unsafe {
LATEST_SEED = (1, 2.0);
}
// Zero cannot be a macOS cursor ID, even if AppKit has no current cursor.
let result = get_cursor_data(0);
let after_failure = unsafe { LATEST_SEED };
unsafe {
LATEST_SEED = previous;
}
assert!(result.is_err());
assert_eq!(after_failure, (0, 0.0));
}