macOS pen pressure: a feed written on the UI thread never waits for a touch

This commit is contained in:
bflatastic
2026-10-24 09:26:27 +07:00
parent b1e36d69f3
commit 8dbca35893
2 changed files with 22 additions and 2 deletions
+2 -1
View File
@@ -130,7 +130,8 @@ impl Pen {
/// refuses the monitor or this isn't the main thread. /// refuses the monitor or this isn't the main thread.
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub fn start() -> Option<StylusFeed> { pub fn start() -> Option<StylusFeed> {
let feed = StylusFeed::default(); // The monitor writes on the main thread before winit hands the event on: a press never waits.
let feed = StylusFeed::on_ui_thread();
match monitor::install(feed.clone()) { match monitor::install(feed.clone()) {
Ok(()) => Some(feed), Ok(()) => Some(feed),
Err(e) => { Err(e) => {
+20 -1
View File
@@ -69,6 +69,8 @@ struct Shared {
pen: Mutex<Pen>, pen: Mutex<Pen>,
/// Signaled on every [`StylusFeed::set_sample`] ([`StylusFeed::set`] included). /// Signaled on every [`StylusFeed::set_sample`] ([`StylusFeed::set`] included).
set: Condvar, set: Condvar,
/// Written on the UI thread itself ([`StylusFeed::on_ui_thread`]): a press never waits.
ui_thread: bool,
} }
/// The pen pressure and pen end the host last read, written from any thread and read on the UI /// The pen pressure and pen end the host last read, written from any thread and read on the UI
@@ -77,6 +79,12 @@ struct Shared {
pub struct StylusFeed(Arc<Shared>); pub struct StylusFeed(Arc<Shared>);
impl StylusFeed { impl StylusFeed {
/// A feed the host writes on the UI thread, before the UI handles the event it read (macOS):
/// a press has its touch already, and waiting for one would only stall the thread.
pub fn on_ui_thread() -> Self {
Self(Arc::new(Shared { ui_thread: true, ..Shared::default() }))
}
fn lock(&self) -> MutexGuard<'_, Pen> { fn lock(&self) -> MutexGuard<'_, Pen> {
self.0.pen.lock().unwrap_or_else(|e| e.into_inner()) self.0.pen.lock().unwrap_or_else(|e| e.into_inner())
} }
@@ -160,7 +168,7 @@ impl StylusFeed {
fn press_within(&self, wait: Duration) -> Option<f32> { fn press_within(&self, wait: Duration) -> Option<f32> {
let mut pen = self.lock(); let mut pen = self.lock();
if pen.hovering() { if pen.hovering() && !self.0.ui_thread {
pen = self.wait_for_touch(pen, wait); pen = self.wait_for_touch(pen, wait);
} }
let peak = pen.peak.take(); let peak = pen.peak.take();
@@ -385,4 +393,15 @@ mod tests {
assert_eq!(feed.press_within(Duration::from_secs(10)), None); assert_eq!(feed.press_within(Duration::from_secs(10)), None);
assert!(start.elapsed() < Duration::from_secs(5)); assert!(start.elapsed() < Duration::from_secs(5));
} }
/// A feed written on the UI thread (macOS) has nothing to wait for: a hovering pen's press
/// gets its 0 at once rather than stalling the thread.
#[test]
fn a_feed_written_on_the_ui_thread_never_waits() {
let feed = StylusFeed::on_ui_thread();
feed.set(Some(0.0));
let start = std::time::Instant::now();
assert_eq!(feed.press_within(Duration::from_secs(10)), Some(0.0));
assert!(start.elapsed() < Duration::from_secs(5));
}
} }