accessibility_ng/
value.rs

1#![allow(non_upper_case_globals)]
2use std::convert::TryFrom;
3use std::{ffi::c_void, mem::MaybeUninit};
4
5use crate::Error;
6
7use cocoa::appkit::CGPoint;
8use core_foundation::base::{CFRange, TCFType};
9use core_foundation::{declare_TCFType, impl_CFTypeDescription, impl_TCFType};
10
11use accessibility_sys_ng::{
12    kAXValueTypeAXError, kAXValueTypeCFRange, kAXValueTypeCGPoint, kAXValueTypeCGRect,
13    kAXValueTypeCGSize, kAXValueTypeIllegal, AXValueCreate, AXValueGetType, AXValueGetTypeID,
14    AXValueGetValue, AXValueRef, AXValueType,
15};
16use core_graphics_types::geometry::{CGRect, CGSize};
17
18declare_TCFType!(AXValue, AXValueRef);
19impl_TCFType!(AXValue, AXValueRef, AXValueGetTypeID);
20impl_CFTypeDescription!(AXValue);
21
22// AXValues can only be of type CGPoint, CGSize, CGRect, or CFRange.
23pub trait ValidAXValueType {}
24impl ValidAXValueType for CGRect {}
25impl ValidAXValueType for CGSize {}
26impl ValidAXValueType for CGPoint {}
27impl ValidAXValueType for CFRange {}
28
29impl AXValue {
30    #[allow(non_snake_case)]
31    pub fn from_CGSize(mut size: CGSize) -> Result<Self, Error> {
32        unsafe {
33            Ok(Self::wrap_under_create_rule(AXValueCreate(
34                kAXValueTypeCGSize,
35                &mut size as *mut _ as *mut c_void,
36            )))
37        }
38    }
39
40    #[allow(non_snake_case)]
41    pub fn from_CGPoint(mut point: CGPoint) -> Result<Self, Error> {
42        unsafe {
43            Ok(Self::wrap_under_create_rule(AXValueCreate(
44                kAXValueTypeCGPoint,
45                &mut point as *mut _ as *mut c_void,
46            )))
47        }
48    }
49
50    #[allow(non_snake_case)]
51    pub fn from_CGRect(mut rect: CGRect) -> Result<Self, Error> {
52        unsafe {
53            Ok(Self::wrap_under_create_rule(AXValueCreate(
54                kAXValueTypeCGRect,
55                &mut rect as *mut _ as *mut c_void,
56            )))
57        }
58    }
59
60    #[allow(non_snake_case)]
61    pub fn from_CFRange(mut range: CFRange) -> Result<Self, Error> {
62        unsafe {
63            Ok(Self::wrap_under_create_rule(AXValueCreate(
64                kAXValueTypeCFRange,
65                &mut range as *mut _ as *mut c_void,
66            )))
67        }
68    }
69
70    pub fn get_type(&self) -> AXValueType {
71        unsafe { AXValueGetType(self.0) }
72    }
73
74    pub fn get_value<T: ValidAXValueType>(&self) -> Result<T, Error> {
75        unsafe {
76            // Verify that the value is requested of the correct type.
77            match self.get_type() {
78                kAXValueTypeAXError => {
79                    return Err(Error::Ax(helper_u32_to_i32(kAXValueTypeAXError)));
80                }
81                kAXValueTypeIllegal => {
82                    return Err(Error::Ax(helper_u32_to_i32(kAXValueTypeIllegal)));
83                }
84                kAXValueTypeCGPoint => {
85                    if std::any::type_name::<T>() != "core_graphics_types::geometry::CGPoint" {
86                        return Err(Error::Ax(helper_u32_to_i32(kAXValueTypeAXError)));
87                    }
88                }
89                kAXValueTypeCGSize => {
90                    if std::any::type_name::<T>() != "core_graphics_types::geometry::CGSize" {
91                        return Err(Error::Ax(helper_u32_to_i32(kAXValueTypeAXError)));
92                    }
93                }
94                kAXValueTypeCGRect => {
95                    if std::any::type_name::<T>() != "core_graphics_types::geometry::CGRect" {
96                        return Err(Error::Ax(helper_u32_to_i32(kAXValueTypeAXError)));
97                    }
98                }
99                kAXValueTypeCFRange => {
100                    if std::any::type_name::<T>() != "core_foundation_sys::base::CFRange" {
101                        return Err(Error::Ax(helper_u32_to_i32(kAXValueTypeAXError)));
102                    }
103                }
104                other => {
105                    assert!(false, "unexpected AXValueType: {}", other);
106                }
107            }
108
109            let mut value = MaybeUninit::<T>::uninit();
110            let mut_ptr = &mut value as *mut _ as *mut c_void;
111
112            if AXValueGetValue(self.0, self.get_type(), mut_ptr) {
113                Ok(value.assume_init() as T)
114            } else {
115                Err(Error::Ax(helper_u32_to_i32(kAXValueTypeAXError)))
116            }
117        }
118    }
119}
120
121// Just a helper to convert between i32 and u32; it is safe, because the values for u32 are known here and are small enough.
122fn helper_u32_to_i32(v: u32) -> i32 {
123    i32::try_from(v).ok().unwrap()
124}