diff --git a/platforms/macos/src/node.rs b/platforms/macos/src/node.rs index 29cc4fce..773f5668 100644 --- a/platforms/macos/src/node.rs +++ b/platforms/macos/src/node.rs @@ -23,8 +23,8 @@ use objc2::{ }; use objc2_app_kit::*; use objc2_foundation::{ - ns_string, NSArray, NSCopying, NSInteger, NSNumber, NSObject, NSPoint, NSRange, NSRect, - NSString, + ns_string, NSArray, NSCopying, NSInteger, NSNumber, NSObject, NSObjectProtocol, NSPoint, + NSRange, NSRect, NSString, }; use std::rc::{Rc, Weak}; @@ -357,6 +357,13 @@ impl NodeWrapper<'_> { } } +// derived from objc2 0.6 `AnyObject::downcast_ref` +// TODO: can be removed after updating objc2 to 0.6 which has `AnyObject::downcast_ref` +fn downcast_ref(obj: &NSObject) -> Option<&T> { + obj.is_kind_of::() + .then(|| unsafe { &*(obj as *const NSObject).cast::() }) +} + pub(crate) struct PlatformNodeIvars { context: Weak, node_id: NodeId, @@ -548,9 +555,24 @@ declare_class!( } #[method(setAccessibilityValue:)] - fn set_value(&self, _value: &NSObject) { - // This isn't yet implemented. See the comment on this selector - // in `is_selector_allowed`. + fn set_value(&self, value: &NSObject) { + if let Some(string) = downcast_ref::(value) { + self.resolve_with_context(|node, context| { + context.do_action(ActionRequest { + action: Action::SetValue, + target: node.id(), + data: Some(ActionData::Value(string.to_string().into())), + }); + }); + } else if let Some(number) = downcast_ref::(value) { + self.resolve_with_context(|node, context| { + context.do_action(ActionRequest { + action: Action::SetValue, + target: node.id(), + data: Some(ActionData::NumericValue(number.doubleValue())), + }); + }); + } } #[method_id(accessibilityMinValue)] @@ -1024,11 +1046,7 @@ declare_class!( return node.supports_text_ranges(); } if selector == sel!(setAccessibilityValue:) { - // Our implementation of this currently does nothing, - // and it's not clear if VoiceOver ever actually uses it, - // but it must be allowed for editable text in order to get - // the expected VoiceOver behavior. - return node.supports_text_ranges() && !node.is_read_only(); + return node.supports_action(Action::SetValue, &filter); } if selector == sel!(isAccessibilitySelected) { let wrapper = NodeWrapper(node);