AXElements 0.7.5 → 0.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/accessibility/core.rb +56 -37
- data/lib/accessibility/dsl.rb +2 -2
- data/lib/accessibility/factory.rb +9 -14
- data/lib/accessibility/pp_inspector.rb +0 -1
- data/lib/accessibility/version.rb +1 -1
- data/lib/ax/application.rb +8 -1
- data/lib/ax/element.rb +28 -30
- data/test/integration/accessibility/test_dsl.rb +16 -0
- data/test/integration/ax/test_application.rb +8 -4
- data/test/integration/ax/test_element.rb +0 -4
- data/test/sanity/accessibility/test_core.rb +5 -5
- metadata +2 -2
data/lib/accessibility/core.rb
CHANGED
@@ -98,13 +98,13 @@ module Accessibility::Core
|
|
98
98
|
def attribute name
|
99
99
|
ptr = Pointer.new :id
|
100
100
|
case code = AXUIElementCopyAttributeValue(self, name, ptr)
|
101
|
-
when 0
|
102
|
-
|
103
|
-
when
|
101
|
+
when 0
|
102
|
+
ptr.value.to_ruby
|
103
|
+
when KAXErrorNoValue, KAXErrorAttributeUnsupported,
|
104
|
+
KAXErrorFailure, KAXErrorInvalidUIElement then
|
104
105
|
name == KAXChildrenAttribute ? [] : nil
|
105
|
-
|
106
|
-
|
107
|
-
else handle_error code, name
|
106
|
+
else
|
107
|
+
handle_error code, name
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
@@ -177,10 +177,13 @@ module Accessibility::Core
|
|
177
177
|
def size_of name
|
178
178
|
ptr = Pointer.new :long_long
|
179
179
|
case code = AXUIElementGetAttributeValueCount(self, name, ptr)
|
180
|
-
when 0
|
180
|
+
when 0
|
181
|
+
ptr.value
|
181
182
|
when KAXErrorFailure, KAXErrorAttributeUnsupported,
|
182
|
-
|
183
|
-
|
183
|
+
KAXErrorNoValue, KAXErrorInvalidUIElement
|
184
|
+
0
|
185
|
+
else
|
186
|
+
handle_error code, name
|
184
187
|
end
|
185
188
|
end
|
186
189
|
|
@@ -196,9 +199,13 @@ module Accessibility::Core
|
|
196
199
|
def writable? name
|
197
200
|
ptr = Pointer.new :bool
|
198
201
|
case code = AXUIElementIsAttributeSettable(self, name, ptr)
|
199
|
-
when 0
|
200
|
-
|
201
|
-
|
202
|
+
when 0
|
203
|
+
ptr.value
|
204
|
+
when KAXErrorFailure, KAXErrorAttributeUnsupported,
|
205
|
+
KAXErrorNoValue, KAXErrorInvalidUIElement
|
206
|
+
false
|
207
|
+
else
|
208
|
+
handle_error code, name
|
202
209
|
end
|
203
210
|
end
|
204
211
|
|
@@ -223,8 +230,11 @@ module Accessibility::Core
|
|
223
230
|
# @param [String] name an attribute constant
|
224
231
|
def set name, value
|
225
232
|
code = AXUIElementSetAttributeValue(self, name, value.to_ax)
|
226
|
-
|
227
|
-
|
233
|
+
if code.zero?
|
234
|
+
value
|
235
|
+
else
|
236
|
+
handle_error code, name, value
|
237
|
+
end
|
228
238
|
end
|
229
239
|
|
230
240
|
|
@@ -270,12 +280,15 @@ module Accessibility::Core
|
|
270
280
|
# @param [String] attr an attribute constant
|
271
281
|
# @param [Object] param
|
272
282
|
def attribute name, for_parameter: param
|
273
|
-
ptr
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
when
|
278
|
-
|
283
|
+
ptr = Pointer.new :id
|
284
|
+
case code = AXUIElementCopyParameterizedAttributeValue(self, name, param.to_ax, ptr)
|
285
|
+
when 0
|
286
|
+
ptr.value.to_ruby
|
287
|
+
when KAXErrorFailure, KAXErrorAttributeUnsupported,
|
288
|
+
KAXErrorNoValue, KAXErrorInvalidUIElement
|
289
|
+
nil
|
290
|
+
else
|
291
|
+
handle_error code, name, param
|
279
292
|
end
|
280
293
|
end
|
281
294
|
|
@@ -318,8 +331,11 @@ module Accessibility::Core
|
|
318
331
|
# @return [Boolean]
|
319
332
|
def perform action
|
320
333
|
code = AXUIElementPerformAction(self, action)
|
321
|
-
|
322
|
-
|
334
|
+
if code.zero?
|
335
|
+
true
|
336
|
+
else
|
337
|
+
handle_error code, action
|
338
|
+
end
|
323
339
|
end
|
324
340
|
|
325
341
|
##
|
@@ -398,9 +414,14 @@ module Accessibility::Core
|
|
398
414
|
def element_at point
|
399
415
|
ptr = Pointer.new ELEMENT
|
400
416
|
case code = AXUIElementCopyElementAtPosition(self, *point.to_point, ptr)
|
401
|
-
when 0
|
402
|
-
|
403
|
-
|
417
|
+
when 0
|
418
|
+
ptr.value
|
419
|
+
when KAXErrorNoValue
|
420
|
+
nil
|
421
|
+
when KAXErrorInvalidUIElement
|
422
|
+
system_wide.element_at point unless self == system_wide
|
423
|
+
else
|
424
|
+
handle_error code, point, nil, nil
|
404
425
|
end
|
405
426
|
end
|
406
427
|
|
@@ -453,9 +474,11 @@ module Accessibility::Core
|
|
453
474
|
raise ArgumentError, 'A callback is required' unless block_given?
|
454
475
|
ptr = Pointer.new OBSERVER
|
455
476
|
callback = proc { |obsrvr, sender, notif, ctx| yield obsrvr, sender, notif }
|
456
|
-
|
457
|
-
|
458
|
-
|
477
|
+
code = AXObserverCreate(pid, callback, ptr)
|
478
|
+
if code.zero?
|
479
|
+
ptr.value
|
480
|
+
else
|
481
|
+
handle_error code, callback
|
459
482
|
end
|
460
483
|
end
|
461
484
|
|
@@ -540,12 +563,14 @@ module Accessibility::Core
|
|
540
563
|
# @return [Fixnum]
|
541
564
|
def pid
|
542
565
|
@pid ||= (
|
543
|
-
ptr
|
566
|
+
ptr = Pointer.new :int
|
544
567
|
case code = AXUIElementGetPid(self, ptr)
|
545
|
-
when 0
|
568
|
+
when 0
|
569
|
+
ptr.value
|
546
570
|
when KAXErrorInvalidUIElement
|
547
571
|
self == system_wide ? 0 : handle_error(code)
|
548
|
-
else
|
572
|
+
else
|
573
|
+
handle_error code
|
549
574
|
end
|
550
575
|
)
|
551
576
|
end
|
@@ -889,9 +914,3 @@ class CGPoint
|
|
889
914
|
# @return [CGPoint]
|
890
915
|
def to_point; self end
|
891
916
|
end
|
892
|
-
|
893
|
-
##
|
894
|
-
# Cached reference to the system wide object.
|
895
|
-
#
|
896
|
-
# @return [AXUIElementRef]
|
897
|
-
SYSTEMWIDE = AXUIElementCreateSystemWide()
|
data/lib/accessibility/dsl.rb
CHANGED
@@ -210,7 +210,7 @@ module Accessibility::DSL
|
|
210
210
|
#
|
211
211
|
# @param [AX::Element]
|
212
212
|
def set_focus_to element
|
213
|
-
element.set(:focused, true) if element.respond_to? :focused
|
213
|
+
element.set(:focused, true) if element.respond_to? :focused
|
214
214
|
end
|
215
215
|
alias_method :set_focus, :set_focus_to
|
216
216
|
|
@@ -243,7 +243,7 @@ module Accessibility::DSL
|
|
243
243
|
# @return [nil] do not rely on a return value
|
244
244
|
def set element, change
|
245
245
|
if element.respond_to? :focused
|
246
|
-
if element.
|
246
|
+
if element.writable? :focused
|
247
247
|
element.set :focused, true
|
248
248
|
end
|
249
249
|
end
|
@@ -66,16 +66,11 @@ module Accessibility::Factory
|
|
66
66
|
# @param [AXUIElementRef]
|
67
67
|
# @return [AX::Element]
|
68
68
|
def process_element ref
|
69
|
-
role
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
if subrole
|
75
|
-
class_for TRANSLATOR.unprefix(subrole), and: role
|
76
|
-
else
|
77
|
-
class_for role
|
78
|
-
end
|
69
|
+
role = TRANSLATOR.unprefix ref.role
|
70
|
+
|
71
|
+
# Some objects claim to have a subrole but return nil
|
72
|
+
klass = if subrole = ref.subrole
|
73
|
+
class_for TRANSLATOR.unprefix(subrole), and: role
|
79
74
|
else
|
80
75
|
class_for role
|
81
76
|
end
|
@@ -87,9 +82,9 @@ module Accessibility::Factory
|
|
87
82
|
#
|
88
83
|
# @return [Array]
|
89
84
|
def process_array vals
|
90
|
-
|
91
|
-
|
92
|
-
|
85
|
+
(vals.empty? && vals) ||
|
86
|
+
(CFGetTypeID(vals.first) != REF_TYPE && vals) ||
|
87
|
+
vals.map { |val| process_element val }
|
93
88
|
end
|
94
89
|
|
95
90
|
##
|
@@ -137,7 +132,7 @@ module Accessibility::Factory
|
|
137
132
|
|
138
133
|
##
|
139
134
|
# Create a new class in the {AX} namesapce that has the given
|
140
|
-
# `superklass` as the superclass
|
135
|
+
# `superklass` as the superclass.
|
141
136
|
#
|
142
137
|
# @param [#to_s] name
|
143
138
|
# @param [#to_s] superklass
|
data/lib/ax/application.rb
CHANGED
@@ -9,6 +9,13 @@ require 'accessibility/string'
|
|
9
9
|
class AX::Application < AX::Element
|
10
10
|
include Accessibility::String
|
11
11
|
|
12
|
+
##
|
13
|
+
# @private
|
14
|
+
# Cached reference to the system wide object.
|
15
|
+
#
|
16
|
+
# @return [AXUIElementRef]
|
17
|
+
SYSTEMWIDE = AXUIElementCreateSystemWide()
|
18
|
+
|
12
19
|
##
|
13
20
|
# Overridden so that we can also cache the `NSRunningApplication`
|
14
21
|
# instance for this object.
|
@@ -81,7 +88,7 @@ class AX::Application < AX::Element
|
|
81
88
|
# Overridden to handle the {Accessibility::Language#set_focus} case.
|
82
89
|
#
|
83
90
|
# (see AX::Element#set:to:)
|
84
|
-
def set attr,
|
91
|
+
def set attr, value
|
85
92
|
case attr
|
86
93
|
when :focused
|
87
94
|
perform(value ? :unhide : :hide)
|
data/lib/ax/element.rb
CHANGED
@@ -17,6 +17,7 @@ class AX::Element
|
|
17
17
|
include Accessibility::PPInspector
|
18
18
|
include Accessibility::Factory
|
19
19
|
|
20
|
+
|
20
21
|
# @param [AXUIElementRef]
|
21
22
|
def initialize ref
|
22
23
|
@ref = ref
|
@@ -34,7 +35,7 @@ class AX::Element
|
|
34
35
|
#
|
35
36
|
# @return [Array<Symbol>]
|
36
37
|
def attributes
|
37
|
-
@
|
38
|
+
@attrs ||= TRANSLATOR.rubyize @ref.attributes
|
38
39
|
end
|
39
40
|
|
40
41
|
##
|
@@ -49,14 +50,15 @@ class AX::Element
|
|
49
50
|
#
|
50
51
|
# @param [#to_sym]
|
51
52
|
def attribute name
|
52
|
-
if rattr = lookup(name, @ref.attributes)
|
53
|
+
if rattr = TRANSLATOR.lookup(name, @ref.attributes)
|
53
54
|
process @ref.attribute(rattr)
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
57
58
|
##
|
58
|
-
# Needed to override inherited `NSObject#description
|
59
|
-
#
|
59
|
+
# Needed to override inherited `NSObject#description` as some
|
60
|
+
# elements have a `description` attribute. If you want a description
|
61
|
+
# of the object then you should use {#inspect} instead.
|
60
62
|
def description
|
61
63
|
attribute :description
|
62
64
|
end
|
@@ -75,7 +77,7 @@ class AX::Element
|
|
75
77
|
# @param [#to_sym]
|
76
78
|
# @return [Number]
|
77
79
|
def size_of attr
|
78
|
-
if rattr = lookup(attr, @ref.attributes)
|
80
|
+
if rattr = TRANSLATOR.lookup(attr, @ref.attributes)
|
79
81
|
@ref.size_of rattr
|
80
82
|
else
|
81
83
|
0
|
@@ -105,7 +107,7 @@ class AX::Element
|
|
105
107
|
#
|
106
108
|
# @param [#to_sym]
|
107
109
|
def writable? attr
|
108
|
-
if rattr = lookup(attr, @ref.attributes)
|
110
|
+
if rattr = TRANSLATOR.lookup(attr, @ref.attributes)
|
109
111
|
@ref.writable? rattr
|
110
112
|
else
|
111
113
|
false
|
@@ -127,9 +129,7 @@ class AX::Element
|
|
127
129
|
raise NoMethodError, "#{attr} is read-only for #{inspect}"
|
128
130
|
end
|
129
131
|
value = value.relative_to(@ref.value.size) if value.kind_of? Range
|
130
|
-
|
131
|
-
@ref.set rattr, value
|
132
|
-
value
|
132
|
+
@ref.set TRANSLATOR.lookup(attr, @ref.attributes), value
|
133
133
|
end
|
134
134
|
|
135
135
|
|
@@ -146,7 +146,7 @@ class AX::Element
|
|
146
146
|
#
|
147
147
|
# @return [Array<Symbol>]
|
148
148
|
def parameterized_attributes
|
149
|
-
TRANSLATOR.rubyize @ref.parameterized_attributes
|
149
|
+
@param_attrs ||= TRANSLATOR.rubyize @ref.parameterized_attributes
|
150
150
|
end
|
151
151
|
|
152
152
|
##
|
@@ -158,7 +158,7 @@ class AX::Element
|
|
158
158
|
#
|
159
159
|
# @param [#to_sym]
|
160
160
|
def attribute attr, for_parameter: param
|
161
|
-
if rattr = lookup(attr, @ref.parameterized_attributes)
|
161
|
+
if rattr = TRANSLATOR.lookup(attr, @ref.parameterized_attributes)
|
162
162
|
param = param.relative_to(@ref.value.size) if value.kind_of? Range
|
163
163
|
process @ref.attribute(rattr, for_parameter: param)
|
164
164
|
end
|
@@ -178,7 +178,7 @@ class AX::Element
|
|
178
178
|
#
|
179
179
|
# @return [Array<Symbol>]
|
180
180
|
def actions
|
181
|
-
TRANSLATOR.rubyize @ref.actions
|
181
|
+
@actions ||= TRANSLATOR.rubyize @ref.actions
|
182
182
|
end
|
183
183
|
|
184
184
|
##
|
@@ -191,12 +191,13 @@ class AX::Element
|
|
191
191
|
#
|
192
192
|
# @example
|
193
193
|
#
|
194
|
-
# button.perform :press
|
194
|
+
# button.perform :press # => true
|
195
|
+
# button.perform :make_pie # => false
|
195
196
|
#
|
196
197
|
# @param [#to_sym]
|
197
198
|
# @return [Boolean] true if successful
|
198
199
|
def perform action
|
199
|
-
if raction = lookup(action, @ref.actions)
|
200
|
+
if raction = TRANSLATOR.lookup(action, @ref.actions)
|
200
201
|
@ref.perform raction
|
201
202
|
else
|
202
203
|
false
|
@@ -226,7 +227,7 @@ class AX::Element
|
|
226
227
|
tree = Accessibility::Enumerators::BreadthFirst.new(self)
|
227
228
|
|
228
229
|
if TRANSLATOR.singularize(kind) == kind
|
229
|
-
tree.find
|
230
|
+
tree.find { |element| qualifier.qualifies? element }
|
230
231
|
else
|
231
232
|
tree.find_all { |element| qualifier.qualifies? element }
|
232
233
|
end
|
@@ -300,16 +301,18 @@ class AX::Element
|
|
300
301
|
if method[-1] == EQUALS
|
301
302
|
return set(method.chomp(EQUALS), args.first)
|
302
303
|
|
303
|
-
elsif
|
304
|
-
return
|
304
|
+
elsif attributes.include? method
|
305
|
+
return attribute method
|
305
306
|
|
306
|
-
elsif
|
307
|
-
return
|
307
|
+
elsif parameterized_attributes.include? method
|
308
|
+
return attribute method, for_parameter: args.first
|
308
309
|
|
309
|
-
elsif
|
310
|
-
result = search method, *args, &block
|
311
|
-
|
312
|
-
|
310
|
+
elsif attributes.include? :children
|
311
|
+
if (result = search method, *args, &block).blank?
|
312
|
+
raise Accessibility::SearchFailure.new(self, method, args.first)
|
313
|
+
else
|
314
|
+
return result
|
315
|
+
end
|
313
316
|
|
314
317
|
else
|
315
318
|
super
|
@@ -416,8 +419,8 @@ class AX::Element
|
|
416
419
|
# Overriden to respond properly with regards to dynamic attribute
|
417
420
|
# lookups, but will return false for potential implicit searches.
|
418
421
|
def respond_to? name
|
419
|
-
|
420
|
-
|
422
|
+
attributes.include?(name) ||
|
423
|
+
parameterized_attributes.include?(name) ||
|
421
424
|
super
|
422
425
|
end
|
423
426
|
|
@@ -486,11 +489,6 @@ class AX::Element
|
|
486
489
|
# @return [String]
|
487
490
|
EQUALS = '='
|
488
491
|
|
489
|
-
def lookup key, values
|
490
|
-
value = TRANSLATOR.lookup key, values
|
491
|
-
return value if values.include? value
|
492
|
-
end
|
493
|
-
|
494
492
|
def notif_callback_for
|
495
493
|
# we are ignoring the context pointer since this is OO
|
496
494
|
Proc.new do |observer, sender, notif, _|
|
@@ -59,6 +59,22 @@ class TestAccessibilityDSL < MiniTest::Unit::TestCase
|
|
59
59
|
assert_equal app, dsl.app_with_pid(PID)
|
60
60
|
end
|
61
61
|
|
62
|
+
def test_set_focus_to
|
63
|
+
assert dsl.set_focus_to app
|
64
|
+
assert dsl.set_focus app
|
65
|
+
assert dsl.set_focus_to app.main_window.search_field
|
66
|
+
assert dsl.set_focus app.main_window.search_field
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_set
|
70
|
+
expected = 'Octocat is not Hello Kitty!'
|
71
|
+
field = app.main_window.search_field
|
72
|
+
dsl.set field, expected
|
73
|
+
assert_equal expected, field.value
|
74
|
+
ensure
|
75
|
+
field.set :value, '' if field
|
76
|
+
end
|
77
|
+
|
62
78
|
def test_typing_human_string
|
63
79
|
try_typing "A sentence, with punctuation and num8ers. LOL!\tA 'quoted' string--then some @#*$."
|
64
80
|
end
|
@@ -17,12 +17,12 @@ class TestAXApplication < MiniTest::Unit::TestCase
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def test_can_set_focus_and_blur_app # lol, blur
|
20
|
-
assert app.set :focused,
|
20
|
+
assert app.set :focused, false
|
21
21
|
refute app.active?
|
22
22
|
refute app.attribute :focused
|
23
23
|
refute app.attribute :focused?
|
24
24
|
|
25
|
-
assert app.set :focused,
|
25
|
+
assert app.set :focused, true
|
26
26
|
assert app.active?
|
27
27
|
assert app.attribute :focused
|
28
28
|
assert app.attribute :focused?
|
@@ -32,10 +32,10 @@ class TestAXApplication < MiniTest::Unit::TestCase
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def test_can_hide_and_unhide_app
|
35
|
-
assert app.set :hidden,
|
35
|
+
assert app.set :hidden, true
|
36
36
|
assert app.hidden?
|
37
37
|
|
38
|
-
assert app.set :hidden,
|
38
|
+
assert app.set :hidden, false
|
39
39
|
refute app.hidden?
|
40
40
|
|
41
41
|
assert app.perform :hide
|
@@ -48,6 +48,10 @@ class TestAXApplication < MiniTest::Unit::TestCase
|
|
48
48
|
running_app.activateWithOptions NSApplicationActivateIgnoringOtherApps
|
49
49
|
end
|
50
50
|
|
51
|
+
def test_set_calls_super
|
52
|
+
assert app.set(:enhanced_user_interface, true)
|
53
|
+
end
|
54
|
+
|
51
55
|
def test_element_at_point
|
52
56
|
button = app.main_window.close_button
|
53
57
|
assert_equal button, app.element_at_point(button)
|
@@ -70,7 +70,7 @@ class TestAccessibilityCore < MiniTest::Unit::TestCase
|
|
70
70
|
assert_equal 10..19, window.attribute("AXPie" )
|
71
71
|
end
|
72
72
|
|
73
|
-
def
|
73
|
+
def test_attribute_when_no_value
|
74
74
|
assert_nil window.attribute(KAXGrowAreaAttribute)
|
75
75
|
end
|
76
76
|
|
@@ -79,8 +79,8 @@ class TestAccessibilityCore < MiniTest::Unit::TestCase
|
|
79
79
|
assert_empty invalid_ref.attribute(KAXChildrenAttribute)
|
80
80
|
end
|
81
81
|
|
82
|
-
def
|
83
|
-
|
82
|
+
def test_attribute_when_not_supported_attribute
|
83
|
+
assert_nil REF.attribute('MADEUPATTRIBUTE')
|
84
84
|
end
|
85
85
|
|
86
86
|
def test_role
|
@@ -120,8 +120,8 @@ class TestAccessibilityCore < MiniTest::Unit::TestCase
|
|
120
120
|
refute invalid_ref.writable? KAXRoleAttribute
|
121
121
|
end
|
122
122
|
|
123
|
-
def
|
124
|
-
|
123
|
+
def test_writable_false_for_bad_attributes
|
124
|
+
refute REF.writable? 'FAKE'
|
125
125
|
end
|
126
126
|
|
127
127
|
def test_set_number
|
metadata
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
name: AXElements
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.7.
|
5
|
+
version: 0.7.6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Mark Rada
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-06 00:00:00 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|