diff --git a/src/platform/macos.rs b/src/platform/macos.rs index fe44009d8..c9b1e7a86 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -37,6 +37,9 @@ use std::{ mod cursor; +#[cfg(test)] +mod cursor_poll_tests; + // macOS boolean_t is defined as `int` in type BooleanT = hbb_common::libc::c_int; @@ -567,10 +570,10 @@ fn unsafe_get_cursor() -> ResultType> { 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 { - 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 { 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"); } diff --git a/src/platform/macos/cursor_poll_tests.rs b/src/platform/macos/cursor_poll_tests.rs new file mode 100644 index 000000000..ab7f1250f --- /dev/null +++ b/src/platform/macos/cursor_poll_tests.rs @@ -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)); +}