Hi, I've been trying to play with using the Accessibility API to do some automated testing. From what I have researched, I have to use some C functions that often need a reference passed to the them. I am at a loss when trying to deal with Pointer objects. I've tried playing with them and googling it, but I just cannot figure out how to turn a pointer into a more useful type or to get what I want out of them. For example, I can start like this: framework 'Cocoa' unless AXAPIEnabled() # only works if I include the parenthesis puts 'Please enable Access for Assistive Devices first' exit 2 end mail = NSRunningApplication.runningApplicationsWithBundleIdentifier('com.apple.Mail').first mail_object = AXUIElementCreateApplication mail.processIdentifier names = Pointer.new :object AXUIElementCopyAttributeNames mail_object, names But then how do I get the values out of the names pointer? For reference, I found the functions in AXUIElement.h. Thanks, Mark
You can set pointers using: Pointer.new_with_type and using one of the following types: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCR... Note, that not none of the types are supported. Here is some more information: http://jonathan.waddilove.net/macruby_pointers.html To dereference a pointer, simply get its value: pointer = Pointer.new_with_type("f") pointer.assign(3.2) pointer's value = pointer[0] I'll soon update my book draft with a section on pointers. - Matt On Sat, Oct 23, 2010 at 10:04 PM, Mark Rada <mrada@marketcircle.com> wrote:
Hi,
I've been trying to play with using the Accessibility API to do some automated testing.
From what I have researched, I have to use some C functions that often need a reference passed to the them.
I am at a loss when trying to deal with Pointer objects. I've tried playing with them and googling it, but I just cannot figure out how to turn a pointer into a more useful type or to get what I want out of them.
For example, I can start like this:
framework 'Cocoa'
unless AXAPIEnabled() # only works if I include the parenthesis puts 'Please enable Access for Assistive Devices first' exit 2 end
mail = NSRunningApplication.runningApplicationsWithBundleIdentifier('com.apple.Mail').first mail_object = AXUIElementCreateApplication mail.processIdentifier
names = Pointer.new :object
AXUIElementCopyAttributeNames mail_object, names
But then how do I get the values out of the names pointer? For reference, I found the functions in AXUIElement.h.
Thanks, Mark _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
On 2010-10-24, at 05:06 , Matt Aimonetti wrote: Is there any difference if I do these instead:
pointer = Pointer.new_with_type("f")
p = Pointer.new(:float) #<= new instead of new_with_type
pointer.assign(3.2)
p[0] = 3.2 #<= #[]= instead of #assign I have used both successfully in the past. Just wondering if I was just lucky or if they're fine. Also, what's with the #[] thing anyway? What would I get using p[1], p[2]? Is this a way to deal with C arrays or otherwise do basic pointer arithmetics?
Hi Caio, On Oct 24, 2010, at 11:09 AM, Caio Chassot wrote:
On 2010-10-24, at 05:06 , Matt Aimonetti wrote:
Is there any difference if I do these instead:
pointer = Pointer.new_with_type("f")
p = Pointer.new(:float) #<= new instead of new_with_type
pointer.assign(3.2)
p[0] = 3.2 #<= #[]= instead of #assign
I have used both successfully in the past. Just wondering if I was just lucky or if they're fine.
They are the same :)
Also, what's with the #[] thing anyway? What would I get using p[1], p[2]? Is this a way to deal with C arrays or otherwise do basic pointer arithmetics?
A Pointer object allows you to allocate memory of a given type for a given number of elements. You can create an array of floats for example. Then, #[] and #[]= make sense to get/set elements of this array. Pointer objects are also returned by MacRuby when calling a native API that returns a pointer to something. For example, float *. The API documentation might state that it's one float, or an array of floats. In this case, MacRuby doesn't really know much about the pointer itself (like its bounds), which is why using #[] and #[]= must be done in a very careful way. Laurent
Hey, Thanks for the response. It has helped, but I am still confused a bit by you stating that none of the types are supported but that I can still dereference a pointer. I have now been able to dereference some pointers, but not pointers to pointers. Is that what you meant? In these cases I guess I will have to create an objective-c wrapper. I found an entry on the MacRuby site about creating bundles which I think is a good solution. Thanks for the pointers, Mark Sent from my iDevice On 2010-10-24, at 3:06, Matt Aimonetti <mattaimonetti@gmail.com> wrote:
You can set pointers using:
Pointer.new_with_type and using one of the following types: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCR... Note, that not none of the types are supported.
Here is some more information: http://jonathan.waddilove.net/macruby_pointers.html
To dereference a pointer, simply get its value:
pointer = Pointer.new_with_type("f") pointer.assign(3.2) pointer's value = pointer[0]
I'll soon update my book draft with a section on pointers.
- Matt
On Sat, Oct 23, 2010 at 10:04 PM, Mark Rada <mrada@marketcircle.com> wrote: Hi,
I've been trying to play with using the Accessibility API to do some automated testing.
From what I have researched, I have to use some C functions that often need a reference passed to the them.
I am at a loss when trying to deal with Pointer objects. I've tried playing with them and googling it, but I just cannot figure out how to turn a pointer into a more useful type or to get what I want out of them.
For example, I can start like this:
framework 'Cocoa'
unless AXAPIEnabled() # only works if I include the parenthesis puts 'Please enable Access for Assistive Devices first' exit 2 end
mail = NSRunningApplication.runningApplicationsWithBundleIdentifier('com.apple.Mail').first mail_object = AXUIElementCreateApplication mail.processIdentifier
names = Pointer.new :object
AXUIElementCopyAttributeNames mail_object, names
But then how do I get the values out of the names pointer? For reference, I found the functions in AXUIElement.h.
Thanks, Mark _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
Hi Mark, Matt already replied but I thought I would give more info. On Oct 23, 2010, at 10:04 PM, Mark Rada wrote:
Hi,
I've been trying to play with using the Accessibility API to do some automated testing.
From what I have researched, I have to use some C functions that often need a reference passed to the them.
I am at a loss when trying to deal with Pointer objects. I've tried playing with them and googling it, but I just cannot figure out how to turn a pointer into a more useful type or to get what I want out of them.
For example, I can start like this:
framework 'Cocoa'
unless AXAPIEnabled() # only works if I include the parenthesis puts 'Please enable Access for Assistive Devices first' exit 2 end
That's expected, in Ruby methods starting with a capital letter must be called with explicit parentheses, otherwise they are interpreted as constants.
mail = NSRunningApplication.runningApplicationsWithBundleIdentifier('com.apple.Mail').first mail_object = AXUIElementCreateApplication mail.processIdentifier
names = Pointer.new :object
AXUIElementCopyAttributeNames mail_object, names
But then how do I get the values out of the names pointer? For reference, I found the functions in AXUIElement.h.
It looks like AXUIElementCopyAttributeNames returns a CFArray by reference. So your pointer object is properly created, to retrieve the array after the call you just use array = names[0] Then, it should behave like a normal Ruby array. Laurent
On 2010-10-24, at 9:34 PM, Laurent Sansonetti wrote:
Hi Mark,
Matt already replied but I thought I would give more info.
On Oct 23, 2010, at 10:04 PM, Mark Rada wrote:
Hi,
I've been trying to play with using the Accessibility API to do some automated testing.
From what I have researched, I have to use some C functions that often need a reference passed to the them.
I am at a loss when trying to deal with Pointer objects. I've tried playing with them and googling it, but I just cannot figure out how to turn a pointer into a more useful type or to get what I want out of them.
For example, I can start like this:
framework 'Cocoa'
unless AXAPIEnabled() # only works if I include the parenthesis puts 'Please enable Access for Assistive Devices first' exit 2 end
That's expected, in Ruby methods starting with a capital letter must be called with explicit parentheses, otherwise they are interpreted as constants.
Ah, that makes more sense now.
mail = NSRunningApplication.runningApplicationsWithBundleIdentifier('com.apple.Mail').first mail_object = AXUIElementCreateApplication mail.processIdentifier
names = Pointer.new :object
AXUIElementCopyAttributeNames mail_object, names
But then how do I get the values out of the names pointer? For reference, I found the functions in AXUIElement.h.
It looks like AXUIElementCopyAttributeNames returns a CFArray by reference. So your pointer object is properly created, to retrieve the array after the call you just use
array = names[0]
Then, it should behave like a normal Ruby array.
Ah, that does work, and seems to have worked for a number of other things I am trying to do. The only problem now is when I have something like value = Pointer.new '^v' # pointer to pointer to void AXUIElementCopyAttributeValue mail_object, 'AXHidden', value In this case I am using it right now, it will be returning a boolean, but when I try to dereference it like puts value[0][0] # => 120 it gives me a Fixnum, and then I can keep trying things like puts value[0][1] # => 104 puts value[0][10000] # => 0 And I seem to get nowhere. Is there a way to cast the data back into the type I want it to be? Or am I doing something dumb? Thanks, Mark
Laurent _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
Hi Mark,
Ah, that does work, and seems to have worked for a number of other things I am trying to do.
The only problem now is when I have something like
value = Pointer.new '^v' # pointer to pointer to void AXUIElementCopyAttributeValue mail_object, 'AXHidden', value
In this case I am using it right now, it will be returning a boolean, but when I try to dereference it like
puts value[0][0] # => 120
it gives me a Fixnum, and then I can keep trying things like
puts value[0][1] # => 104 puts value[0][10000] # => 0
And I seem to get nowhere.
Is there a way to cast the data back into the type I want it to be? Or am I doing something dumb?
Looks like this function has the following declaration: extern AXError AXUIElementCopyAttributeValue (AXUIElementRef element, CFStringRef attribute, CFTypeRef *value); So, the 3rd argument is is a CF object returned by reference. You should be able to do the following then: ptr = Pointer.new(:id) AXUIElementCopyAttributeValue(mail_object, 'AXHidden', ptr) value = ptr[0] To reply to your other question, it is possible to cast the type of a Pointer object, using the #cast! method. Sometimes this is useful when you get a void pointer from a native API and want to cast it into something more useful. But you should be careful, MacRuby will not prevent you from doing bad casts. Laurent
On 2010-10-25, at 11:39 PM, Laurent Sansonetti wrote:
Hi Mark,
Ah, that does work, and seems to have worked for a number of other things I am trying to do.
The only problem now is when I have something like
value = Pointer.new '^v' # pointer to pointer to void AXUIElementCopyAttributeValue mail_object, 'AXHidden', value
In this case I am using it right now, it will be returning a boolean, but when I try to dereference it like
puts value[0][0] # => 120
it gives me a Fixnum, and then I can keep trying things like
puts value[0][1] # => 104 puts value[0][10000] # => 0
And I seem to get nowhere.
Is there a way to cast the data back into the type I want it to be? Or am I doing something dumb?
Looks like this function has the following declaration:
extern AXError AXUIElementCopyAttributeValue (AXUIElementRef element, CFStringRef attribute, CFTypeRef *value);
So, the 3rd argument is is a CF object returned by reference.
You should be able to do the following then:
ptr = Pointer.new(:id) AXUIElementCopyAttributeValue(mail_object, 'AXHidden', ptr) value = ptr[0]
To reply to your other question, it is possible to cast the type of a Pointer object, using the #cast! method. Sometimes this is useful when you get a void pointer from a native API and want to cast it into something more useful. But you should be careful, MacRuby will not prevent you from doing bad casts.
Hmm, I tried that but it did not work. The error I got was: TypeError: expected instance of Pointer of type `^v', got `@' So I tried to see if I could cast a '^v' Pointer, but I do not know how #cast! wants the argument to be phrased, when I checked macri, I got this error: # macri Pointer /Library/Frameworks/MacRuby.framework/Versions/0.7.1/usr/lib/ruby/1.9.2/rdoc/ri/driver.rb:383:in `create_class_cache': Permission denied - open() failed (Errno::EACCES) from /Library/Frameworks/MacRuby.framework/Versions/0.7.1/usr/lib/ruby/1.9.2/rdoc/ri/driver.rb:342:in `class_cache' from /Library/Frameworks/MacRuby.framework/Versions/0.7.1/usr/lib/ruby/1.9.2/rdoc/ri/driver.rb:596:in `block' from /Library/Frameworks/MacRuby.framework/Versions/0.7.1/usr/lib/ruby/1.9.2/rdoc/ri/driver.rb:591:in `run' from /usr/local/bin/macri:3:in `<main>' zsh: exit 1 macri Pointer My feeble attempts to try and coerce a String from the pointer Pointer ended like this: irb(main):029:0> value = test[0].cast! 'String' => #<Pointer:0x200c2ab80> irb(main):030:0> value = test[0][0].cast! 'String' NoMethodError: undefined method `cast!' for 120:Fixnum But I don't know if it is because I am using #cast! incorrectly or not. Also, in cases where I want to cast a boolean pointer into MacRuby would I have to do some additional logic to decide to cast to TrueClass and FalseClass or is there some more convenient way that will figure it out for me? Thanks, Mark
Laurent _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
participants (4)
-
Caio Chassot
-
Laurent Sansonetti
-
Mark Rada
-
Matt Aimonetti