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 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 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 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}