Skip to main content

multitouch/
device.rs

1use crate::cf;
2use crate::ffi::*;
3use crate::haptics::Actuator;
4use crate::power;
5use crate::queue::Queue;
6use crate::{Contact, ContactState, PathEvent, RunMode};
7use objc2_core_foundation::{CFRetained, CFString};
8use std::collections::HashMap;
9use std::fmt;
10use std::ptr;
11use std::sync::atomic::{AtomicBool, Ordering};
12use std::sync::{Arc, Mutex, OnceLock, Weak, mpsc};
13use std::time::Duration;
14
15static DEVICES_BY_REF: OnceLock<Mutex<HashMap<usize, Weak<DeviceInner>>>> = OnceLock::new();
16
17fn registry() -> &'static Mutex<HashMap<usize, Weak<DeviceInner>>> {
18    DEVICES_BY_REF.get_or_init(|| Mutex::new(HashMap::new()))
19}
20
21pub(crate) struct DeviceInner {
22    pub(crate) raw: MTDeviceRef,
23    contact_registered: AtomicBool,
24    path_registered: AtomicBool,
25    contact_subscribers: Mutex<Vec<Weak<Queue<Vec<Contact>>>>>,
26    path_subscribers: Mutex<Vec<Weak<Queue<PathEvent>>>>,
27    run_gate: Mutex<()>,
28    auto_restart_on_wake: AtomicBool,
29    wanted_running: AtomicBool,
30}
31
32unsafe impl Send for DeviceInner {}
33unsafe impl Sync for DeviceInner {}
34
35impl DeviceInner {
36    pub(crate) fn raw_restart_after_wake(&self) {
37        let _run = self.run_gate.lock().unwrap_or_else(|e| e.into_inner());
38        if !self.auto_restart_on_wake.load(Ordering::Acquire)
39            || !self.wanted_running.load(Ordering::Acquire)
40        {
41            return;
42        }
43        unsafe {
44            let _ = MTDeviceStop(self.raw);
45        }
46        std::thread::sleep(Duration::from_secs(1));
47        if self.wanted_running.load(Ordering::Acquire) {
48            unsafe {
49                let _ = MTDeviceStart(self.raw, RunMode::Verbose as i32);
50            }
51        }
52    }
53
54    fn close_streams(&self) {
55        let mut contacts = self
56            .contact_subscribers
57            .lock()
58            .unwrap_or_else(|e| e.into_inner());
59        for weak in contacts.drain(..) {
60            if let Some(queue) = weak.upgrade() {
61                queue.close();
62            }
63        }
64        let mut paths = self
65            .path_subscribers
66            .lock()
67            .unwrap_or_else(|e| e.into_inner());
68        for weak in paths.drain(..) {
69            if let Some(queue) = weak.upgrade() {
70                queue.close();
71            }
72        }
73    }
74}
75
76impl Drop for DeviceInner {
77    fn drop(&mut self) {
78        self.wanted_running.store(false, Ordering::Release);
79        unsafe {
80            if self.contact_registered.swap(false, Ordering::AcqRel) {
81                MTUnregisterContactFrameCallback(self.raw, Some(contact_frame_callback));
82            }
83            if self.path_registered.swap(false, Ordering::AcqRel) {
84                MTUnregisterPathCallback(self.raw, Some(path_callback));
85            }
86            let _ = MTDeviceStop(self.raw);
87        }
88        self.close_streams();
89        let mut registry = registry().lock().unwrap_or_else(|e| e.into_inner());
90        let key = self.raw as usize;
91        if registry
92            .get(&key)
93            .is_some_and(|weak| std::ptr::eq(weak.as_ptr(), self as *const DeviceInner))
94        {
95            registry.remove(&key);
96        }
97        drop(registry);
98        unsafe { MTDeviceRelease(self.raw) };
99    }
100}
101
102#[derive(Clone)]
103pub struct Device {
104    pub(crate) inner: Arc<DeviceInner>,
105}
106
107unsafe impl Send for Device {}
108unsafe impl Sync for Device {}
109
110impl Device {
111    fn from_owned_raw(raw: MTDeviceRef) -> Option<Self> {
112        if raw.is_null() {
113            return None;
114        }
115
116        // Create/Get functions hand us ownership. If this exact native object is
117        // already wrapped, share the Rust state and balance the newly acquired
118        // native reference immediately. This also guarantees one callback
119        // registration per MTDeviceRef.
120        let mut registry = registry().lock().unwrap_or_else(|e| e.into_inner());
121        if let Some(existing) = registry.get(&(raw as usize)).and_then(Weak::upgrade) {
122            drop(registry);
123            unsafe { MTDeviceRelease(raw) };
124            return Some(Self { inner: existing });
125        }
126
127        let inner = Arc::new(DeviceInner {
128            raw,
129            contact_registered: AtomicBool::new(false),
130            path_registered: AtomicBool::new(false),
131            contact_subscribers: Mutex::new(Vec::new()),
132            path_subscribers: Mutex::new(Vec::new()),
133            run_gate: Mutex::new(()),
134            auto_restart_on_wake: AtomicBool::new(true),
135            wanted_running: AtomicBool::new(false),
136        });
137        registry.insert(raw as usize, Arc::downgrade(&inner));
138        drop(registry);
139        Some(Self { inner })
140    }
141
142    pub fn is_available() -> bool {
143        unsafe { MTDeviceIsAvailable() }
144    }
145
146    pub fn default() -> Option<Self> {
147        Self::from_owned_raw(unsafe { MTDeviceCreateDefault() })
148    }
149
150    pub fn all() -> Vec<Self> {
151        // MTDeviceCreateList follows the Create rule; the array is released on drop.
152        let Some(list) = (unsafe { MTDeviceCreateList() }) else {
153            return Vec::new();
154        };
155        let list = unsafe { CFRetained::from_raw(list) };
156        let count = list.count();
157        let mut devices = Vec::with_capacity(count.max(0) as usize);
158        for index in 0..count {
159            let raw = unsafe { list.value_at_index(index) } as MTDeviceRef;
160            if raw.is_null() {
161                continue;
162            }
163            unsafe { cf::retain(raw.cast_const()) };
164            if let Some(device) = Self::from_owned_raw(raw) {
165                devices.push(device);
166            }
167        }
168        devices
169    }
170
171    pub fn current_absolute_time() -> f64 {
172        unsafe { MTAbsoluteTimeGetCurrent() }
173    }
174
175    pub fn from_device_id(device_id: u64) -> Option<Self> {
176        Self::from_owned_raw(unsafe { MTDeviceCreateFromDeviceID(device_id) })
177    }
178
179    pub fn from_service(service: u32) -> Option<Self> {
180        Self::from_owned_raw(unsafe { MTDeviceCreateFromService(service) })
181    }
182
183    pub fn start(&self) -> bool {
184        let _run = self
185            .inner
186            .run_gate
187            .lock()
188            .unwrap_or_else(|e| e.into_inner());
189        let ok = unsafe { MTDeviceStart(self.inner.raw, RunMode::Verbose as i32) == 0 };
190        if ok {
191            self.inner.wanted_running.store(true, Ordering::Release);
192            power::watch(&self.inner);
193        }
194        ok
195    }
196
197    pub fn stop(&self) -> bool {
198        let _run = self
199            .inner
200            .run_gate
201            .lock()
202            .unwrap_or_else(|e| e.into_inner());
203        self.inner.wanted_running.store(false, Ordering::Release);
204        power::unwatch(&self.inner);
205        self.remove_contact_frame_callback();
206        self.remove_path_callback();
207        unsafe { MTDeviceStop(self.inner.raw) == 0 }
208    }
209
210    pub fn is_running(&self) -> bool {
211        unsafe { MTDeviceIsRunning(self.inner.raw) }
212    }
213    pub fn is_built_in(&self) -> bool {
214        unsafe { MTDeviceIsBuiltIn(self.inner.raw) }
215    }
216    pub fn is_opaque_surface(&self) -> bool {
217        unsafe { MTDeviceIsOpaqueSurface(self.inner.raw) }
218    }
219    pub fn is_alive(&self) -> bool {
220        unsafe { MTDeviceIsAlive(self.inner.raw) }
221    }
222    pub fn is_hid_device(&self) -> bool {
223        unsafe { MTDeviceIsMTHIDDevice(self.inner.raw) }
224    }
225    pub fn supports_force(&self) -> bool {
226        unsafe { MTDeviceSupportsForce(self.inner.raw) }
227    }
228    pub fn supports_actuation(&self) -> bool {
229        unsafe { MTDeviceSupportsActuation(self.inner.raw) }
230    }
231    pub fn is_driver_ready(&self) -> bool {
232        unsafe { MTDeviceDriverIsReady(self.inner.raw) }
233    }
234    pub fn supports_power_control(&self) -> bool {
235        unsafe { MTDevicePowerControlSupported(self.inner.raw) }
236    }
237
238    pub fn service(&self) -> u32 {
239        unsafe { MTDeviceGetService(self.inner.raw) }
240    }
241
242    pub fn sensor_surface_dimensions(&self) -> Option<(i32, i32)> {
243        let (mut width, mut height) = (0, 0);
244        (unsafe { MTDeviceGetSensorSurfaceDimensions(self.inner.raw, &mut width, &mut height) }
245            == 0)
246            .then_some((width, height))
247    }
248
249    pub fn sensor_dimensions(&self) -> Option<(i32, i32)> {
250        let (mut rows, mut columns) = (0, 0);
251        (unsafe { MTDeviceGetSensorDimensions(self.inner.raw, &mut rows, &mut columns) } == 0)
252            .then_some((rows, columns))
253    }
254
255    fn get_i32(&self, f: unsafe extern "C" fn(MTDeviceRef, *mut i32) -> OSStatus) -> Option<i32> {
256        let mut value = 0;
257        (unsafe { f(self.inner.raw, &mut value) } == 0).then_some(value)
258    }
259
260    pub fn family_id(&self) -> Option<i32> {
261        self.get_i32(MTDeviceGetFamilyID)
262    }
263    pub fn version(&self) -> Option<i32> {
264        self.get_i32(MTDeviceGetVersion)
265    }
266    pub fn driver_type(&self) -> Option<i32> {
267        self.get_i32(MTDeviceGetDriverType)
268    }
269    pub fn transport_method(&self) -> Option<i32> {
270        self.get_i32(MTDeviceGetTransportMethod)
271    }
272
273    pub fn device_id(&self) -> Option<u64> {
274        let mut value = 0;
275        (unsafe { MTDeviceGetDeviceID(self.inner.raw, &mut value) } == 0).then_some(value)
276    }
277
278    pub fn serial_number(&self) -> Option<String> {
279        let mut value: *const CFString = ptr::null();
280        if unsafe { MTDeviceGetSerialNumber(self.inner.raw, &mut value) } != 0 {
281            return None;
282        }
283        // Get rule: the string is borrowed from the device.
284        unsafe { value.as_ref() }.map(ToString::to_string)
285    }
286
287    pub fn name(&self) -> String {
288        match self.family_id() {
289            Some(98 | 99 | 100 | 101 | 102 | 103 | 104 | 108 | 109) => "MacBook Trackpad".into(),
290            Some(105) => "Touch Bar".into(),
291            Some(112 | 113) => "Magic Mouse".into(),
292            Some(128 | 129 | 130) => "Magic Trackpad".into(),
293            family => {
294                let id = family
295                    .map(|v| v.to_string())
296                    .unwrap_or_else(|| "unknown".into());
297                if self
298                    .sensor_surface_dimensions()
299                    .is_some_and(|(w, h)| w > 1000 && h < 100)
300                {
301                    format!("Unknown Touch Bar (family ID: {id})")
302                } else {
303                    format!("Unknown Device (family ID: {id})")
304                }
305            }
306        }
307    }
308
309    pub fn system_force_response_enabled(&self) -> bool {
310        unsafe { MTDeviceGetSystemForceResponseEnabled(self.inner.raw) }
311    }
312
313    pub fn set_system_force_response_enabled(&self, enabled: bool) {
314        unsafe { MTDeviceSetSystemForceResponseEnabled(self.inner.raw, enabled) };
315    }
316
317    pub fn supports_silent_click(&self) -> bool {
318        let mut supported = false;
319        unsafe { MTDeviceSupportsSilentClick(self.inner.raw, &mut supported) == 0 && supported }
320    }
321
322    pub fn power_enabled(&self) -> bool {
323        let mut enabled = false;
324        unsafe { MTDevicePowerGetEnabled(self.inner.raw, &mut enabled) };
325        enabled
326    }
327
328    pub fn set_power_enabled(&self, enabled: bool) -> bool {
329        unsafe { MTDevicePowerSetEnabled(self.inner.raw, enabled) == 0 }
330    }
331
332    pub fn auto_restart_on_wake(&self) -> bool {
333        self.inner.auto_restart_on_wake.load(Ordering::Acquire)
334    }
335
336    pub fn set_auto_restart_on_wake(&self, enabled: bool) {
337        self.inner
338            .auto_restart_on_wake
339            .store(enabled, Ordering::Release);
340    }
341
342    pub fn system_actuations_enabled(&self) -> Option<bool> {
343        let actuator = unsafe { MTDeviceGetMTActuator(self.inner.raw) };
344        (!actuator.is_null()).then(|| unsafe { MTActuatorGetSystemActuationsEnabled(actuator) })
345    }
346
347    pub fn set_system_actuations_enabled(&self, enabled: bool) -> bool {
348        let actuator = unsafe { MTDeviceGetMTActuator(self.inner.raw) };
349        !actuator.is_null()
350            && unsafe { MTActuatorSetSystemActuationsEnabled(actuator, enabled) == 0 }
351    }
352
353    pub fn contact_frames(&self) -> ContactStream {
354        let queue = Queue::new(1);
355        self.inner
356            .contact_subscribers
357            .lock()
358            .unwrap_or_else(|e| e.into_inner())
359            .push(Arc::downgrade(&queue));
360
361        if !self.inner.contact_registered.swap(true, Ordering::AcqRel) {
362            unsafe { MTRegisterContactFrameCallback(self.inner.raw, Some(contact_frame_callback)) };
363        }
364        ContactStream { queue }
365    }
366
367    pub fn paths(&self) -> PathStream {
368        let queue = Queue::new(32);
369        self.inner
370            .path_subscribers
371            .lock()
372            .unwrap_or_else(|e| e.into_inner())
373            .push(Arc::downgrade(&queue));
374        if !self.inner.path_registered.swap(true, Ordering::AcqRel) {
375            unsafe { MTRegisterPathCallback(self.inner.raw, Some(path_callback)) };
376        }
377        PathStream { queue }
378    }
379
380    pub fn remove_contact_frame_callback(&self) {
381        if self.inner.contact_registered.swap(false, Ordering::AcqRel) {
382            unsafe {
383                MTUnregisterContactFrameCallback(self.inner.raw, Some(contact_frame_callback))
384            };
385        }
386        let mut subscribers = self
387            .inner
388            .contact_subscribers
389            .lock()
390            .unwrap_or_else(|e| e.into_inner());
391        for weak in subscribers.drain(..) {
392            if let Some(queue) = weak.upgrade() {
393                queue.close();
394            }
395        }
396    }
397
398    pub fn remove_path_callback(&self) {
399        if self.inner.path_registered.swap(false, Ordering::AcqRel) {
400            unsafe { MTUnregisterPathCallback(self.inner.raw, Some(path_callback)) };
401        }
402        let mut subscribers = self
403            .inner
404            .path_subscribers
405            .lock()
406            .unwrap_or_else(|e| e.into_inner());
407        for weak in subscribers.drain(..) {
408            if let Some(queue) = weak.upgrade() {
409                queue.close();
410            }
411        }
412    }
413
414    pub fn actuator(&self) -> Option<Actuator> {
415        let raw = unsafe { MTDeviceGetMTActuator(self.inner.raw) };
416        Actuator::from_borrowed(raw)
417    }
418}
419
420impl fmt::Debug for Device {
421    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
422        f.debug_struct("Device")
423            .field("name", &self.name())
424            .field("device_id", &self.device_id())
425            .field("family_id", &self.family_id())
426            .field("is_running", &self.is_running())
427            .finish()
428    }
429}
430
431unsafe extern "C" fn contact_frame_callback(
432    device: MTDeviceRef,
433    data: *mut Contact,
434    count: i32,
435    _timestamp: f64,
436    _frame: i32,
437) -> i32 {
438    if data.is_null() || count < 0 {
439        return 0;
440    }
441    let inner = registry()
442        .lock()
443        .unwrap_or_else(|e| e.into_inner())
444        .get(&(device as usize))
445        .and_then(Weak::upgrade);
446    let Some(inner) = inner else { return 0 };
447
448    let contacts = unsafe { std::slice::from_raw_parts(data, count as usize) }.to_vec();
449    let mut subscribers = inner
450        .contact_subscribers
451        .lock()
452        .unwrap_or_else(|e| e.into_inner());
453    subscribers.retain(|weak| {
454        if let Some(queue) = weak.upgrade() {
455            queue.push(contacts.clone());
456            true
457        } else {
458            false
459        }
460    });
461    0
462}
463
464unsafe extern "C" fn path_callback(
465    device: MTDeviceRef,
466    path_id: isize,
467    stage: isize,
468    contact: *mut Contact,
469) {
470    if contact.is_null() {
471        return;
472    }
473    let inner = registry()
474        .lock()
475        .unwrap_or_else(|e| e.into_inner())
476        .get(&(device as usize))
477        .and_then(Weak::upgrade);
478    let Some(inner) = inner else { return };
479
480    let event = PathEvent {
481        path_id: path_id.max(0) as usize,
482        stage: ContactState::from_raw(stage as i32),
483        contact: unsafe { *contact },
484    };
485    let mut subscribers = inner
486        .path_subscribers
487        .lock()
488        .unwrap_or_else(|e| e.into_inner());
489    subscribers.retain(|weak| {
490        if let Some(queue) = weak.upgrade() {
491            queue.push(event);
492            true
493        } else {
494            false
495        }
496    });
497}
498
499pub struct ContactStream {
500    queue: Arc<Queue<Vec<Contact>>>,
501}
502
503impl ContactStream {
504    pub fn recv(&self) -> Option<Vec<Contact>> {
505        self.queue.recv()
506    }
507    pub fn try_recv(&self) -> Option<Vec<Contact>> {
508        self.queue.try_recv()
509    }
510    pub fn recv_timeout(&self, timeout: Duration) -> Option<Vec<Contact>> {
511        self.queue.recv_timeout(timeout)
512    }
513
514    pub fn into_receiver(self) -> mpsc::Receiver<Vec<Contact>> {
515        let (tx, rx) = mpsc::sync_channel(1);
516        std::thread::spawn(move || {
517            let mut stream = self;
518            for frame in &mut stream {
519                if tx.send(frame).is_err() {
520                    break;
521                }
522            }
523        });
524        rx
525    }
526}
527
528impl Iterator for ContactStream {
529    type Item = Vec<Contact>;
530    fn next(&mut self) -> Option<Self::Item> {
531        self.queue.recv()
532    }
533}
534
535pub struct PathStream {
536    queue: Arc<Queue<PathEvent>>,
537}
538
539impl PathStream {
540    pub fn recv(&self) -> Option<PathEvent> {
541        self.queue.recv()
542    }
543    pub fn try_recv(&self) -> Option<PathEvent> {
544        self.queue.try_recv()
545    }
546}
547
548impl Iterator for PathStream {
549    type Item = PathEvent;
550    fn next(&mut self) -> Option<Self::Item> {
551        self.queue.recv()
552    }
553}